diff --git a/web/src/components/RealtimeTable/utils/columnUtils.js b/web/src/components/RealtimeTable/utils/columnUtils.js index 91e61cb..cd23607 100644 --- a/web/src/components/RealtimeTable/utils/columnUtils.js +++ b/web/src/components/RealtimeTable/utils/columnUtils.js @@ -1,3 +1,51 @@ +// Получение accessorKey колонки +export const getColumnKey = (node) => node?.accessorKey; + +// Проверка, нужно ли скрыть колонку из дерева +export const shouldExcludeFromTree = (node, excludeSet) => { + if (node?.hideInTree) return true; + const key = getColumnKey(node); + return Boolean(key && excludeSet.has(key)); +}; + +// Фильтрация дерева колонок по списку исключений +export const filterColumnTree = (nodes, excludeColumnKeys = []) => { + if (!nodes?.length) return []; + + const excludeSet = new Set(excludeColumnKeys); + + return nodes.flatMap((node) => { + if (shouldExcludeFromTree(node, excludeSet)) return []; + + const hasChildren = Array.isArray(node.columns) && node.columns.length > 0; + if (!hasChildren) return [node]; + + const filteredChildren = filterColumnTree(node.columns, excludeColumnKeys); + if (filteredChildren.length === 0) return []; + + return [{ ...node, columns: filteredChildren }]; + }); +}; + +// Получение accessorKey всех листовых колонок из дерева +export const getColumnTreeLeafKeys = (nodes) => { + const keys = []; + + const collect = (cols) => { + for (const col of cols) { + if (col.columns?.length) { + collect(col.columns); + } else { + const key = getColumnKey(col); + if (key) keys.push(key); + } + } + }; + + collect(nodes); + return keys; +}; + // Сбор листовых колонок export const getLeafColumns = (targetColumn) => { if (!targetColumn) return []; diff --git a/web/src/components/Stages/AddStagesModal.jsx b/web/src/components/Stages/AddStagesModal.jsx index 7689571..511a9d0 100644 --- a/web/src/components/Stages/AddStagesModal.jsx +++ b/web/src/components/Stages/AddStagesModal.jsx @@ -23,6 +23,7 @@ import { Cancel } from '../common/icons/icons'; import { getStageStatus, getStatusColors } from './StagesTable/utils'; import { StageStatusChip } from './StageStatusChip'; import { formatDateForApi } from '../../utils/formatDate'; +import { stageColumnsHiddenFromPicker } from './constants'; import CollapsibleTree from '../common/CollapsibleTree'; import { collectLeafColumns } from '../RealtimeTable/utils/columnUtils'; import { STAGE_ROLE_RUSSIAN_NAME } from '../../constants/constants'; @@ -223,6 +224,7 @@ export const AddStagesModal = ({ filterColumnTree(columnTree, excludeColumnKeys), + [columnTree, excludeColumnKeys], + ); + + const visibleLeafKeys = useMemo( + () => getColumnTreeLeafKeys(visibleColumnTree), + [visibleColumnTree], + ); + const handleExpandedItemsChange = (event, itemIds) => { setExpandedItems(itemIds); }; const handleSelectAll = (isSelected) => { - for (const col of columnTree) { + for (const col of visibleColumnTree) { onSelectNode?.(col, !isSelected); } }; @@ -134,8 +146,8 @@ const CollapsibleTree = ({ }; const treeElements = useMemo(() => { - return columnTree ? renderTree(columnTree) : null; - }, [columnTree, selectedNodes]); + return visibleColumnTree.length > 0 ? renderTree(visibleColumnTree) : null; + }, [visibleColumnTree, selectedNodes]); const handleOpen = (event) => { setAnchorEl(event.currentTarget); @@ -145,12 +157,15 @@ const CollapsibleTree = ({ setAnchorEl(null); }; - const selectedCount = forStage ? selectedNodes.length : selectedNodes.length - 1; //1 колонка всегда скрыта + const visibleSelectedCount = selectedNodes.filter((id) => + visibleLeafKeys.includes(id), + ).length; + const selectedCount = forStage ? visibleSelectedCount : visibleSelectedCount - 1; //1 колонка всегда скрыта const isAllSelected = () => { - if (!columnTree) return false; + if (!visibleColumnTree.length) return false; let isSelect = true; - for (const col of columnTree) { + for (const col of visibleColumnTree) { const isChecked = isNodeChecked(col); isSelect = isChecked === 'indeterminate' ? false : isChecked && isSelect; }