diff --git a/client/src/components/TableFieldMultiSelect.tsx b/client/src/components/TableFieldMultiSelect.tsx index cad0151..4469e57 100644 --- a/client/src/components/TableFieldMultiSelect.tsx +++ b/client/src/components/TableFieldMultiSelect.tsx @@ -35,6 +35,7 @@ export default function TableFieldMultiSelect({ rows: DataTableRow[]; columns: Array<{ name: string }>; treeColumnIndex: number | null; + treeDisplayColumnIndex: number | null; }; }>({ queryKey: ['/api/directories', tableId], @@ -69,7 +70,7 @@ export default function TableFieldMultiSelect({ let displayColumnIndex = table?.columns?.findIndex((c) => c.name === displayColumn); if (displayColumnIndex === undefined || displayColumnIndex < 0) { - displayColumnIndex = 0; + displayColumnIndex = table?.treeDisplayColumnIndex ?? 0; } const selectedValues = useMemo(() => { @@ -166,7 +167,6 @@ export default function TableFieldMultiSelect({ {hasTree ? ( ; treeColumnIndex: number | null; + treeDisplayColumnIndex: number | null; }; }>({ queryKey: ['/api/directories', tableId], @@ -67,7 +68,7 @@ export default function TableFieldSelect({ let displayColumnIndex = table?.columns?.findIndex((c) => c.name === displayColumn); if (displayColumnIndex === undefined || displayColumnIndex < 0) { - displayColumnIndex = 0; + displayColumnIndex = table?.treeDisplayColumnIndex ?? 0; } const sortedRows = useMemo(() => { @@ -151,7 +152,6 @@ export default function TableFieldSelect({ {hasTree ? ( ): D function filterTree( tree: DirectoryRowTreeItem[], - query: string + query: string, + labelColumnIndex = 0 ): { tree: DirectoryRowTreeItem[]; expanded: Set } { if (!query.trim()) return { tree, expanded: new Set() }; const q = query.toLowerCase(); @@ -115,7 +116,7 @@ function filterTree( function walk(nodes: DirectoryRowTreeItem[]): DirectoryRowTreeItem[] { const visible: DirectoryRowTreeItem[] = []; for (const node of nodes) { - const label = String(node.values[0] ?? '').toLowerCase(); + const label = getRowLabel(node, labelColumnIndex).toLowerCase(); const children = walk(node.children); const childMatch = children.length > 0; if (label.includes(q) || childMatch) { @@ -298,7 +299,7 @@ export function DirectoryRowTree({ searchQuery, }: DirectoryRowTreeProps & { searchQuery?: string }) { const tree = useMemo(() => buildTree(rows), [rows]); - const filtered = useMemo(() => filterTree(tree, searchQuery || ''), [tree, searchQuery]); + const filtered = useMemo(() => filterTree(tree, searchQuery || '', labelColumnIndex), [tree, searchQuery, labelColumnIndex]); const effectiveExpanded = useMemo( () => (searchQuery?.trim() ? filtered.expanded : expanded), [searchQuery, filtered.expanded, expanded] diff --git a/client/src/components/directories/DirectoryTreeMultiSelect.tsx b/client/src/components/directories/DirectoryTreeMultiSelect.tsx index 65c56f3..27f3fec 100644 --- a/client/src/components/directories/DirectoryTreeMultiSelect.tsx +++ b/client/src/components/directories/DirectoryTreeMultiSelect.tsx @@ -6,7 +6,7 @@ import type { DataTableRow } from '@shared/schema'; export type DirectoryTreeNode = | { type: 'group'; id: string; label: string; level: number; children: DirectoryTreeNode[] } - | { type: 'row'; id: number; level: number; row: DataTableRow }; + | { type: 'row'; id: number; label: string; level: number; row: DataTableRow }; function assignLevels(nodes: DirectoryTreeNode[], level = 0): DirectoryTreeNode[] { return nodes.map((node) => { @@ -19,7 +19,6 @@ function assignLevels(nodes: DirectoryTreeNode[], level = 0): DirectoryTreeNode[ interface DirectoryTreeMultiSelectProps { nodes: DirectoryTreeNode[]; - displayColumnIndex: number; selected: Set; onToggle: (rowId: string) => void; searchTerm?: string; @@ -27,8 +26,7 @@ interface DirectoryTreeMultiSelectProps { function filterNodes( nodes: DirectoryTreeNode[], - query: string, - displayColumnIndex: number + query: string ): { nodes: DirectoryTreeNode[]; expanded: Set } { if (!query.trim()) return { nodes, expanded: new Set() }; const q = query.toLowerCase(); @@ -38,7 +36,7 @@ function filterNodes( const visible: DirectoryTreeNode[] = []; for (const node of items) { if (node.type === 'row') { - const label = String(node.row.values[displayColumnIndex] ?? node.row.values[0] ?? '').toLowerCase(); + const label = node.label.toLowerCase(); if (label.includes(q)) visible.push(node); } else { const children = walk(node.children); @@ -56,21 +54,14 @@ function filterNodes( return { nodes: walk(nodes), expanded }; } -function getRowLabel(row: DataTableRow, displayColumnIndex: number): string { - const values = Array.isArray(row.values) ? row.values : []; - return String(values[displayColumnIndex] ?? values[0] ?? '') || '(без названия)'; -} - function TreeNode({ node, - displayColumnIndex, selected, onToggle, expanded, onToggleExpand, }: { node: DirectoryTreeNode; - displayColumnIndex: number; selected: Set; onToggle: (rowId: string) => void; expanded: Set; @@ -87,7 +78,7 @@ function TreeNode({ - {getRowLabel(node.row, displayColumnIndex)} + {node.label} ); @@ -117,7 +108,6 @@ function TreeNode({ assignLevels(nodes), [nodes]); const filtered = useMemo( - () => filterNodes(nodesWithLevels, searchTerm, displayColumnIndex), - [nodesWithLevels, searchTerm, displayColumnIndex] + () => filterNodes(nodesWithLevels, searchTerm), + [nodesWithLevels, searchTerm] ); const [manualExpanded, setManualExpanded] = useState>(new Set()); @@ -168,7 +157,6 @@ export function DirectoryTreeMultiSelect({ { @@ -18,7 +18,6 @@ function assignLevels(nodes: DirectoryTreeNode[], level = 0): DirectoryTreeNode[ interface DirectoryTreeSelectProps { nodes: DirectoryTreeNode[]; - displayColumnIndex: number; value?: string | number | null; onChange: (rowId: string) => void; searchTerm?: string; @@ -26,8 +25,7 @@ interface DirectoryTreeSelectProps { function filterNodes( nodes: DirectoryTreeNode[], - query: string, - displayColumnIndex: number + query: string ): { nodes: DirectoryTreeNode[]; expanded: Set } { if (!query.trim()) return { nodes, expanded: new Set() }; const q = query.toLowerCase(); @@ -37,7 +35,7 @@ function filterNodes( const visible: DirectoryTreeNode[] = []; for (const node of items) { if (node.type === 'row') { - const label = String(node.row.values[displayColumnIndex] ?? node.row.values[0] ?? '').toLowerCase(); + const label = node.label.toLowerCase(); if (label.includes(q)) visible.push(node); } else { const children = walk(node.children); @@ -55,21 +53,14 @@ function filterNodes( return { nodes: walk(nodes), expanded }; } -function getRowLabel(row: DataTableRow, displayColumnIndex: number): string { - const values = Array.isArray(row.values) ? row.values : []; - return String(values[displayColumnIndex] ?? values[0] ?? '') || '(без названия)'; -} - function TreeNode({ node, - displayColumnIndex, value, onChange, expanded, onToggle, }: { node: DirectoryTreeNode; - displayColumnIndex: number; value?: string | number | null; onChange: (rowId: string) => void; expanded: Set; @@ -89,7 +80,7 @@ function TreeNode({ onClick={() => onChange(rowId)} > - {getRowLabel(node.row, displayColumnIndex)} + {node.label} ); } @@ -116,7 +107,6 @@ function TreeNode({ assignLevels(nodes), [nodes]); const filtered = useMemo( - () => filterNodes(nodesWithLevels, searchTerm, displayColumnIndex), - [nodesWithLevels, searchTerm, displayColumnIndex] + () => filterNodes(nodesWithLevels, searchTerm), + [nodesWithLevels, searchTerm] ); const [manualExpanded, setManualExpanded] = useState>(new Set()); @@ -176,7 +165,6 @@ export function DirectoryTreeSelect({ ([]); const [treeColumnIndex, setTreeColumnIndex] = useState(null); + const [treeDisplayColumnIndex, setTreeDisplayColumnIndex] = useState(null); const [importOpen, setImportOpen] = useState(false); const [importPreview, setImportPreview] = useState<{ added: { values: string[] }[]; @@ -175,6 +176,7 @@ export default function TableEditor() { setTableDescription(data.table.description || ''); setTableColumns(data.table.columns as TableColumn[]); setTreeColumnIndex(data.table.treeColumnIndex ?? null); + setTreeDisplayColumnIndex(data.table.treeDisplayColumnIndex ?? null); setNewRowValues(new Array(data.table.columns.length).fill('')); } }, [data]); @@ -186,7 +188,7 @@ export default function TableEditor() { }, [rowEditorOpen, rowEditorInitialValues]); const updateTableMutation = useMutation({ - mutationFn: async (updates: { name?: string; description?: string; columns?: TableColumn[]; treeColumnIndex?: number | null }) => { + mutationFn: async (updates: { name?: string; description?: string; columns?: TableColumn[]; treeColumnIndex?: number | null; treeDisplayColumnIndex?: number | null }) => { return apiRequest('PATCH', `/api/directories/${tableId}`, updates); }, onSuccess: () => { @@ -723,7 +725,7 @@ export default function TableEditor() { - {activeRow.values[0] || '—'} + {activeRow.values[treeDisplayColumnIndex ?? 0] || activeRow.values[0] || '—'} ) : null} @@ -1195,13 +1198,34 @@ export default function TableEditor() { Строки будут сгруппированы по уникальным значениям выбранной колонки.

+
+ + +

+ Значение этой колонки будет показано как название узла в дереве. +

+