From 8d11a922fda4f979dfa4cc8528b5d20886111307 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Tue, 7 Jul 2026 14:20:00 +0200 Subject: [PATCH] feat: enhance DataTypeInputControlsComponent with improved suggestion handling and menu structure --- .../inputs/DataTypeInputControlsComponent.tsx | 234 +++++++++++++++--- 1 file changed, 205 insertions(+), 29 deletions(-) diff --git a/src/packages/ce/src/datatype/components/inputs/DataTypeInputControlsComponent.tsx b/src/packages/ce/src/datatype/components/inputs/DataTypeInputControlsComponent.tsx index cbe3c364..6bebde52 100644 --- a/src/packages/ce/src/datatype/components/inputs/DataTypeInputControlsComponent.tsx +++ b/src/packages/ce/src/datatype/components/inputs/DataTypeInputControlsComponent.tsx @@ -1,6 +1,12 @@ -import {LiteralValue, NodeFunction, ReferenceValue, SubFlowValue} from "@code0-tech/sagittarius-graphql-types"; +import { + LiteralValue, + NodeFunction, + ReferencePath, + ReferenceValue, + SubFlowValue +} from "@code0-tech/sagittarius-graphql-types"; import React from "react"; -import {IconVariable, IconX} from "@tabler/icons-react"; +import {IconChevronRight, IconVariable, IconX} from "@tabler/icons-react"; import {ReferenceBadgeComponent} from "@edition/datatype/components/badges/ReferenceBadgeComponent"; import { Button, @@ -10,7 +16,14 @@ import { MenuContent, MenuItem, MenuPortal, + MenuSub, + MenuSubContent, + MenuSubTrigger, MenuTrigger, + ScrollArea, + ScrollAreaScrollbar, + ScrollAreaThumb, + ScrollAreaViewport, Text, Tooltip, TooltipContent, @@ -25,13 +38,147 @@ export interface DataTypeInputControlsComponentProps { showSuggestions?: boolean } +interface ReferencePathTreeNode { + label: string + // set when a suggestion references exactly this path + value?: ReferenceValue + children: Map +} + +interface ReferenceGroup { + // representative reference without path, used to render the group badge + root: ReferenceValue + // set when a suggestion references the root itself (empty path) + value?: ReferenceValue + children: Map + suggestions: ReferenceValue[] +} + +type MenuEntry = + | { kind: "value", value: LiteralValue | SubFlowValue } + | { kind: "reference-group", key: string, group: ReferenceGroup } + +const referenceGroupKey = (value: ReferenceValue): string => { + return [value.nodeFunctionId, value.inputTypeIdentifier, value.inputIndex, value.parameterIndex].join("/") +} + +const referencePathLabel = (path: ReferencePath): string => { + return `${path.path ?? ""}${path.arrayIndex != null ? `[${path.arrayIndex}]` : ""}` +} + +const MenuScrollArea: React.FC = ({children}) => { + const contentRef = React.useRef(null) + const [height, setHeight] = React.useState() + + React.useLayoutEffect(() => { + const el = contentRef.current + if (!el) return + const observer = new ResizeObserver((entries) => { + const entry = entries[0] + if (entry) setHeight(entry.contentRect.height) + }) + observer.observe(el) + return () => observer.disconnect() + }, []) + + return + +
+ {children} +
+
+ + + +
+} + +const ReferencePathMenuItems: React.FC<{ + nodes: Map + onSelect?: DataTypeInputControlsComponentProps['onSelect'] +}> = ({nodes, onSelect}) => { + return <> + {Array.from(nodes.values()).map(node => { + if (node.children.size <= 0) { + return node.value && onSelect?.(node.value)}> + {node.label} + + } + + return + + + {node.label} + + + + + + {node.value ? ( + onSelect?.(node.value!)}> + {node.label} + + ) : null} + + + + + })} + +} + export const DataTypeInputControlsComponent: React.FC = (props) => { const {suggestions, showSuggestions = true, onSelect} = props - const filteredSuggestions = React.useMemo(() => { + const menuEntries = React.useMemo(() => { if (!suggestions) return [] - return suggestions.filter(suggest => suggest.__typename === "LiteralValue" || suggest.__typename === "ReferenceValue" || suggest.__typename === "SubFlowValue") + + const entries: MenuEntry[] = [] + const groups = new Map() + + suggestions.forEach(suggest => { + if (suggest.__typename === "LiteralValue" || suggest.__typename === "SubFlowValue") { + entries.push({kind: "value", value: suggest}) + return + } + + if (suggest.__typename !== "ReferenceValue") return + + const key = referenceGroupKey(suggest) + let group = groups.get(key) + if (!group) { + group = { + root: {...suggest, referencePath: undefined}, + children: new Map(), + suggestions: [] + } + groups.set(key, group) + entries.push({kind: "reference-group", key, group}) + } + group.suggestions.push(suggest) + + const segments = suggest.referencePath ?? [] + if (segments.length <= 0) { + group.value = suggest + return + } + + let children = group.children + let node: ReferencePathTreeNode | undefined = undefined + segments.forEach(segment => { + const label = referencePathLabel(segment) + if (!children.has(label)) { + children.set(label, {label, children: new Map()}) + } + node = children.get(label)! + children = node.children + }) + node!.value = suggest + }) + + return entries }, [suggestions]) return @@ -39,7 +186,7 @@ export const DataTypeInputControlsComponent: React.FC - + @@ -47,7 +194,7 @@ export const DataTypeInputControlsComponent: React.FC - {filteredSuggestions.length <= 0 ? + {menuEntries.length <= 0 ? No suggestion available : Suggestions for this parameter @@ -56,28 +203,57 @@ export const DataTypeInputControlsComponent: React.FC - - {filteredSuggestions?.map((suggest, index) => { - if (suggest.__typename === "LiteralValue") { - return onSelect?.(suggest)}> - - {(suggest)?.value.toString()} - - - } - - if (suggest.__typename === "ReferenceValue") { - return onSelect?.(suggest)}> - - - } - - if (suggest.__typename === "SubFlowValue") { - return onSelect?.(suggest)}> - - - } - })} + + + {menuEntries.map((entry, index) => { + if (entry.kind === "value" && entry.value.__typename === "LiteralValue") { + return onSelect?.(entry.value)}> + + {entry.value.value.toString()} + + + } + + if (entry.kind === "value" && entry.value.__typename === "SubFlowValue") { + return onSelect?.(entry.value)}> + + + } + + if (entry.kind === "reference-group") { + const group = entry.group + + if (group.suggestions.length === 1) { + return onSelect?.(group.suggestions[0])}> + + + } + + return + + + + + + + + + {group.value ? ( + onSelect?.(group.value!)}> + + + ) : null} + + + + + } + + return null + })} + @@ -91,4 +267,4 @@ export const DataTypeInputControlsComponent: React.FC -} \ No newline at end of file +}