feat(documents): папки шаблонов, маппинги и поле document_template; fix(batch): атомарное создание задач, idempotency и массовое удаление в реестре
This commit is contained in:
@@ -111,6 +111,11 @@ interface TaskRegistryProps {
|
||||
searches: string[];
|
||||
onAddSearch: (value: string) => void;
|
||||
onRemoveSearch: (index: number) => void;
|
||||
// Bulk selection
|
||||
isAdmin?: boolean;
|
||||
selectedTaskIds?: Set<number>;
|
||||
onToggleSelected?: (taskId: number) => void;
|
||||
onToggleSelectAll?: () => void;
|
||||
}
|
||||
|
||||
// Отображает значение поля с учётом типа
|
||||
@@ -248,7 +253,7 @@ const REGISTRY_INLINE_TYPES = new Set([
|
||||
// Типы полей, которые переключаются по одиночному клику
|
||||
const REGISTRY_QUICK_TOGGLE_TYPES = new Set(['checkbox', 'toggle']);
|
||||
|
||||
const TaskRegistry = ({ tasks, relatedTaskTitles = {}, fields, statuses, users = [], roles = [], formId, onFilteredCountChange, onTaskClick, filters, sort, setFilter, clearFilter, clearAll, setSort, clearSort, hasActiveFilters, searches, onAddSearch, onRemoveSearch }: TaskRegistryProps) => {
|
||||
const TaskRegistry = ({ tasks, relatedTaskTitles = {}, fields, statuses, users = [], roles = [], formId, onFilteredCountChange, onTaskClick, filters, sort, setFilter, clearFilter, clearAll, setSort, clearSort, hasActiveFilters, searches, onAddSearch, onRemoveSearch, isAdmin, selectedTaskIds, onToggleSelected, onToggleSelectAll }: TaskRegistryProps) => {
|
||||
const { toast } = useToast();
|
||||
|
||||
// Текущая редактируемая ячейка: { taskId, columnKey }
|
||||
@@ -754,6 +759,22 @@ const TaskRegistry = ({ tasks, relatedTaskTitles = {}, fields, statuses, users =
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
{isAdmin && (
|
||||
<TableHead className="w-8 px-2">
|
||||
<Checkbox
|
||||
checked={filteredTasks.length > 0 && filteredTasks.every(t => selectedTaskIds?.has(t.id))}
|
||||
data-state={
|
||||
filteredTasks.length > 0 &&
|
||||
filteredTasks.some(t => selectedTaskIds?.has(t.id)) &&
|
||||
!filteredTasks.every(t => selectedTaskIds?.has(t.id))
|
||||
? 'indeterminate'
|
||||
: (filteredTasks.length > 0 && filteredTasks.every(t => selectedTaskIds?.has(t.id)) ? 'checked' : 'unchecked')
|
||||
}
|
||||
onCheckedChange={() => onToggleSelectAll?.()}
|
||||
aria-label="Выделить все видимые задачи"
|
||||
/>
|
||||
</TableHead>
|
||||
)}
|
||||
{columnOrder.filter(key => visibleColumns[key]).map(key => {
|
||||
if (key === 'title') {
|
||||
return (
|
||||
@@ -835,6 +856,16 @@ const TaskRegistry = ({ tasks, relatedTaskTitles = {}, fields, statuses, users =
|
||||
|
||||
return (
|
||||
<TableRow key={task.id} data-testid={`row-task-${task.id}`} className={`${isCompleted ? 'bg-gray-100 dark:bg-gray-900 opacity-70' : ''} ${isOverdue ? 'border-l-2 border-l-red-500 bg-red-50 dark:bg-red-950/20' : ''}`}>
|
||||
{isAdmin && (
|
||||
<TableCell className="py-1 px-2 w-8" onClick={(e) => e.stopPropagation()}>
|
||||
<Checkbox
|
||||
checked={selectedTaskIds?.has(task.id) ?? false}
|
||||
onCheckedChange={() => onToggleSelected?.(task.id)}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
aria-label="Выделить задачу"
|
||||
/>
|
||||
</TableCell>
|
||||
)}
|
||||
{columnOrder.filter(key => visibleColumns[key]).map(key => {
|
||||
if (key === 'title') {
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user