This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import { createDisableDeclarationPlugin } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const VariableSelector = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.VariableSelector,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
plugins={() => [createDisableDeclarationPlugin()]}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<string[] | undefined> name="variable_selector">
|
||||
{({ field }) => (
|
||||
<VariableSelector value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
.json-schema-color-picker-container {
|
||||
.semi-colorPicker-popover-defaultChildren {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import {
|
||||
ConditionRow,
|
||||
ConditionRowValueType,
|
||||
createTypePresetPlugin,
|
||||
DynamicValueInput,
|
||||
IFlowConstantRefValue,
|
||||
type IJsonSchema,
|
||||
} from '@flowgram.ai/form-materials';
|
||||
import { ColorPicker } from '@douyinfe/semi-ui';
|
||||
import { IconColorPalette } from '@douyinfe/semi-icons';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
import './json-schema-preset.css';
|
||||
|
||||
const TypeSelector = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.TypeSelector,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
transformInitialNode={{
|
||||
start_0: (node) => {
|
||||
node.data.outputs = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
color_output: {
|
||||
type: 'color',
|
||||
},
|
||||
},
|
||||
};
|
||||
return node;
|
||||
},
|
||||
}}
|
||||
plugins={() => [
|
||||
createTypePresetPlugin({
|
||||
types: [
|
||||
{
|
||||
type: 'color',
|
||||
icon: <IconColorPalette />,
|
||||
label: 'Color',
|
||||
ConstantRenderer: ({ value, onChange }) => (
|
||||
<div className="json-schema-color-picker-container ">
|
||||
<ColorPicker
|
||||
alpha={true}
|
||||
usePopover={true}
|
||||
value={value ? ColorPicker.colorStringToValue(value) : undefined}
|
||||
onChange={(_value) => onChange?.(_value.hex)}
|
||||
/>
|
||||
</div>
|
||||
),
|
||||
conditionRule: {
|
||||
eq: { type: 'color' },
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
]}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<b>Type Selector: </b>
|
||||
<Field<Partial<IJsonSchema> | undefined>
|
||||
name="type_selector"
|
||||
defaultValue={{ type: 'color' }}
|
||||
>
|
||||
{({ field }) => (
|
||||
<TypeSelector value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
|
||||
<b>DynamicValueInput: </b>
|
||||
<Field<IFlowConstantRefValue | undefined>
|
||||
name="dynamic_value_input"
|
||||
defaultValue={{ type: 'constant', schema: { type: 'color' }, content: '#b5ed0c' }}
|
||||
>
|
||||
{({ field }) => (
|
||||
<DynamicValueInput value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
|
||||
<b>Condition: </b>
|
||||
<Field<ConditionRowValueType | undefined>
|
||||
name="condition_row"
|
||||
defaultValue={{
|
||||
left: { type: 'ref', content: ['start_0', 'color_output'] },
|
||||
operator: 'eq',
|
||||
right: { type: 'ref', content: ['start_0', 'color_output'] },
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<ConditionRow value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import { AssignValueType } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const AssignRow = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.AssignRow,
|
||||
}))
|
||||
);
|
||||
|
||||
export const AssignModeStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<AssignValueType | undefined>
|
||||
defaultValue={{
|
||||
operator: 'assign',
|
||||
left: { type: 'ref', content: ['start_0', 'str'] },
|
||||
right: { type: 'constant', content: 'Hello World', schema: { type: 'string' } },
|
||||
}}
|
||||
name="assign_row"
|
||||
>
|
||||
{({ field }) => (
|
||||
<AssignRow value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const DeclareModeStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<AssignValueType | undefined> name="assign_row">
|
||||
{({ field }) => (
|
||||
<AssignRow
|
||||
value={{
|
||||
operator: 'declare',
|
||||
left: 'newVariable',
|
||||
right: {
|
||||
type: 'constant',
|
||||
content: 'Hello World',
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
}}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const AssignRows = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.AssignRows,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<AssignRows name="assign_rows" />
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,171 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field, FlowNodeRegistry } from '@flowgram.ai/free-layout-editor';
|
||||
import { SubCanvasRender, createContainerNodePlugin } from '@flowgram.ai/free-container-plugin';
|
||||
import {
|
||||
provideBatchInputEffect,
|
||||
createBatchOutputsFormPlugin,
|
||||
type IFlowRefValue,
|
||||
DisplayOutputs,
|
||||
} from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const BatchVariableSelector = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.BatchVariableSelector,
|
||||
}))
|
||||
);
|
||||
|
||||
const BatchOutputs = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.BatchOutputs,
|
||||
}))
|
||||
);
|
||||
|
||||
type BatchOutputsValueType = Record<string, IFlowRefValue | undefined>;
|
||||
|
||||
const createLoopRegistry = (): FlowNodeRegistry => ({
|
||||
type: 'custom',
|
||||
meta: {
|
||||
isContainer: true,
|
||||
size: {
|
||||
width: 500,
|
||||
height: 260,
|
||||
},
|
||||
padding: () => ({
|
||||
top: 160,
|
||||
bottom: 40,
|
||||
left: 50,
|
||||
right: 50,
|
||||
}),
|
||||
},
|
||||
formMeta: {
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Loop input (select array variable):
|
||||
</div>
|
||||
<Field<IFlowRefValue | undefined>
|
||||
name="loopFor"
|
||||
defaultValue={{ type: 'ref', content: ['start_0', 'arr', 'arr_obj'] }}
|
||||
>
|
||||
{({ field }) => (
|
||||
<BatchVariableSelector
|
||||
style={{ width: '100%' }}
|
||||
value={field.value?.content}
|
||||
onChange={(val) => field.onChange({ type: 'ref', content: val })}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
<SubCanvasRender offsetY={-100} />
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Loop outputs (key-value pairs collected into arrays):
|
||||
</div>
|
||||
<Field<BatchOutputsValueType | undefined>
|
||||
name="loopOutputs"
|
||||
defaultValue={{
|
||||
result: { type: 'ref', content: ['variable_0', 'result'] },
|
||||
count: { type: 'ref', content: ['variable_0', 'count'] },
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<BatchOutputs
|
||||
style={{ width: '100%' }}
|
||||
value={field.value}
|
||||
onChange={(val) => field.onChange(val)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
<div>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Generated output variables:
|
||||
</div>
|
||||
<DisplayOutputs displayFromScope />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
effect: {
|
||||
loopFor: provideBatchInputEffect,
|
||||
},
|
||||
plugins: [
|
||||
createBatchOutputsFormPlugin({ outputKey: 'loopOutputs', inferTargetKey: 'outputs' }),
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
height={550}
|
||||
initialData={{
|
||||
nodes: [
|
||||
{
|
||||
id: 'custom_0',
|
||||
type: 'custom',
|
||||
data: {
|
||||
title: 'Loop',
|
||||
loopFor: { type: 'ref', content: ['start_0', 'arr', 'arr_obj'] },
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
id: 'block_start_0',
|
||||
type: 'block-start',
|
||||
data: { title: 'Start' },
|
||||
meta: { position: { x: 20, y: 0 } },
|
||||
},
|
||||
{
|
||||
id: 'variable_0',
|
||||
type: 'variable',
|
||||
data: {
|
||||
title: 'Variable',
|
||||
assign: [
|
||||
{
|
||||
operator: 'declare',
|
||||
left: 'result',
|
||||
right: { type: 'ref', content: ['custom_0_locals', 'item', 'str'] },
|
||||
},
|
||||
{
|
||||
operator: 'declare',
|
||||
left: 'count',
|
||||
right: { type: 'ref', content: ['custom_0_locals', 'index'] },
|
||||
},
|
||||
],
|
||||
},
|
||||
meta: { position: { x: 100, y: 0 } },
|
||||
},
|
||||
{
|
||||
id: 'block_end_0',
|
||||
type: 'block-end',
|
||||
data: { title: 'End' },
|
||||
meta: { position: { x: 360, y: 0 } },
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{ sourceNodeID: 'block_start_0', targetNodeID: 'variable_0' },
|
||||
{ sourceNodeID: 'variable_0', targetNodeID: 'block_end_0' },
|
||||
],
|
||||
},
|
||||
],
|
||||
edges: [{ sourceNodeID: 'start_0', targetNodeID: 'custom_0' }],
|
||||
}}
|
||||
transformRegistry={(props) => ({
|
||||
...props,
|
||||
nodeRegistries: [
|
||||
...(props.nodeRegistries || []).filter((r) => r.type !== 'custom'),
|
||||
createLoopRegistry(),
|
||||
],
|
||||
})}
|
||||
plugins={(ctx) => [createContainerNodePlugin({})]}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const BatchVariableSelector = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.BatchVariableSelector,
|
||||
}))
|
||||
);
|
||||
|
||||
const VariableSelector = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.VariableSelector,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
BatchVariableSelector (Array variables only):
|
||||
</div>
|
||||
<Field<string[] | undefined> name="batch_variable">
|
||||
{({ field }) => (
|
||||
<BatchVariableSelector
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
VariableSelector (All variables):
|
||||
</div>
|
||||
<Field<string[] | undefined> name="normal_variable">
|
||||
{({ field }) => (
|
||||
<VariableSelector value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const BlurInput = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.BlurInput,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
filterStartNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<string> name="blur_input" defaultValue="Initial text">
|
||||
{({ field }) => (
|
||||
<>
|
||||
<BlurInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
placeholder="Please enter text"
|
||||
/>
|
||||
<p className="mt-2">Current value: {field.value}</p>
|
||||
<p className="text-sm text-gray-500">
|
||||
Note: Value updates after clicking outside the input
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const PlaceholderStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
filterStartNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<string> name="blur_input_placeholder" defaultValue="">
|
||||
{({ field }) => (
|
||||
<>
|
||||
<BlurInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
placeholder="This is an input field with placeholder"
|
||||
/>
|
||||
<p className="mt-2">Current value: {field.value || 'Empty'}</p>
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const DisabledStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
filterStartNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<string> name="blur_input_disabled" defaultValue="Disabled state text">
|
||||
{({ field }) => (
|
||||
<BlurInput value={field.value} onChange={(value) => field.onChange(value)} disabled />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const CodeEditor = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.CodeEditor,
|
||||
}))
|
||||
);
|
||||
|
||||
const defaultTsCode = `// Here, you can retrieve input variables from the node using 'params' and output results using 'ret'.
|
||||
// 'params' has been correctly injected into the environment.
|
||||
// Here's an example of getting the value of the parameter named 'input' from the node input:
|
||||
// const input = params.input;
|
||||
// Here's an example of outputting a 'ret' object containing multiple data types:
|
||||
// const ret = { "name": 'Xiaoming', "hobbies": ["Reading", "Traveling"] };
|
||||
|
||||
async function main({ params }) {
|
||||
// Build the output object
|
||||
const ret = {
|
||||
key0: params.input + params.input, // Concatenate the input parameter 'input' twice
|
||||
key1: ["hello", "world"], // Output an array
|
||||
key2: { // Output an Object
|
||||
key21: "hi"
|
||||
},
|
||||
};
|
||||
|
||||
return ret;
|
||||
}`;
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterStartNode
|
||||
filterEndNode
|
||||
height={600}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<div style={{ width: 500 }}>
|
||||
<FormHeader />
|
||||
<Field<string | undefined> name="code_editor" defaultValue={defaultTsCode}>
|
||||
{({ field }) => (
|
||||
<CodeEditor
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
languageId="typescript"
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import type { ConditionOpConfigs, IConditionRule } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const ConditionRow = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.ConditionRow,
|
||||
}))
|
||||
);
|
||||
|
||||
const DBConditionRow = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DBConditionRow,
|
||||
}))
|
||||
);
|
||||
|
||||
const ConditionProvider = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.ConditionProvider,
|
||||
}))
|
||||
);
|
||||
|
||||
const OPS: ConditionOpConfigs = {
|
||||
cop: {
|
||||
abbreviation: 'C',
|
||||
label: 'Custom Operator',
|
||||
},
|
||||
};
|
||||
|
||||
const RULES: Record<string, IConditionRule> = {
|
||||
string: {
|
||||
cop: { type: 'string' },
|
||||
},
|
||||
};
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<ConditionProvider ops={OPS} rules={RULES}>
|
||||
<Field<any | undefined> name="condition_row">
|
||||
{({ field }) => (
|
||||
<ConditionRow value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<Field<any | undefined> name="db_condition_row">
|
||||
{({ field }) => (
|
||||
<DBConditionRow
|
||||
options={[
|
||||
{
|
||||
label: 'UserName',
|
||||
value: 'username',
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
]}
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</ConditionProvider>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const ConditionRow = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.ConditionRow,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<any | undefined>
|
||||
name="condition_row"
|
||||
defaultValue={{
|
||||
left: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'str'],
|
||||
},
|
||||
operator: 'eq',
|
||||
right: {
|
||||
type: 'constant',
|
||||
content: 'Hello World!',
|
||||
schema: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<ConditionRow value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const ConstantInput = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.ConstantInput,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterStartNode
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
|
||||
<b>String</b>
|
||||
<Field<string> name="constant_string" defaultValue="Hello World">
|
||||
{({ field }) => (
|
||||
<ConstantInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
schema={{ type: 'string' }}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<b>Enum</b>
|
||||
<Field<string> name="constant_enum" defaultValue="morning">
|
||||
{({ field }) => (
|
||||
<ConstantInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
schema={{ type: 'string', enum: ['morning', 'afternoon'] }}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<b>Number</b>
|
||||
<Field<number> name="constant_number" defaultValue={42}>
|
||||
{({ field }) => (
|
||||
<ConstantInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
schema={{ type: 'number' }}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<b>Boolean</b>
|
||||
<Field<boolean> name="constant_boolean" defaultValue={true}>
|
||||
{({ field }) => (
|
||||
<ConstantInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
schema={{ type: 'boolean' }}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<b>Object</b>
|
||||
<Field<string>
|
||||
name="constant_object"
|
||||
defaultValue={JSON.stringify({ key: 'value', nested: { data: 'test' } })}
|
||||
>
|
||||
{({ field }) => (
|
||||
<ConstantInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
schema={{ type: 'object' }}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<b>Array</b>
|
||||
<Field<string>
|
||||
name="constant_array"
|
||||
defaultValue={JSON.stringify([1, 2, 3, 'four', true])}
|
||||
>
|
||||
{({ field }) => (
|
||||
<ConstantInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
schema={{ type: 'array' }}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const FallbackRendererStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterStartNode
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<any>
|
||||
name="constant_fallback"
|
||||
defaultValue={{ custom: 'data', type: 'unsupported' }}
|
||||
>
|
||||
{({ field }) => (
|
||||
<ConstantInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
schema={{ type: 'custom-unsupported-type' }}
|
||||
fallbackRenderer={({ value, onChange, readonly }) => (
|
||||
<div style={{ padding: '8px', background: '#f0f0f0', border: '1px dashed #ccc' }}>
|
||||
<p>Fallback renderer for unsupported type</p>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const CustomStrategyStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterStartNode
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<string> name="constant_custom" defaultValue="Custom Value">
|
||||
{({ field }) => (
|
||||
<ConstantInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
schema={{ type: 'object' }}
|
||||
strategies={[
|
||||
{
|
||||
hit: (schema) => schema.type === 'object',
|
||||
Renderer: ({ value, onChange, readonly }) => <p>Object is not supported now</p>,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const DBConditionRow = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DBConditionRow,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<any | undefined>
|
||||
name="db_condition_row"
|
||||
defaultValue={{
|
||||
left: 'amount',
|
||||
operator: 'gt',
|
||||
right: {
|
||||
type: 'constant',
|
||||
content: 1000,
|
||||
schema: {
|
||||
type: 'number',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<DBConditionRow
|
||||
options={[
|
||||
{
|
||||
label: 'TransactionID',
|
||||
value: 'transaction_id',
|
||||
schema: { type: 'integer' },
|
||||
},
|
||||
{
|
||||
label: 'Amount',
|
||||
value: 'amount',
|
||||
schema: { type: 'number' },
|
||||
},
|
||||
{
|
||||
label: 'Description',
|
||||
value: 'description',
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
{
|
||||
label: 'Archived',
|
||||
value: 'archived',
|
||||
schema: { type: 'boolean' },
|
||||
},
|
||||
{
|
||||
label: 'CreateTime',
|
||||
value: 'create_time',
|
||||
schema: { type: 'date-time' },
|
||||
},
|
||||
]}
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const DynamicValueInput = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DynamicValueInput,
|
||||
}))
|
||||
);
|
||||
|
||||
const DisplayFlowValue = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DisplayFlowValue,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode={true}
|
||||
transformInitialNode={{
|
||||
custom_0: (node) => {
|
||||
node.data.dynamic_value_input = {
|
||||
type: 'constant',
|
||||
content: 'Hello World',
|
||||
};
|
||||
return node;
|
||||
},
|
||||
}}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<any> name="dynamic_value_input">
|
||||
{({ field }) => (
|
||||
<DynamicValueInput value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
<div>
|
||||
<Field<any> name="dynamic_value_input">
|
||||
{({ field }) => {
|
||||
console.log('debugger field value', field);
|
||||
return <DisplayFlowValue value={field.value} title="Display Flow Value" />;
|
||||
}}
|
||||
</Field>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const InputsValuesTree = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.InputsValuesTree,
|
||||
}))
|
||||
);
|
||||
|
||||
const DisplayInputsValues = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DisplayInputsValues,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode={true}
|
||||
transformInitialNode={{
|
||||
custom_0: (node) => {
|
||||
node.data.inputs_values = {
|
||||
a: {
|
||||
b: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'str'],
|
||||
},
|
||||
c: {
|
||||
type: 'constant',
|
||||
content: 'hello',
|
||||
},
|
||||
},
|
||||
d: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'arr', 'arr_str'],
|
||||
},
|
||||
e: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'obj'],
|
||||
},
|
||||
};
|
||||
return node;
|
||||
},
|
||||
}}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<Record<string, any> | undefined> name="inputs_values">
|
||||
{({ field }) => (
|
||||
<InputsValuesTree value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
<Field<Record<string, any> | undefined> name="inputs_values">
|
||||
{({ field }) => <DisplayInputsValues value={field.value} />}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import { provideJsonSchemaOutputs, type IJsonSchema } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const DisplayOutputs = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DisplayOutputs,
|
||||
}))
|
||||
);
|
||||
|
||||
const JsonSchemaEditor = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.JsonSchemaEditor,
|
||||
}))
|
||||
);
|
||||
|
||||
export const DisplayFromScopeStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
filterStartNode
|
||||
transformInitialNode={{
|
||||
custom_0: (node) => {
|
||||
node.data.outputs = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
result: { type: 'string' },
|
||||
status: { type: 'number' },
|
||||
},
|
||||
};
|
||||
return node;
|
||||
},
|
||||
}}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<IJsonSchema | undefined> name="outputs">
|
||||
{({ field }) => (
|
||||
<JsonSchemaEditor value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
<b>Display Outputs by Scope:</b>
|
||||
<DisplayOutputs displayFromScope />
|
||||
</>
|
||||
),
|
||||
effect: {
|
||||
outputs: provideJsonSchemaOutputs,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const DisplayFromFieldStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
filterStartNode
|
||||
transformInitialNode={{
|
||||
custom_0: (node) => {
|
||||
node.data.outputs = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
result: { type: 'string' },
|
||||
status: { type: 'number' },
|
||||
},
|
||||
};
|
||||
return node;
|
||||
},
|
||||
}}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<IJsonSchema | undefined> name="outputs">
|
||||
{({ field }) => (
|
||||
<JsonSchemaEditor value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
<b>Display Outputs By Schema</b>
|
||||
<Field<IJsonSchema | undefined> name="outputs">
|
||||
{({ field }) => <DisplayOutputs value={field.value} />}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,59 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const DisplaySchemaTag = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DisplaySchemaTag,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
filterStartNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<div>
|
||||
<DisplaySchemaTag
|
||||
title="Transaction"
|
||||
value={{
|
||||
type: 'object',
|
||||
properties: {
|
||||
transaction_id: { type: 'integer' },
|
||||
amount: { type: 'number' },
|
||||
description: { type: 'string' },
|
||||
archived: { type: 'boolean' },
|
||||
owner: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' },
|
||||
username: { type: 'string' },
|
||||
friends: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' },
|
||||
username: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const DisplaySchemaTree = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DisplaySchemaTree,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
filterStartNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<DisplaySchemaTree
|
||||
value={{
|
||||
type: 'object',
|
||||
properties: {
|
||||
transaction_id: { type: 'integer' },
|
||||
amount: { type: 'number' },
|
||||
description: { type: 'string' },
|
||||
archived: { type: 'boolean' },
|
||||
owner: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' },
|
||||
username: { type: 'string' },
|
||||
friends: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
id: { type: 'integer' },
|
||||
username: { type: 'string' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const DynamicValueInput = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DynamicValueInput,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<any> name="dynamic_value_input">
|
||||
{({ field }) => (
|
||||
<DynamicValueInput value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const WithSchemaStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<any> name="dynamic_value_input">
|
||||
{({ field }) => (
|
||||
<DynamicValueInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
schema={{ type: 'string' }}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const InputsValuesTree = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.InputsValuesTree,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<Record<string, any> | undefined>
|
||||
name="inputs_values"
|
||||
defaultValue={{
|
||||
a: {
|
||||
b: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'str'],
|
||||
},
|
||||
c: {
|
||||
type: 'constant',
|
||||
content: 'hello',
|
||||
},
|
||||
},
|
||||
d: {
|
||||
type: 'constant',
|
||||
content: '{ "a": "b"}',
|
||||
schema: { type: 'object' },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<InputsValuesTree value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const InputsValues = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.InputsValues,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<Record<string, any> | undefined>
|
||||
name="inputs_values"
|
||||
defaultValue={{
|
||||
a: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'str'],
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<InputsValues value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const WithSchemaStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<Record<string, any> | undefined>
|
||||
name="inputs_values"
|
||||
defaultValue={{
|
||||
a: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'str'],
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<InputsValues
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
schema={{
|
||||
type: 'string',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const JsonEditorWithVariables = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.JsonEditorWithVariables,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<div style={{ width: 400 }}>
|
||||
<FormHeader />
|
||||
<Field<any> name="json_editor_with_variables" defaultValue={`{ "a": {{start_0.str}}}`}>
|
||||
{({ field }) => (
|
||||
<JsonEditorWithVariables
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import type { IJsonSchema } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const JsonSchemaCreator = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.JsonSchemaCreator,
|
||||
}))
|
||||
);
|
||||
|
||||
const JsonSchemaEditor = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.JsonSchemaEditor,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<IJsonSchema | undefined> name="json_schema">
|
||||
{({ field }) => (
|
||||
<div>
|
||||
<JsonSchemaCreator onSchemaCreate={(schema) => field.onChange(schema)} />
|
||||
<div style={{ marginTop: 16 }}>
|
||||
<JsonSchemaEditor
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import type { IJsonSchema } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const JsonSchemaEditor = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.JsonSchemaEditor,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterStartNode
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<IJsonSchema | undefined>
|
||||
name="json_schema_editor"
|
||||
defaultValue={{
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
age: { type: 'number' },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<JsonSchemaEditor value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import { IFlowTemplateValue, IInputsValues, InputsValuesTree } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const PromptEditorWithInputs = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.PromptEditorWithInputs,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<div style={{ width: 400 }}>
|
||||
<FormHeader />
|
||||
<Field<IInputsValues | undefined>
|
||||
name="inputsValues"
|
||||
defaultValue={{
|
||||
a: { type: 'constant', content: '123' },
|
||||
b: { type: 'ref', content: ['start_0', 'obj'] },
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<InputsValuesTree value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
<Field<IInputsValues | undefined> name="inputsValues">
|
||||
{({ field: inputsField }) => (
|
||||
<Field<IFlowTemplateValue | undefined>
|
||||
name="prompt_editor_with_inputs"
|
||||
defaultValue={{
|
||||
type: 'template',
|
||||
content: '# Query \n {{b.obj2.num}}',
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<PromptEditorWithInputs
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
inputsValues={inputsField.value || {}}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const WithoutCanvas = () => {
|
||||
const [value, setValue] = useState<IFlowTemplateValue | undefined>({
|
||||
type: 'template',
|
||||
content: '# Role \nYou are a helpful assistant. \n\n# Query \n{{b.obj2.num}} \n\n',
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PromptEditorWithInputs
|
||||
value={value}
|
||||
onChange={(value) => setValue(value)}
|
||||
inputsValues={{
|
||||
a: { type: 'constant', content: '123' },
|
||||
b: {
|
||||
c: {
|
||||
d: { type: 'constant', content: 456 },
|
||||
},
|
||||
e: { type: 'constant', content: 789 },
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const PromptEditorWithVariables = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.PromptEditorWithVariables,
|
||||
}))
|
||||
);
|
||||
|
||||
const VariableSelectorProvider = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.VariableSelectorProvider,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<div style={{ width: 400 }}>
|
||||
<FormHeader />
|
||||
<Field<any | undefined>
|
||||
name="prompt_editor"
|
||||
defaultValue={{
|
||||
type: 'template',
|
||||
content: `# Role
|
||||
You are a helpful assistant
|
||||
|
||||
# Query
|
||||
{{start_0.str}}`,
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<PromptEditorWithVariables
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
const STRING_ONLY_SCHEMA = { type: 'string' };
|
||||
export const StringOnlyStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<div style={{ width: 400 }}>
|
||||
<FormHeader />
|
||||
<VariableSelectorProvider includeSchema={STRING_ONLY_SCHEMA}>
|
||||
<Field<any | undefined>
|
||||
name="prompt_editor"
|
||||
defaultValue={{
|
||||
type: 'template',
|
||||
content: `# Role
|
||||
You are a helpful assistant`,
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<PromptEditorWithVariables
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</VariableSelectorProvider>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const PromptEditor = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.PromptEditor,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<any | undefined>
|
||||
name="prompt_editor"
|
||||
defaultValue={{
|
||||
type: 'template',
|
||||
content: '# Role \n You are a helpful assistant',
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<PromptEditor value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const SQLEditorWithVariables = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.SQLEditorWithVariables,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<div style={{ width: 400 }}>
|
||||
<FormHeader />
|
||||
<Field<string | undefined>
|
||||
name="sql_editor_with_variables"
|
||||
defaultValue={'SELECT * FROM users \n WHERE user_id = {{start_0.str}}'}
|
||||
>
|
||||
{({ field }) => (
|
||||
<SQLEditorWithVariables
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import type { IJsonSchema } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const TypeSelector = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.TypeSelector,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterStartNode
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<Partial<IJsonSchema> | undefined>
|
||||
name="type_selector"
|
||||
defaultValue={{ type: 'string' }}
|
||||
>
|
||||
{({ field }) => (
|
||||
<TypeSelector value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import { useVariableTree } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const VariableSelector = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.VariableSelector,
|
||||
}))
|
||||
);
|
||||
|
||||
const VariableSelectorProvider = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.VariableSelectorProvider,
|
||||
}))
|
||||
);
|
||||
|
||||
const Tree = React.lazy(() =>
|
||||
import('@douyinfe/semi-ui').then((module) => ({
|
||||
default: module.Tree,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<string[] | undefined> name="variable_selector">
|
||||
{({ field }) => (
|
||||
<VariableSelector value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const FilterSchemaStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<string[] | undefined> name="variable_selector">
|
||||
{({ field }) => (
|
||||
<VariableSelector
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
includeSchema={{ type: 'string' }}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const CustomFilterStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<VariableSelectorProvider skipVariable={(variable) => variable?.key === 'str'}>
|
||||
<FormHeader />
|
||||
<Field<string[] | undefined> name="variable_selector">
|
||||
{({ field }) => (
|
||||
<VariableSelector value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</VariableSelectorProvider>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
||||
export const CustomVariableTreeStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
render: () => {
|
||||
const treeData = useVariableTree({});
|
||||
|
||||
return (
|
||||
<VariableSelectorProvider skipVariable={(variable) => variable?.key === 'str'}>
|
||||
<FormHeader />
|
||||
<Tree treeData={treeData} defaultExpandAll />
|
||||
</VariableSelectorProvider>
|
||||
);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { autoRenameRefEffect } from '@flowgram.ai/form-materials';
|
||||
import { Field } from '@flowgram.ai/fixed-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const InputsValues = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.InputsValues,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
effect: {
|
||||
inputsValues: autoRenameRefEffect,
|
||||
},
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<Record<string, any> | undefined>
|
||||
name="inputsValues"
|
||||
defaultValue={{
|
||||
a: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'str'],
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<InputsValues value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { listenRefSchemaChange } from '@flowgram.ai/form-materials';
|
||||
import { Field } from '@flowgram.ai/fixed-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const InputsValues = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.InputsValues,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
effect: {
|
||||
'inputsValues.*': listenRefSchemaChange(({ name, schema, form, formValues }) => {
|
||||
form.setValueIn(
|
||||
`log`,
|
||||
`${form.getValueIn(`log`) || ''}${name}: ${JSON.stringify(schema)}\n`
|
||||
);
|
||||
}),
|
||||
},
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<Record<string, any> | undefined>
|
||||
name="inputsValues"
|
||||
defaultValue={{
|
||||
a: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'str'],
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<InputsValues value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
<Field<any> name="log" defaultValue={'When schema updated, log changes:\n'}>
|
||||
{({ field }) => (
|
||||
<pre
|
||||
style={{
|
||||
width: 500,
|
||||
padding: 4,
|
||||
background: '#f5f5f5',
|
||||
fontSize: 12,
|
||||
whiteSpace: 'pre-wrap',
|
||||
}}
|
||||
>
|
||||
{field.value}
|
||||
</pre>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { listenRefValueChange } from '@flowgram.ai/form-materials';
|
||||
import { Field } from '@flowgram.ai/fixed-layout-editor';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const InputsValues = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.InputsValues,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
formMeta={{
|
||||
effect: {
|
||||
'inputsValues.*': listenRefValueChange(({ name, variable, form }) => {
|
||||
form.setValueIn(
|
||||
`log`,
|
||||
`${form.getValueIn(`log`) || ''}${name}: ${JSON.stringify(variable?.toJSON() || {})} \n`
|
||||
);
|
||||
}),
|
||||
},
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<Record<string, any> | undefined>
|
||||
name="inputsValues"
|
||||
defaultValue={{
|
||||
a: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'str'],
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<InputsValues value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
<Field<any> name="log" defaultValue={'When variable value updated, log changes:\n'}>
|
||||
{({ field }) => (
|
||||
<pre
|
||||
style={{
|
||||
width: 500,
|
||||
padding: 4,
|
||||
background: '#f5f5f5',
|
||||
fontSize: 12,
|
||||
whiteSpace: 'pre-wrap',
|
||||
}}
|
||||
>
|
||||
{field.value}
|
||||
</pre>
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field, FlowNodeRegistry } from '@flowgram.ai/free-layout-editor';
|
||||
import { SubCanvasRender, createContainerNodePlugin } from '@flowgram.ai/free-container-plugin';
|
||||
import {
|
||||
provideBatchInputEffect,
|
||||
createBatchOutputsFormPlugin,
|
||||
type IFlowRefValue,
|
||||
DisplayOutputs,
|
||||
} from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const BatchVariableSelector = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.BatchVariableSelector,
|
||||
}))
|
||||
);
|
||||
|
||||
const BatchOutputs = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.BatchOutputs,
|
||||
}))
|
||||
);
|
||||
|
||||
const VariableSelector = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.VariableSelector,
|
||||
}))
|
||||
);
|
||||
|
||||
type BatchOutputsValueType = Record<string, IFlowRefValue | undefined>;
|
||||
|
||||
const createLoopRegistry = (): FlowNodeRegistry => ({
|
||||
type: 'custom',
|
||||
meta: {
|
||||
isContainer: true,
|
||||
size: {
|
||||
width: 500,
|
||||
height: 260,
|
||||
},
|
||||
padding: () => ({
|
||||
top: 180,
|
||||
bottom: 40,
|
||||
left: 50,
|
||||
right: 50,
|
||||
}),
|
||||
},
|
||||
formMeta: {
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Loop input (select array variable):
|
||||
</div>
|
||||
<Field<IFlowRefValue | undefined>
|
||||
name="loopFor"
|
||||
defaultValue={{ type: 'ref', content: ['start_0', 'arr', 'arr_obj'] }}
|
||||
>
|
||||
{({ field }) => (
|
||||
<BatchVariableSelector
|
||||
style={{ width: '100%' }}
|
||||
value={field.value?.content}
|
||||
onChange={(val) => field.onChange({ type: 'ref', content: val })}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
<SubCanvasRender offsetY={-120} />
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Available local variables (item & index generated by provideBatchInputEffect):
|
||||
</div>
|
||||
<Field<string[] | undefined> name="localVariable">
|
||||
{({ field }) => (
|
||||
<VariableSelector value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Loop outputs (collected into arrays):
|
||||
</div>
|
||||
<Field<BatchOutputsValueType | undefined>
|
||||
name="loopOutputs"
|
||||
defaultValue={{
|
||||
names: { type: 'ref', content: ['variable_0', 'name'] },
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<BatchOutputs
|
||||
style={{ width: '100%' }}
|
||||
value={field.value}
|
||||
onChange={(val) => field.onChange(val)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
<DisplayOutputs displayFromScope />
|
||||
</>
|
||||
),
|
||||
effect: {
|
||||
loopFor: provideBatchInputEffect,
|
||||
},
|
||||
plugins: [
|
||||
createBatchOutputsFormPlugin({ outputKey: 'loopOutputs', inferTargetKey: 'outputs' }),
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
height={550}
|
||||
initialData={{
|
||||
nodes: [
|
||||
{
|
||||
id: 'custom_0',
|
||||
type: 'custom',
|
||||
data: {
|
||||
title: 'Loop',
|
||||
loopFor: { type: 'ref', content: ['start_0', 'arr', 'arr_obj'] },
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
id: 'block_start_0',
|
||||
type: 'block-start',
|
||||
data: { title: 'Start' },
|
||||
meta: { position: { x: 20, y: 0 } },
|
||||
},
|
||||
{
|
||||
id: 'variable_0',
|
||||
type: 'variable',
|
||||
data: {
|
||||
title: 'Variable',
|
||||
assign: [
|
||||
{
|
||||
operator: 'declare',
|
||||
left: 'name',
|
||||
right: { type: 'ref', content: ['custom_0_locals', 'item', 'str'] },
|
||||
},
|
||||
],
|
||||
},
|
||||
meta: { position: { x: 100, y: 0 } },
|
||||
},
|
||||
{
|
||||
id: 'block_end_0',
|
||||
type: 'block-end',
|
||||
data: { title: 'End' },
|
||||
meta: { position: { x: 360, y: 0 } },
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{ sourceNodeID: 'block_start_0', targetNodeID: 'variable_0' },
|
||||
{ sourceNodeID: 'variable_0', targetNodeID: 'block_end_0' },
|
||||
],
|
||||
},
|
||||
],
|
||||
edges: [{ sourceNodeID: 'start_0', targetNodeID: 'custom_0' }],
|
||||
}}
|
||||
transformRegistry={(props) => ({
|
||||
...props,
|
||||
nodeRegistries: [
|
||||
...(props.nodeRegistries || []).filter((r) => r.type !== 'custom'),
|
||||
createLoopRegistry(),
|
||||
],
|
||||
})}
|
||||
plugins={(ctx) => [createContainerNodePlugin({})]}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import {
|
||||
provideJsonSchemaOutputs,
|
||||
syncVariableTitle,
|
||||
type IJsonSchema,
|
||||
} from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const JsonSchemaEditor = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.JsonSchemaEditor,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterStartNode
|
||||
transformInitialNode={{
|
||||
end_0: (node) => {
|
||||
node.data.inputsValues = {
|
||||
success: { type: 'constant', content: true, schema: { type: 'boolean' } },
|
||||
message: { type: 'ref', content: ['custom_0', 'name'] },
|
||||
};
|
||||
return node;
|
||||
},
|
||||
}}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<Field<IJsonSchema | undefined>
|
||||
name="outputs"
|
||||
defaultValue={{
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
age: { type: 'number' },
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<JsonSchemaEditor value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
effect: {
|
||||
// Sync the title to variables
|
||||
title: syncVariableTitle,
|
||||
outputs: provideJsonSchemaOutputs,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import { provideJsonSchemaOutputs, syncVariableTitle } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const Input = React.lazy(() =>
|
||||
import('@douyinfe/semi-ui').then((module) => ({
|
||||
default: module.Input,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterStartNode
|
||||
transformInitialNode={{
|
||||
end_0: (node) => {
|
||||
node.data.inputsValues = {
|
||||
success: { type: 'constant', content: true, schema: { type: 'boolean' } },
|
||||
message: { type: 'ref', content: ['custom_0', 'name'] },
|
||||
};
|
||||
return node;
|
||||
},
|
||||
custom_0: (node) => {
|
||||
node.data.outputs = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
name: { type: 'string' },
|
||||
age: { type: 'number' },
|
||||
},
|
||||
};
|
||||
return node;
|
||||
},
|
||||
}}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<p>Please Edit Title below to sync to variables:</p>
|
||||
<Field<string | undefined> name="title">
|
||||
{({ field }) => (
|
||||
<Input value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</>
|
||||
),
|
||||
effect: {
|
||||
// Sync the title to variables
|
||||
title: syncVariableTitle,
|
||||
outputs: provideJsonSchemaOutputs,
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import { validateFlowValue, validateWhenVariableSync } from '@flowgram.ai/form-materials';
|
||||
import { Button } from '@douyinfe/semi-ui';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const DynamicValueInput = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DynamicValueInput,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
transformInitialNode={{
|
||||
custom_0: (node) => {
|
||||
node.data.value = {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'query'],
|
||||
};
|
||||
|
||||
return node;
|
||||
},
|
||||
}}
|
||||
formMeta={{
|
||||
effect: {
|
||||
value: validateWhenVariableSync(),
|
||||
},
|
||||
validate: {
|
||||
value: ({ value, context }) =>
|
||||
validateFlowValue(value, {
|
||||
node: context.node,
|
||||
errorMessages: {
|
||||
unknownVariable: 'Unknown Variable',
|
||||
},
|
||||
}),
|
||||
},
|
||||
render: ({ form }) => {
|
||||
useEffect(() => {
|
||||
form.validate();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormHeader />
|
||||
|
||||
<b>{"Add 'query' in Start"}</b>
|
||||
<Field<any> name="value">
|
||||
{({ field, fieldState }) => (
|
||||
<>
|
||||
<DynamicValueInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
<span style={{ color: 'red' }}>
|
||||
{fieldState.errors?.map((e) => e.message).join('\n')}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
|
||||
<Button onClick={() => form.validate()}>Trigger Validate</Button>
|
||||
</>
|
||||
);
|
||||
},
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field, FlowNodeRegistry } from '@flowgram.ai/free-layout-editor';
|
||||
import { SubCanvasRender, createContainerNodePlugin } from '@flowgram.ai/free-container-plugin';
|
||||
import {
|
||||
provideBatchInputEffect,
|
||||
createBatchOutputsFormPlugin,
|
||||
type IFlowRefValue,
|
||||
DisplayOutputs,
|
||||
} from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const BatchVariableSelector = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.BatchVariableSelector,
|
||||
}))
|
||||
);
|
||||
|
||||
const BatchOutputs = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.BatchOutputs,
|
||||
}))
|
||||
);
|
||||
|
||||
type BatchOutputsValueType = Record<string, IFlowRefValue | undefined>;
|
||||
|
||||
const createLoopRegistry = (): FlowNodeRegistry => ({
|
||||
type: 'custom',
|
||||
meta: {
|
||||
isContainer: true,
|
||||
size: {
|
||||
width: 500,
|
||||
height: 260,
|
||||
},
|
||||
padding: () => ({
|
||||
top: 160,
|
||||
bottom: 40,
|
||||
left: 50,
|
||||
right: 50,
|
||||
}),
|
||||
},
|
||||
formMeta: {
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Loop input (select array variable):
|
||||
</div>
|
||||
<Field<IFlowRefValue | undefined>
|
||||
name="loopFor"
|
||||
defaultValue={{ type: 'ref', content: ['start_0', 'arr', 'arr_obj'] }}
|
||||
>
|
||||
{({ field }) => (
|
||||
<BatchVariableSelector
|
||||
style={{ width: '100%' }}
|
||||
value={field.value?.content}
|
||||
onChange={(val) => field.onChange({ type: 'ref', content: val })}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
<SubCanvasRender offsetY={-100} />
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Loop outputs (collected into arrays):
|
||||
</div>
|
||||
<Field<BatchOutputsValueType | undefined>
|
||||
name="loopOutputs"
|
||||
defaultValue={{
|
||||
names: { type: 'ref', content: ['variable_0', 'name'] },
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<BatchOutputs
|
||||
style={{ width: '100%' }}
|
||||
value={field.value}
|
||||
onChange={(val) => field.onChange(val)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Generated output variables:
|
||||
</div>
|
||||
<DisplayOutputs displayFromScope />
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
effect: {
|
||||
loopFor: provideBatchInputEffect,
|
||||
},
|
||||
plugins: [
|
||||
createBatchOutputsFormPlugin({ outputKey: 'loopOutputs', inferTargetKey: 'outputs' }),
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
const createLoopRegistryWithInfer = (): FlowNodeRegistry => ({
|
||||
type: 'custom',
|
||||
meta: {
|
||||
isContainer: true,
|
||||
size: {
|
||||
width: 500,
|
||||
height: 260,
|
||||
},
|
||||
padding: () => ({
|
||||
top: 160,
|
||||
bottom: 40,
|
||||
left: 50,
|
||||
right: 50,
|
||||
}),
|
||||
},
|
||||
formMeta: {
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>Loop input:</div>
|
||||
<Field<IFlowRefValue | undefined>
|
||||
name="loopFor"
|
||||
defaultValue={{ type: 'ref', content: ['start_0', 'arr', 'arr_obj'] }}
|
||||
>
|
||||
{({ field }) => (
|
||||
<BatchVariableSelector
|
||||
style={{ width: '100%' }}
|
||||
value={field.value?.content}
|
||||
onChange={(val) => field.onChange({ type: 'ref', content: val })}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
<SubCanvasRender offsetY={-100} />
|
||||
<div style={{ marginBottom: 16 }}>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Loop outputs (with schema inference):
|
||||
</div>
|
||||
<Field<BatchOutputsValueType | undefined>
|
||||
name="loopOutputs"
|
||||
defaultValue={{
|
||||
items: { type: 'ref', content: ['variable_0', 'item_name'] },
|
||||
values: { type: 'ref', content: ['variable_0', 'item_index'] },
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<BatchOutputs
|
||||
style={{ width: '100%' }}
|
||||
value={field.value}
|
||||
onChange={(val) => field.onChange(val)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ marginBottom: 8, fontSize: 12, color: '#666' }}>
|
||||
Output variables (check Debug panel for inferred schema):
|
||||
</div>
|
||||
<DisplayOutputs displayFromScope />
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
effect: {
|
||||
loopFor: provideBatchInputEffect,
|
||||
},
|
||||
plugins: [
|
||||
createBatchOutputsFormPlugin({ outputKey: 'loopOutputs', inferTargetKey: 'outputs' }),
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
height={550}
|
||||
initialData={{
|
||||
nodes: [
|
||||
{
|
||||
id: 'custom_0',
|
||||
type: 'custom',
|
||||
data: {
|
||||
title: 'Loop',
|
||||
loopFor: { type: 'ref', content: ['start_0', 'arr', 'arr_obj'] },
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
id: 'block_start_0',
|
||||
type: 'block-start',
|
||||
data: { title: 'Start' },
|
||||
meta: { position: { x: 20, y: 0 } },
|
||||
},
|
||||
{
|
||||
id: 'variable_0',
|
||||
type: 'variable',
|
||||
data: {
|
||||
title: 'Variable',
|
||||
assign: [
|
||||
{
|
||||
operator: 'declare',
|
||||
left: 'name',
|
||||
right: { type: 'ref', content: ['custom_0_locals', 'item', 'str'] },
|
||||
},
|
||||
],
|
||||
},
|
||||
meta: { position: { x: 100, y: 0 } },
|
||||
},
|
||||
{
|
||||
id: 'block_end_0',
|
||||
type: 'block-end',
|
||||
data: { title: 'End' },
|
||||
meta: { position: { x: 360, y: 0 } },
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{ sourceNodeID: 'block_start_0', targetNodeID: 'variable_0' },
|
||||
{ sourceNodeID: 'variable_0', targetNodeID: 'block_end_0' },
|
||||
],
|
||||
},
|
||||
],
|
||||
edges: [{ sourceNodeID: 'start_0', targetNodeID: 'custom_0' }],
|
||||
}}
|
||||
transformRegistry={(props) => ({
|
||||
...props,
|
||||
nodeRegistries: [
|
||||
...(props.nodeRegistries || []).filter((r) => r.type !== 'custom'),
|
||||
createLoopRegistry(),
|
||||
],
|
||||
})}
|
||||
plugins={(ctx) => [createContainerNodePlugin({})]}
|
||||
/>
|
||||
);
|
||||
|
||||
export const WithInferSchemaStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
height={550}
|
||||
initialData={{
|
||||
nodes: [
|
||||
{
|
||||
id: 'custom_0',
|
||||
type: 'custom',
|
||||
data: {
|
||||
title: 'Loop',
|
||||
loopFor: { type: 'ref', content: ['start_0', 'arr', 'arr_obj'] },
|
||||
},
|
||||
blocks: [
|
||||
{
|
||||
id: 'block_start_0',
|
||||
type: 'block-start',
|
||||
data: { title: 'Start' },
|
||||
meta: { position: { x: 20, y: 0 } },
|
||||
},
|
||||
{
|
||||
id: 'variable_0',
|
||||
type: 'variable',
|
||||
data: {
|
||||
title: 'Variable',
|
||||
assign: [
|
||||
{
|
||||
operator: 'declare',
|
||||
left: 'item_name',
|
||||
right: { type: 'ref', content: ['custom_0_locals', 'item', 'str'] },
|
||||
},
|
||||
{
|
||||
operator: 'declare',
|
||||
left: 'item_index',
|
||||
right: { type: 'ref', content: ['custom_0_locals', 'index'] },
|
||||
},
|
||||
],
|
||||
},
|
||||
meta: { position: { x: 100, y: 0 } },
|
||||
},
|
||||
{
|
||||
id: 'block_end_0',
|
||||
type: 'block-end',
|
||||
data: { title: 'End' },
|
||||
meta: { position: { x: 360, y: 0 } },
|
||||
},
|
||||
],
|
||||
edges: [
|
||||
{ sourceNodeID: 'block_start_0', targetNodeID: 'variable_0' },
|
||||
{ sourceNodeID: 'variable_0', targetNodeID: 'block_end_0' },
|
||||
],
|
||||
},
|
||||
],
|
||||
edges: [{ sourceNodeID: 'start_0', targetNodeID: 'custom_0' }],
|
||||
}}
|
||||
transformRegistry={(props) => ({
|
||||
...props,
|
||||
nodeRegistries: [
|
||||
...(props.nodeRegistries || []).filter((r) => r.type !== 'custom'),
|
||||
createLoopRegistryWithInfer(),
|
||||
],
|
||||
})}
|
||||
plugins={(ctx) => [createContainerNodePlugin({})]}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,90 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { createInferAssignPlugin } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const AssignRows = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.AssignRows,
|
||||
}))
|
||||
);
|
||||
|
||||
const DisplayOutputs = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DisplayOutputs,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
transformInitialNode={{
|
||||
end_0: (node) => {
|
||||
node.data.inputsValues = {
|
||||
info: {
|
||||
type: 'ref',
|
||||
content: ['custom_0', 'userInfo'],
|
||||
},
|
||||
};
|
||||
|
||||
return node;
|
||||
},
|
||||
}}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<AssignRows
|
||||
name="assign"
|
||||
defaultValue={[
|
||||
// 从常量声明变量
|
||||
{
|
||||
operator: 'declare',
|
||||
left: 'userName',
|
||||
right: {
|
||||
type: 'constant',
|
||||
content: 'John Doe',
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
},
|
||||
// 从变量声明变量
|
||||
{
|
||||
operator: 'declare',
|
||||
left: 'userInfo',
|
||||
right: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'obj'],
|
||||
},
|
||||
},
|
||||
// 赋值现有变量
|
||||
{
|
||||
operator: 'assign',
|
||||
left: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'str'],
|
||||
},
|
||||
right: {
|
||||
type: 'constant',
|
||||
content: 'Hello Flowgram',
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<DisplayOutputs displayFromScope style={{ marginTop: 10 }} />
|
||||
</>
|
||||
),
|
||||
plugins: [
|
||||
createInferAssignPlugin({
|
||||
assignKey: 'assign',
|
||||
outputKey: 'outputs',
|
||||
}),
|
||||
],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,104 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import { createInferInputsPlugin } from '@flowgram.ai/form-materials';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const InputsValues = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.InputsValues,
|
||||
}))
|
||||
);
|
||||
|
||||
const InputsValuesTree = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.InputsValuesTree,
|
||||
}))
|
||||
);
|
||||
|
||||
/**
|
||||
* Basic usage story - demonstrates automatic schema inference from InputsValues
|
||||
*/
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
height={500}
|
||||
formMeta={{
|
||||
render: () => (
|
||||
<>
|
||||
<FormHeader />
|
||||
<div>
|
||||
<div>
|
||||
<h4>Headers</h4>
|
||||
<Field<Record<string, any> | undefined>
|
||||
name="headersValues"
|
||||
defaultValue={{
|
||||
'Content-Type': {
|
||||
type: 'constant',
|
||||
content: 'application/json',
|
||||
schema: { type: 'string' },
|
||||
},
|
||||
Authorization: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'str'],
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<InputsValues value={field.value} onChange={(value) => field.onChange(value)} />
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h4>Body</h4>
|
||||
<Field<Record<string, any> | undefined>
|
||||
name="bodyValues"
|
||||
defaultValue={{
|
||||
page: {
|
||||
index: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'obj', 'obj2', 'num'],
|
||||
},
|
||||
size: {
|
||||
type: 'constant',
|
||||
content: 10,
|
||||
schema: { type: 'number' },
|
||||
},
|
||||
},
|
||||
query: {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'obj'],
|
||||
},
|
||||
}}
|
||||
>
|
||||
{({ field }) => (
|
||||
<InputsValuesTree
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
),
|
||||
plugins: [
|
||||
createInferInputsPlugin({
|
||||
sourceKey: 'headersValues',
|
||||
targetKey: 'headersSchema',
|
||||
}),
|
||||
createInferInputsPlugin({
|
||||
sourceKey: 'bodyValues',
|
||||
targetKey: 'bodySchema',
|
||||
}),
|
||||
],
|
||||
}}
|
||||
/>
|
||||
);
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Copyright (c) 2025 Bytedance Ltd. and/or its affiliates
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { Field } from '@flowgram.ai/free-layout-editor';
|
||||
import { validateFlowValue } from '@flowgram.ai/form-materials';
|
||||
import { Button } from '@douyinfe/semi-ui';
|
||||
|
||||
import { FreeFormMetaStoryBuilder, FormHeader } from '../../free-form-meta-story-builder';
|
||||
|
||||
const DynamicValueInput = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.DynamicValueInput,
|
||||
}))
|
||||
);
|
||||
|
||||
const PromptEditorWithVariables = React.lazy(() =>
|
||||
import('@flowgram.ai/form-materials').then((module) => ({
|
||||
default: module.PromptEditorWithVariables,
|
||||
}))
|
||||
);
|
||||
|
||||
export const BasicStory = () => (
|
||||
<FreeFormMetaStoryBuilder
|
||||
filterEndNode
|
||||
transformInitialNode={{
|
||||
custom_0: (node) => {
|
||||
node.data.dynamic_value_input = {
|
||||
type: 'ref',
|
||||
content: ['start_0', 'unknown_key'],
|
||||
};
|
||||
node.data.required_dynamic_value_input = {
|
||||
type: 'constant',
|
||||
content: '',
|
||||
};
|
||||
node.data.prompt_editor = {
|
||||
type: 'template',
|
||||
content: 'Hello {{start_0.unknown_key}}',
|
||||
};
|
||||
return node;
|
||||
},
|
||||
}}
|
||||
formMeta={{
|
||||
validate: {
|
||||
dynamic_value_input: ({ value, context }) =>
|
||||
validateFlowValue(value, {
|
||||
node: context.node,
|
||||
errorMessages: {
|
||||
required: 'Value is required',
|
||||
unknownVariable: 'Unknown Variable',
|
||||
},
|
||||
}),
|
||||
|
||||
required_dynamic_value_input: ({ value, context }) =>
|
||||
validateFlowValue(value, {
|
||||
node: context.node,
|
||||
required: true,
|
||||
errorMessages: {
|
||||
required: 'Value is required',
|
||||
unknownVariable: 'Unknown Variable',
|
||||
},
|
||||
}),
|
||||
|
||||
prompt_editor: ({ value, context }) =>
|
||||
validateFlowValue(value, {
|
||||
node: context.node,
|
||||
required: true,
|
||||
errorMessages: {
|
||||
required: 'Prompt is required',
|
||||
unknownVariable: 'Unknown Variable In Template',
|
||||
},
|
||||
}),
|
||||
},
|
||||
render: ({ form }) => (
|
||||
<>
|
||||
<FormHeader />
|
||||
|
||||
<b>Validate variable valid</b>
|
||||
<Field<any> name="dynamic_value_input">
|
||||
{({ field, fieldState }) => (
|
||||
<>
|
||||
<DynamicValueInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
<span style={{ color: 'red' }}>
|
||||
{fieldState.errors?.map((e) => e.message).join('\n')}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
|
||||
<b>Validate required value</b>
|
||||
<Field<any> name="required_dynamic_value_input">
|
||||
{({ field, fieldState }) => (
|
||||
<>
|
||||
<DynamicValueInput
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
<span style={{ color: 'red' }}>
|
||||
{fieldState.errors?.map((e) => e.message).join('\n')}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
<br />
|
||||
|
||||
<b>Validate required and variables valid in prompt</b>
|
||||
<Field<any> name="prompt_editor">
|
||||
{({ field, fieldState }) => (
|
||||
<>
|
||||
<PromptEditorWithVariables
|
||||
value={field.value}
|
||||
onChange={(value) => field.onChange(value)}
|
||||
/>
|
||||
<span style={{ color: 'red' }}>
|
||||
{fieldState.errors?.map((e) => e.message).join('\n')}
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</Field>
|
||||
|
||||
<br />
|
||||
|
||||
<Button onClick={() => form.validate()}>Trigger Validate</Button>
|
||||
</>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
);
|
||||
Reference in New Issue
Block a user