diff --git a/packages/toolkit/src/components/ReferenceHintTag.tsx b/packages/toolkit/src/components/ReferenceHintTag.tsx new file mode 100644 index 0000000000..d7895248e8 --- /dev/null +++ b/packages/toolkit/src/components/ReferenceHintTag.tsx @@ -0,0 +1,62 @@ +import cn from "clsx"; +import * as React from "react"; +import { Icons } from "@instill-ai/design-system"; + +export const ReferenceHintTagRoot = ({ + children, + className, +}: { + children: React.ReactNode; + className?: string; +}) => { + return ( +
+ {children} +
+ ); +}; + +export const ReferenceHintTagIcon = ({ + type, + className, +}: { + type: "x" | "check"; + className?: string; +}) => { + return type === "x" ? ( + + ) : ( + + ); +}; +export const ReferenceHintTagLabel = ({ + children, + className, +}: { + children: React.ReactNode; + className?: string; +}) => { + return ( +

+ {children} +

+ ); +}; + +export const ReferenceHintTag = { + Root: ReferenceHintTagRoot, + Icon: ReferenceHintTagIcon, + Label: ReferenceHintTagLabel, +}; diff --git a/packages/toolkit/src/components/index.ts b/packages/toolkit/src/components/index.ts index 9c0a89edb2..bb193d5282 100644 --- a/packages/toolkit/src/components/index.ts +++ b/packages/toolkit/src/components/index.ts @@ -25,6 +25,7 @@ export * from "./ObjectViewer"; export * from "./PageBase"; export * from "./PageHead"; export * from "./PageTitle"; +export * from "./ReferenceHintTag"; export * from "./cells"; export * from "./TableError"; export * from "./UserProfileCard"; diff --git a/packages/toolkit/src/lib/use-instill-form/components/component-output-reference-hints/ListField.tsx b/packages/toolkit/src/lib/use-instill-form/components/component-output-reference-hints/ListField.tsx new file mode 100644 index 0000000000..ad5338e707 --- /dev/null +++ b/packages/toolkit/src/lib/use-instill-form/components/component-output-reference-hints/ListField.tsx @@ -0,0 +1,35 @@ +import { ReferenceHintTag } from "../../../../components"; + +export const ListField = ({ + componentID, + path, + title, + instillFormat, + description, +}: { + componentID?: string; + path: string; + title: string; + instillFormat: string; + description?: string; +}) => { + return ( +
+

+ {`${title} [${instillFormat}]`} +

+
+ + + {componentID ? `${componentID}.` + path : path} + + +
+ {description ? ( +

+ {description} +

+ ) : null} +
+ ); +}; diff --git a/packages/toolkit/src/lib/use-instill-form/components/component-output-reference-hints/ObjectArrayField.tsx b/packages/toolkit/src/lib/use-instill-form/components/component-output-reference-hints/ObjectArrayField.tsx new file mode 100644 index 0000000000..2a26d2fceb --- /dev/null +++ b/packages/toolkit/src/lib/use-instill-form/components/component-output-reference-hints/ObjectArrayField.tsx @@ -0,0 +1,43 @@ +import { ComponentOutputReferenceHints } from "."; +import { ComponentOutoutReferenceHint } from "../../type"; + +export const ObjectArrayField = ({ + hints, + parentPath, + componentID, +}: { + hints: ComponentOutoutReferenceHint[]; + parentPath: string; + componentID?: string; +}) => { + return ( +
+

+ {`${parentPath} [array]`} +

+
+

+ {"The "} + {parentPath} + + { + " is an array with this object, you need to add the index to correctly reference its value" + } + +

+ {hints.map((hint) => { + return ( + + ); + })} +
+
+ ); +}; diff --git a/packages/toolkit/src/lib/use-instill-form/components/component-output-reference-hints/index.ts b/packages/toolkit/src/lib/use-instill-form/components/component-output-reference-hints/index.ts new file mode 100644 index 0000000000..f7739d4a6c --- /dev/null +++ b/packages/toolkit/src/lib/use-instill-form/components/component-output-reference-hints/index.ts @@ -0,0 +1,7 @@ +import { ListField } from "./ListField"; +import { ObjectArrayField } from "./ObjectArrayField"; + +export const ComponentOutputReferenceHints = { + ListField, + ObjectArrayField, +}; diff --git a/packages/toolkit/src/lib/use-instill-form/index.ts b/packages/toolkit/src/lib/use-instill-form/index.ts index cd6c4b8cd9..a327974d02 100644 --- a/packages/toolkit/src/lib/use-instill-form/index.ts +++ b/packages/toolkit/src/lib/use-instill-form/index.ts @@ -2,3 +2,4 @@ export * from "./type"; export * from "./useComponentOutputFields"; export * from "./useInstillForm"; export * from "./useStartOperatorTriggerPipelineForm"; +export * from "./useComponentOutputReferenceHintFields"; diff --git a/packages/toolkit/src/lib/use-instill-form/pick/pickComponentOutputFieldsFromInstillFormTree.tsx b/packages/toolkit/src/lib/use-instill-form/pick/pickComponentOutputFieldsFromInstillFormTree.tsx index b710af89a0..151d7f7d39 100644 --- a/packages/toolkit/src/lib/use-instill-form/pick/pickComponentOutputFieldsFromInstillFormTree.tsx +++ b/packages/toolkit/src/lib/use-instill-form/pick/pickComponentOutputFieldsFromInstillFormTree.tsx @@ -93,7 +93,7 @@ export function pickComponentOutputFieldsFromInstillFormTree( } // Process objectArray - // Becase we don't know the index of the output objectArray, we need to user + // Becase we don't know the index of the output objectArray, we need to use // the data as a hint here if (tree._type === "objectArray") { diff --git a/packages/toolkit/src/lib/use-instill-form/pick/pickComponentsFromReferenceHints.tsx b/packages/toolkit/src/lib/use-instill-form/pick/pickComponentsFromReferenceHints.tsx new file mode 100644 index 0000000000..3b53a22db7 --- /dev/null +++ b/packages/toolkit/src/lib/use-instill-form/pick/pickComponentsFromReferenceHints.tsx @@ -0,0 +1,58 @@ +import { groupBy } from "../../utility"; +import { ComponentOutputReferenceHints } from "../components/component-output-reference-hints"; +import { ComponentOutoutReferenceHint } from "../type"; + +export type PickComponentsFromReferenceHintsOptions = { + mode?: "groupByFormat" | "list"; + componentID?: string; +}; + +export function pickComponentsFromReferenceHints( + hints: ComponentOutoutReferenceHint[], + options?: PickComponentsFromReferenceHintsOptions +) { + const mode = options?.mode ?? "list"; + const componentID = options?.componentID ?? undefined; + const fields: React.ReactNode[] = []; + + if (mode === "list") { + const nonObjectArrayHints: ComponentOutoutReferenceHint[] = []; + const objectArrayHints: ComponentOutoutReferenceHint[] = []; + + hints.forEach((hint) => { + if (hint.isObjectArrayChild) { + objectArrayHints.push(hint); + } else { + nonObjectArrayHints.push(hint); + } + }); + + const groupedObjectArrayHints = groupBy(objectArrayHints, (hint) => + hint.isObjectArrayChild ? hint.objectArrayParentPath : "" + ); + + nonObjectArrayHints.forEach((hint) => { + fields.push( + + ); + }); + + Object.entries(groupedObjectArrayHints).forEach(([parentPath, hints]) => { + fields.push( + + ); + }); + } + + return fields; +} diff --git a/packages/toolkit/src/lib/use-instill-form/transform/transformInstillFormTreeToReferenceHints.ts b/packages/toolkit/src/lib/use-instill-form/transform/transformInstillFormTreeToReferenceHints.ts new file mode 100644 index 0000000000..b75b09b2c7 --- /dev/null +++ b/packages/toolkit/src/lib/use-instill-form/transform/transformInstillFormTreeToReferenceHints.ts @@ -0,0 +1,83 @@ +import { ComponentOutoutReferenceHint, InstillFormTree } from "../type"; + +export function transformInstillFormTreeToReferenceHints( + tree: InstillFormTree, + isObjectArrayChild?: boolean, + objectArrayParentPath?: string +): ComponentOutoutReferenceHint[] { + // 1. Preprocess + const title = tree.title ?? tree.fieldKey; + let referenceHints: ComponentOutoutReferenceHint[] = []; + + // Normall a objectArray child will be a formGroup with the same + // path, so we only need to pass the isObjectArrayChild flag and + // objectArrayParentPath to the children + + // 2. Process + + if (tree._type === "formGroup") { + for (const property of tree.properties) { + const hints = transformInstillFormTreeToReferenceHints( + property, + isObjectArrayChild, + objectArrayParentPath + ); + referenceHints = [...referenceHints, ...hints]; + } + return referenceHints; + } + + // The component output don't have formCondition + if (tree._type === "formCondition") { + return referenceHints; + } + + if (tree._type === "objectArray") { + // ObjectArray need to have the path (by instill protocol the top level won't be the + // objectArray, so we can safely assume that the path is not null) + if (tree.path) { + const hints = transformInstillFormTreeToReferenceHints( + tree.properties, + true, + tree.path + ); + referenceHints = [...referenceHints, ...hints]; + } + return referenceHints; + } + + // Process const field + if (tree.const || !tree.path) { + return referenceHints; + } + + // We don't need to hint a field that is lacking instillFormat + if (!tree.instillFormat) { + return referenceHints; + } + + // We don't need to hint a field that is lacking title and key + if (!title) { + return referenceHints; + } + + // Process a normal field + + const hint: ComponentOutoutReferenceHint = + isObjectArrayChild && objectArrayParentPath + ? { + title, + path: tree.path, + instillFormat: tree.instillFormat, + isObjectArrayChild: isObjectArrayChild ?? false, + objectArrayParentPath, + } + : { + title, + path: tree.path, + instillFormat: tree.instillFormat, + isObjectArrayChild: false, + }; + + return [...referenceHints, hint]; +} diff --git a/packages/toolkit/src/lib/use-instill-form/type.ts b/packages/toolkit/src/lib/use-instill-form/type.ts index 9bffc21dd9..915742e4c5 100644 --- a/packages/toolkit/src/lib/use-instill-form/type.ts +++ b/packages/toolkit/src/lib/use-instill-form/type.ts @@ -161,3 +161,20 @@ export type StartOperatorFreeFormFieldBaseProps = { disabledFieldControl?: boolean; disabledReferenceHint?: boolean; }; + +export type ComponentOutoutReferenceHint = + | { + instillFormat: string; + path: string; + title: string; + description?: string; + isObjectArrayChild: false; + } + | { + instillFormat: string; + path: string; + title: string; + description?: string; + isObjectArrayChild: true; + objectArrayParentPath: string; + }; diff --git a/packages/toolkit/src/lib/use-instill-form/useComponentOutputFields.tsx b/packages/toolkit/src/lib/use-instill-form/useComponentOutputFields.tsx index dd037ea5b8..4b6612f387 100644 --- a/packages/toolkit/src/lib/use-instill-form/useComponentOutputFields.tsx +++ b/packages/toolkit/src/lib/use-instill-form/useComponentOutputFields.tsx @@ -23,6 +23,8 @@ export function useComponentOutputFields(props: UseComponentOutputFieldsProps) { const outputFormTree = transformInstillJSONSchemaToFormTree(props.schema); + console.log(outputFormTree); + const fields = pickComponentOutputFieldsFromInstillFormTree({ ...props, tree: outputFormTree, diff --git a/packages/toolkit/src/lib/use-instill-form/useComponentOutputReferenceHintFields.tsx b/packages/toolkit/src/lib/use-instill-form/useComponentOutputReferenceHintFields.tsx new file mode 100644 index 0000000000..710928c938 --- /dev/null +++ b/packages/toolkit/src/lib/use-instill-form/useComponentOutputReferenceHintFields.tsx @@ -0,0 +1,32 @@ +import * as React from "react"; + +import { InstillJSONSchema } from "./type"; +import { Nullable } from "../type"; +import { transformInstillJSONSchemaToFormTree } from "./transform"; +import { pickComponentsFromReferenceHints } from "./pick/pickComponentsFromReferenceHints"; +import { transformInstillFormTreeToReferenceHints } from "./transform/transformInstillFormTreeToReferenceHints"; + +export type UseComponentOutputReferenceHintFieldsOptions = { + componentID: string; +}; + +export function useComponentOutputReferenceHintFields( + schema: Nullable, + options?: UseComponentOutputReferenceHintFieldsOptions +) { + const componentID = options?.componentID ?? undefined; + + const fields = React.useMemo(() => { + if (!schema) { + return []; + } + + const outputFormTree = transformInstillJSONSchemaToFormTree(schema); + const hints = transformInstillFormTreeToReferenceHints(outputFormTree); + const fields = pickComponentsFromReferenceHints(hints, { componentID }); + + return fields; + }, [schema, componentID]); + + return fields; +} diff --git a/packages/toolkit/src/lib/use-instill-form/useInstillForm.test.tsx b/packages/toolkit/src/lib/use-instill-form/useInstillForm.test.tsx index 16fe9f0051..a1e150855a 100644 --- a/packages/toolkit/src/lib/use-instill-form/useInstillForm.test.tsx +++ b/packages/toolkit/src/lib/use-instill-form/useInstillForm.test.tsx @@ -9,7 +9,6 @@ import { import { useInstillForm } from "./useInstillForm"; import { InstillJSONSchema } from "./type"; import { Form } from "@instill-ai/design-system"; -import exp from "constants"; const SimpleFormSchema: InstillJSONSchema = { title: "Simple Form JSON", diff --git a/packages/toolkit/src/lib/vdp-sdk/connector/actions.ts b/packages/toolkit/src/lib/vdp-sdk/connector/actions.ts index 7e4837b291..307091a28c 100644 --- a/packages/toolkit/src/lib/vdp-sdk/connector/actions.ts +++ b/packages/toolkit/src/lib/vdp-sdk/connector/actions.ts @@ -1,6 +1,6 @@ import { Nullable } from "../../type"; import { createInstillAxiosClient } from "../helper"; -import { Connector, ConnectorState, ConnectorWithDefinition } from "./types"; +import { ConnectorState, ConnectorWithDefinition } from "./types"; export type TestUserConnectorConnectionResponse = { state: ConnectorState; diff --git a/packages/toolkit/src/view/model/CreateModelForm.tsx b/packages/toolkit/src/view/model/CreateModelForm.tsx index fc547fca1e..2d65188523 100644 --- a/packages/toolkit/src/view/model/CreateModelForm.tsx +++ b/packages/toolkit/src/view/model/CreateModelForm.tsx @@ -20,7 +20,6 @@ import { type Model, type Nullable, type CreateResourceFormStore, - useAmplitudeCtx, sendAmplitudeData, useCreateResourceFormStore, getInstillApiErrorMessage, @@ -85,7 +84,6 @@ export const CreateModelForm = (props: CreateModelFormProps) => { * Initialize form state * -----------------------------------------------------------------------*/ - const { amplitudeIsInit } = useAmplitudeCtx(); const queryClient = useQueryClient(); const { @@ -233,7 +231,7 @@ export const CreateModelForm = (props: CreateModelFormProps) => { model_definition_name: modelDefinitionName, }); }, - [amplitudeIsInit, accessToken, queryClient, setFieldValue] + [accessToken, queryClient, setFieldValue] ); const deployUserModel = useDeployUserModel(); diff --git a/packages/toolkit/src/view/pipeline-builder/components/ComponentOutputReferenceHints.tsx b/packages/toolkit/src/view/pipeline-builder/components/ComponentOutputReferenceHints.tsx new file mode 100644 index 0000000000..ba0f850545 --- /dev/null +++ b/packages/toolkit/src/view/pipeline-builder/components/ComponentOutputReferenceHints.tsx @@ -0,0 +1,47 @@ +import { ScrollArea } from "@instill-ai/design-system"; +import { + InstillJSONSchema, + Nullable, + useComponentOutputReferenceHintFields, +} from "../../../lib"; +import { ReferenceHintTag } from "../../../components"; + +export const ComponentOutputReferenceHints = ({ + componentID, + outputSchema, +}: { + componentID: string; + outputSchema: Nullable; +}) => { + const hintFields = useComponentOutputReferenceHintFields(outputSchema, { + componentID, + }); + + return ( +
+

