From 226b9a9d3c9243cf0242a78f7b1fb699341d94e4 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Sun, 23 Aug 2026 19:29:57 +0200 Subject: [PATCH 1/3] feat: add DataTypeListBooleanInputComponent for boolean list selection functionality --- .../DataTypeListBooleanInputComponent.tsx | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 src/packages/ce/src/datatype/components/inputs/list-boolean/DataTypeListBooleanInputComponent.tsx diff --git a/src/packages/ce/src/datatype/components/inputs/list-boolean/DataTypeListBooleanInputComponent.tsx b/src/packages/ce/src/datatype/components/inputs/list-boolean/DataTypeListBooleanInputComponent.tsx new file mode 100644 index 00000000..15263a2a --- /dev/null +++ b/src/packages/ce/src/datatype/components/inputs/list-boolean/DataTypeListBooleanInputComponent.tsx @@ -0,0 +1,112 @@ +import React from "react"; +import {DataTypeInputComponentProps} from "../DataTypeInputComponent"; +import { + Badge, + InputDescription, + InputLabel, + TagInput, + TagInputMenu, + TagInputMenuItem, + TagInputTrigger, + TagInputValue, + TagValue, + Text +} from "@code0-tech/pictor"; +import {useDebouncedCallback} from "use-debounce"; +import { + LiteralValue, + NodeFunction, + NodeParameterValue, + ReferenceValue, + SubFlowValue +} from "@code0-tech/sagittarius-graphql-types"; +import {NodeSchema, Schema} from "@code0-tech/triangulum"; +import {DataTypeInputControlsComponent} from "@edition/datatype/components/inputs/DataTypeInputControlsComponent"; +import {DataTypeInputValueComponent} from "@edition/datatype/components/inputs/DataTypeInputValueComponent"; + +export type DataTypeListBooleanInputComponentProps = DataTypeInputComponentProps + +export const DataTypeListBooleanInputComponent: React.FC = (props) => { + + const {schema, formValidation, title, initialValue, description, suggestions, onChange} = props + + const defaultValue: NodeParameterValue | NodeFunction | undefined = React.useMemo(() => initialValue ?? undefined, [initialValue]) + const onChangeDebounced = useDebouncedCallback((value: LiteralValue | SubFlowValue | NodeFunction | ReferenceValue | null) => { + onChange?.(value) + }, 400) + + const optionSuggestions = React.useMemo(() => { + const inner = schema && "schema" in schema ? (schema as NodeSchema).schema : (schema as Schema | undefined) + const items = (inner as { items?: Schema[] })?.items ?? [] + const literals = items.flatMap(item => item.suggestions ?? []) + .filter((suggest): suggest is LiteralValue => suggest.__typename === "LiteralValue") + const seen = new Set() + return literals.filter(literal => { + const key = JSON.stringify(literal.value) + if (seen.has(key)) return false + seen.add(key) + return true + }) + }, [schema]) + const referenceSuggestions = React.useMemo( + () => (suggestions ?? []).filter(suggest => suggest.__typename !== "LiteralValue"), + [suggestions] + ) + + const initialArray = (initialValue as LiteralValue)?.__typename === "LiteralValue" && Array.isArray((initialValue as LiteralValue).value) + ? (initialValue as LiteralValue).value as unknown[] + : [] + const initialKey = JSON.stringify(initialArray) + const initialTags: TagValue[] = React.useMemo( + () => initialArray.map(entry => ({value: entry})), + [initialKey] + ) + + const lastValueKey = React.useRef(initialKey) + + return React.useMemo(() => <> + {title} + {description} + { + formValidation?.setValue?.(value) + onChangeDebounced(value) + }} suggestions={referenceSuggestions} + formValidation={formValidation}> + true}, + {pattern: /^false$/, wrap: () => false} + ]} + formValidation={{...formValidation, setValue: undefined}} + onChange={tags => { + const value = tags.map(tag => tag.value) + const key = JSON.stringify(value) + if (key === lastValueKey.current) return + lastValueKey.current = key + const literal: LiteralValue = {__typename: "LiteralValue", value} + formValidation?.setValue?.(literal) + onChangeDebounced(literal) + }} + right={ + { + formValidation?.setValue?.(value) + onChangeDebounced(value) + }}/> + } + rightType={"action"}> + + {optionSuggestions.map((suggest, index) => ( + + {String(suggest.value)} + + ))} + + + + + + , [formValidation, defaultValue, optionSuggestions]) +} From 12106a312322e1c0d42bee8d88348b9a697229e0 Mon Sep 17 00:00:00 2001 From: nicosammito Date: Sun, 23 Aug 2026 19:30:17 +0200 Subject: [PATCH 2/3] feat: add DataTypeListNumberInputComponent and DataTypeListTextInputComponent for enhanced list input functionality --- .../DataTypeListNumberInputComponent.tsx | 86 +++++++++++++++++++ .../DataTypeListTextInputComponent.tsx | 83 ++++++++++++++++++ 2 files changed, 169 insertions(+) create mode 100644 src/packages/ce/src/datatype/components/inputs/list-number/DataTypeListNumberInputComponent.tsx create mode 100644 src/packages/ce/src/datatype/components/inputs/list-text/DataTypeListTextInputComponent.tsx diff --git a/src/packages/ce/src/datatype/components/inputs/list-number/DataTypeListNumberInputComponent.tsx b/src/packages/ce/src/datatype/components/inputs/list-number/DataTypeListNumberInputComponent.tsx new file mode 100644 index 00000000..9244da08 --- /dev/null +++ b/src/packages/ce/src/datatype/components/inputs/list-number/DataTypeListNumberInputComponent.tsx @@ -0,0 +1,86 @@ +import React from "react"; +import {DataTypeInputComponentProps} from "../DataTypeInputComponent"; +import { + InputDescription, + InputLabel, + TagInput, + TagInputTrigger, + TagInputValue, + TagValue +} from "@code0-tech/pictor"; +import {useDebouncedCallback} from "use-debounce"; +import { + LiteralValue, + NodeFunction, + NodeParameterValue, + ReferenceValue, + SubFlowValue +} from "@code0-tech/sagittarius-graphql-types"; +import {DataTypeInputControlsComponent} from "@edition/datatype/components/inputs/DataTypeInputControlsComponent"; +import {DataTypeInputValueComponent} from "@edition/datatype/components/inputs/DataTypeInputValueComponent"; + +export type DataTypeListNumberInputComponentProps = DataTypeInputComponentProps + +export const DataTypeListNumberInputComponent: React.FC = (props) => { + + const {formValidation, title, initialValue, description, suggestions, onChange} = props + + const defaultValue: NodeParameterValue | NodeFunction | undefined = React.useMemo(() => initialValue ?? undefined, [initialValue]) + const onChangeDebounced = useDebouncedCallback((value: LiteralValue | SubFlowValue | NodeFunction | ReferenceValue | null) => { + onChange?.(value) + }, 400) + + const referenceSuggestions = React.useMemo( + () => (suggestions ?? []).filter(suggest => suggest.__typename !== "LiteralValue"), + [suggestions] + ) + + const initialArray = (initialValue as LiteralValue)?.__typename === "LiteralValue" && Array.isArray((initialValue as LiteralValue).value) + ? (initialValue as LiteralValue).value as unknown[] + : [] + const initialKey = JSON.stringify(initialArray) + const initialTags: TagValue[] = React.useMemo( + () => initialArray.map(entry => ({value: entry})), + [initialKey] + ) + + const lastValueKey = React.useRef(initialKey) + + return React.useMemo(() => <> + {title} + {description} + { + formValidation?.setValue?.(value) + onChangeDebounced(value) + }} suggestions={referenceSuggestions} + formValidation={formValidation}> + { + const value = tags.map(tag => { + const number = Number(tag.value) + return tag.value === "" || Number.isNaN(number) ? tag.value : number + }) + const key = JSON.stringify(value) + if (key === lastValueKey.current) return + lastValueKey.current = key + const literal: LiteralValue = {__typename: "LiteralValue", value} + formValidation?.setValue?.(literal) + onChangeDebounced(literal) + }} + right={ + { + formValidation?.setValue?.(value) + onChangeDebounced(value) + }}/> + } + rightType={"action"}> + + + + + , [formValidation, defaultValue]) +} diff --git a/src/packages/ce/src/datatype/components/inputs/list-text/DataTypeListTextInputComponent.tsx b/src/packages/ce/src/datatype/components/inputs/list-text/DataTypeListTextInputComponent.tsx new file mode 100644 index 00000000..76edcc81 --- /dev/null +++ b/src/packages/ce/src/datatype/components/inputs/list-text/DataTypeListTextInputComponent.tsx @@ -0,0 +1,83 @@ +import React from "react"; +import {DataTypeInputComponentProps} from "../DataTypeInputComponent"; +import { + InputDescription, + InputLabel, + TagInput, + TagInputTrigger, + TagInputValue, + TagValue +} from "@code0-tech/pictor"; +import {useDebouncedCallback} from "use-debounce"; +import { + LiteralValue, + NodeFunction, + NodeParameterValue, + ReferenceValue, + SubFlowValue +} from "@code0-tech/sagittarius-graphql-types"; +import {DataTypeInputControlsComponent} from "@edition/datatype/components/inputs/DataTypeInputControlsComponent"; +import {DataTypeInputValueComponent} from "@edition/datatype/components/inputs/DataTypeInputValueComponent"; + +export type DataTypeListTextInputComponentProps = DataTypeInputComponentProps + +export const DataTypeListTextInputComponent: React.FC = (props) => { + + const {formValidation, title, initialValue, description, suggestions, onChange} = props + + const defaultValue: NodeParameterValue | NodeFunction | undefined = React.useMemo(() => initialValue ?? undefined, [initialValue]) + const onChangeDebounced = useDebouncedCallback((value: LiteralValue | SubFlowValue | NodeFunction | ReferenceValue | null) => { + onChange?.(value) + }, 400) + + const referenceSuggestions = React.useMemo( + () => (suggestions ?? []).filter(suggest => suggest.__typename !== "LiteralValue"), + [suggestions] + ) + + const initialArray = (initialValue as LiteralValue)?.__typename === "LiteralValue" && Array.isArray((initialValue as LiteralValue).value) + ? (initialValue as LiteralValue).value as unknown[] + : [] + const initialKey = JSON.stringify(initialArray) + const initialTags: TagValue[] = React.useMemo( + () => initialArray.map(entry => ({value: entry})), + [initialKey] + ) + + const lastValueKey = React.useRef(initialKey) + + return React.useMemo(() => <> + {title} + {description} + { + formValidation?.setValue?.(value) + onChangeDebounced(value) + }} suggestions={referenceSuggestions} + formValidation={formValidation}> + { + const value = tags.map(tag => String(tag.value)) + const key = JSON.stringify(value) + if (key === lastValueKey.current) return + lastValueKey.current = key + const literal: LiteralValue = {__typename: "LiteralValue", value} + formValidation?.setValue?.(literal) + onChangeDebounced(literal) + }} + right={ + { + formValidation?.setValue?.(value) + onChangeDebounced(value) + }}/> + } + rightType={"action"}> + + + + + , [formValidation, defaultValue]) +} From 457bfa0392ba8ff026107234d9b424a6d4325a9d Mon Sep 17 00:00:00 2001 From: nicosammito Date: Sun, 23 Aug 2026 19:30:21 +0200 Subject: [PATCH 3/3] feat: integrate DataTypeListBooleanInputComponent, DataTypeListTextInputComponent, and DataTypeListNumberInputComponent into DataTypeInputComponent for enhanced list input options --- .../inputs/DataTypeInputComponent.tsx | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/packages/ce/src/datatype/components/inputs/DataTypeInputComponent.tsx b/src/packages/ce/src/datatype/components/inputs/DataTypeInputComponent.tsx index 94d9763d..989964a0 100644 --- a/src/packages/ce/src/datatype/components/inputs/DataTypeInputComponent.tsx +++ b/src/packages/ce/src/datatype/components/inputs/DataTypeInputComponent.tsx @@ -13,6 +13,15 @@ import {DataTypeSelectInputComponent} from "@edition/datatype/components/inputs/ import { DataTypeListSelectInputComponent } from "@edition/datatype/components/inputs/list-select/DataTypeListSelectInputComponent"; +import { + DataTypeListBooleanInputComponent +} from "@edition/datatype/components/inputs/list-boolean/DataTypeListBooleanInputComponent"; +import { + DataTypeListTextInputComponent +} from "@edition/datatype/components/inputs/list-text/DataTypeListTextInputComponent"; +import { + DataTypeListNumberInputComponent +} from "@edition/datatype/components/inputs/list-number/DataTypeListNumberInputComponent"; import {InputWrapperProps} from "@code0-tech/pictor/dist/components/form/InputWrapper"; import {DataTypeNumberInputComponent} from "@edition/datatype/components/inputs/number/DataTypeNumberInputComponent"; import {DataTypeDateInputComponent} from "@edition/datatype/components/inputs/date/DataTypeDateInputComponent"; @@ -62,6 +71,21 @@ export const DataTypeInputComponent: React.FC = (pr schema={schema} suggestions={suggestions} {...rest}/> + case "list-boolean": + return + case "list-text": + return + case "list-number": + return case "number": return