diff --git a/src/frontend/src/components/forms/fields/ApiFormField.tsx b/src/frontend/src/components/forms/fields/ApiFormField.tsx index b5196609a8..e61c818072 100644 --- a/src/frontend/src/components/forms/fields/ApiFormField.tsx +++ b/src/frontend/src/components/forms/fields/ApiFormField.tsx @@ -263,6 +263,7 @@ export function ApiFormField({ definition={fieldDefinition} fieldName={fieldName} endpoint={ApiEndpoints.stock_location_tree} + childIdentifier='sublocations' /> ); case 'category': @@ -272,6 +273,7 @@ export function ApiFormField({ definition={fieldDefinition} fieldName={fieldName} endpoint={ApiEndpoints.category_tree} + childIdentifier='subcategories' /> ); default: diff --git a/src/frontend/src/components/forms/fields/TreeField.tsx b/src/frontend/src/components/forms/fields/TreeField.tsx index 64f7bc5fd8..3dcd2c3acf 100644 --- a/src/frontend/src/components/forms/fields/TreeField.tsx +++ b/src/frontend/src/components/forms/fields/TreeField.tsx @@ -21,12 +21,14 @@ export function TreeField({ controller, definition, fieldName, - endpoint + endpoint, + childIdentifier }: Readonly<{ controller: UseControllerReturn; definition: ApiFormFieldType; fieldName: string; endpoint: ApiEndpoints; + childIdentifier: string; }>) { const api = useApi(); const { @@ -71,30 +73,37 @@ export function TreeField({ }, [debouncedSearch, nodes]); // Convert the flat API response (sorted by level) into the nested TreeNodeData structure. + // `children` is intentionally left undefined on leaf nodes: Mantine's flatten logic uses + // Array.isArray(node.children) to detect loaded children, so an empty [] would make every + // node look like a parent. Instead we set node.hasChildren from the server-side count field + // (childIdentifier) and only attach a children array when a child is actually encountered. const treeData: TreeNodeData[] = useMemo(() => { - const map: Record = {}; + const map: Record = {}; const tree: TreeNodeData[] = []; const sorted = [...nodes].sort((a, b) => a.level - b.level); for (const raw of sorted) { - const node = { + const node: any = { value: raw.pk.toString(), label: raw.name as string, - children: [] as TreeNodeData[] + hasChildren: (raw[childIdentifier] ?? 0) > 0 }; map[raw.pk] = node; if (!raw.parent) { tree.push(node); - } else { - map[raw.parent]?.children.push(node); + } else if (map[raw.parent]) { + if (!map[raw.parent].children) { + map[raw.parent].children = []; + } + map[raw.parent].children.push(node); } } return tree; - }, [nodes]); + }, [nodes, childIdentifier]); const onChange = useCallback( (val: string | null) => {