+ Output +

+ + +
+
+ + + + references + + +
+
{hintFields}
+
+
+
+ ); +}; diff --git a/packages/toolkit/src/view/pipeline-builder/components/ComponentOutputs.tsx b/packages/toolkit/src/view/pipeline-builder/components/ComponentOutputs.tsx index 612117b946..4b626d0103 100644 --- a/packages/toolkit/src/view/pipeline-builder/components/ComponentOutputs.tsx +++ b/packages/toolkit/src/view/pipeline-builder/components/ComponentOutputs.tsx @@ -58,7 +58,9 @@ export const ComponentOutputs = ({ return (
{nodeType === "connector" ? ( -
output
+
+ Output +
) : null} ({ selectedConnectorNodeId: store.selectedConnectorNodeId, @@ -295,7 +295,11 @@ export const ConnectorNode = ({ data, id }: NodeProps) => { (e) => e.name === data.component.definition_name ) ?? null ); - }, [connectorDefinitions.isSuccess, connectorDefinitions.data]); + }, [ + connectorDefinitions.isSuccess, + connectorDefinitions.data, + data.component, + ]); return ( ) => {
{!resourceNotCreated && !enableEdit ? ( - + ) : null}
diff --git a/packages/toolkit/src/view/pipeline-builder/components/nodes/operator-node/OperatorNode.tsx b/packages/toolkit/src/view/pipeline-builder/components/nodes/operator-node/OperatorNode.tsx index 4d8b11cba1..eadaaa1e75 100644 --- a/packages/toolkit/src/view/pipeline-builder/components/nodes/operator-node/OperatorNode.tsx +++ b/packages/toolkit/src/view/pipeline-builder/components/nodes/operator-node/OperatorNode.tsx @@ -19,7 +19,6 @@ import { ImageWithFallback, ObjectViewer } from "../../../../../components"; import { useShallow } from "zustand/react/shallow"; import { ConnectorOperatorControlPanel } from "../control-panel"; import { OpenAdvancedConfigurationButton } from "../../OpenAdvancedConfigurationButton"; -import { ComponentOutputs } from "../../ComponentOutputs"; import { getOperatorInputOutputSchema } from "../../../lib/getOperatorInputOutputSchema"; import { useCheckIsHidden } from "../../useCheckIsHidden"; import { useUpdaterOnNode } from "../../useUpdaterOnNode"; @@ -31,6 +30,7 @@ import { NodeWrapper, useNodeIDEditorForm, } from "../common"; +import { ComponentOutputReferenceHints } from "../../ComponentOutputReferenceHints"; const selector = (store: InstillStore) => ({ selectedConnectorNodeId: store.selectedConnectorNodeId, @@ -339,12 +339,9 @@ export const OperatorNode = ({ data, id }: NodeProps) => { />
- )} diff --git a/packages/toolkit/src/view/pipeline-builder/components/nodes/start-operator-node/StartOperatorNode.tsx b/packages/toolkit/src/view/pipeline-builder/components/nodes/start-operator-node/StartOperatorNode.tsx index 4f45211081..535aaeb93f 100644 --- a/packages/toolkit/src/view/pipeline-builder/components/nodes/start-operator-node/StartOperatorNode.tsx +++ b/packages/toolkit/src/view/pipeline-builder/components/nodes/start-operator-node/StartOperatorNode.tsx @@ -30,7 +30,6 @@ import { import { pickSelectedTypeFromInstillFormat } from "./pickSelectedTypeFromInstillFormat"; import { arrayMove } from "@dnd-kit/sortable"; -import { constructFieldKey } from "./constructFieldKey"; import { StartEndOperatorControlPanel } from "../control-panel"; import { NodeHead, NodeSortableFieldWrapper, NodeWrapper } from "../common"; import { VerticalSortableWrapper } from "../../VerticalSortableWrapper"; diff --git a/packages/toolkit/src/view/pipeline-builder/lib/getReferencesFromString.ts b/packages/toolkit/src/view/pipeline-builder/lib/getReferencesFromString.ts index 1253ee4de7..1fa17dba82 100644 --- a/packages/toolkit/src/view/pipeline-builder/lib/getReferencesFromString.ts +++ b/packages/toolkit/src/view/pipeline-builder/lib/getReferencesFromString.ts @@ -1,4 +1,4 @@ -import { InstillReference, ReferenceValueSet } from "../type"; +import { InstillReference } from "../type"; export function getReferencesFromString(value: string): InstillReference[] { const dollarBraceReferences: InstillReference[] = []; diff --git a/packages/toolkit/src/view/pipeline/view-pipelines/CreatePipelineDialog.tsx b/packages/toolkit/src/view/pipeline/view-pipelines/CreatePipelineDialog.tsx index 306924ec4a..5cacdec977 100644 --- a/packages/toolkit/src/view/pipeline/view-pipelines/CreatePipelineDialog.tsx +++ b/packages/toolkit/src/view/pipeline/view-pipelines/CreatePipelineDialog.tsx @@ -68,7 +68,6 @@ export const CreatePipelineDialog = ({ className }: { className?: string }) => { const [permission, setPermission] = React.useState>("private"); const router = useRouter(); - const { entity } = router.query; const { toast } = useToast(); @@ -101,7 +100,13 @@ export const CreatePipelineDialog = ({ className }: { className?: string }) => { }); } return orgsAndUserList; - }, [organizations.isSuccess, entityObject.isSuccess]); + }, [ + organizations.isSuccess, + organizations.data, + entityObject.isSuccess, + entityObject.entity, + entityObject.entityName, + ]); const createPipeline = useCreateUserPipeline(); async function onSubmit(data: z.infer) { diff --git a/packages/toolkit/src/view/pipeline/view-pipelines/ViewPipelines.tsx b/packages/toolkit/src/view/pipeline/view-pipelines/ViewPipelines.tsx index 1ee048a31d..8f808ec7af 100644 --- a/packages/toolkit/src/view/pipeline/view-pipelines/ViewPipelines.tsx +++ b/packages/toolkit/src/view/pipeline/view-pipelines/ViewPipelines.tsx @@ -73,7 +73,7 @@ export const ViewPipelines = ({ } return all; - }, [pipelines.data, pipelines.isSuccess, searchCode]); + }, [pipelines.data, pipelines.isSuccess]); return (