|
@@ -1,4 +1,8 @@
|
|
|
-# Outputting Variables
|
|
|
|
|
|
|
+---
|
|
|
|
|
+description: Learn how to use the variable engine to output variables in FlowGram
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+# Output Variables
|
|
|
|
|
|
|
|
We mainly divide output variables into three categories:
|
|
We mainly divide output variables into three categories:
|
|
|
|
|
|
|
@@ -14,15 +18,15 @@ We usually have three ways to output node variables:
|
|
|
|
|
|
|
|
### Method 1: Sync via Form Side Effects
|
|
### Method 1: Sync via Form Side Effects
|
|
|
|
|
|
|
|
-[Form Side Effects](/guide/form/form#副作用-effect) are usually configured in the node's `form-meta.ts` file and are the most common way to define node output variables.
|
|
|
|
|
|
|
+[Form Side Effects](/guide/form/form#side-effects-effect) are usually configured in the node's `form-meta.ts` file and are the most common way to define node output variables.
|
|
|
|
|
|
|
|
#### `provideJsonSchemaOutputs` Material
|
|
#### `provideJsonSchemaOutputs` Material
|
|
|
|
|
|
|
|
If the structure of the output variable required by the node matches the [JSON Schema](https://json-schema.org/) structure, you can use the `provideJsonSchemaOutputs` side effect (Effect) material.
|
|
If the structure of the output variable required by the node matches the [JSON Schema](https://json-schema.org/) structure, you can use the `provideJsonSchemaOutputs` side effect (Effect) material.
|
|
|
|
|
|
|
|
-It is very simple to use, just add two lines of configuration in the `effect` of `formMeta`:
|
|
|
|
|
|
|
+Just add two lines of configuration in the `effect` of `formMeta`:
|
|
|
|
|
|
|
|
-```tsx pure title="form-meta.ts"
|
|
|
|
|
|
|
+```tsx pure title="form-meta.ts" {8-9}
|
|
|
import {
|
|
import {
|
|
|
syncVariableTitle,
|
|
syncVariableTitle,
|
|
|
provideJsonSchemaOutputs,
|
|
provideJsonSchemaOutputs,
|
|
@@ -36,22 +40,23 @@ export const formMeta = {
|
|
|
};
|
|
};
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-#### Via `createEffectFromVariableProvider`
|
|
|
|
|
|
|
+#### Customizing Output with `createEffectFromVariableProvider`
|
|
|
|
|
+
|
|
|
|
|
|
|
|
`provideJsonSchemaOutputs` only adapts to `JsonSchema`. If you want to define your own set of Schema, then you need to customize the side effects of the form.
|
|
`provideJsonSchemaOutputs` only adapts to `JsonSchema`. If you want to define your own set of Schema, then you need to customize the side effects of the form.
|
|
|
|
|
|
|
|
:::note
|
|
:::note
|
|
|
|
|
|
|
|
-Flowgram provides `createEffectFromVariableProvider`, you only need to define a `parse` function to customize your own variable synchronization side effects:
|
|
|
|
|
|
|
+FlowGram provides `createEffectFromVariableProvider`, you only need to define a `parse` function to customize your own variable synchronization side effects:
|
|
|
- `parse` will be called when the form value is initialized and updated
|
|
- `parse` will be called when the form value is initialized and updated
|
|
|
- The input of `parse` is the value of the current field's form
|
|
- The input of `parse` is the value of the current field's form
|
|
|
- The output of `parse` is the variable AST information
|
|
- The output of `parse` is the variable AST information
|
|
|
|
|
|
|
|
:::
|
|
:::
|
|
|
|
|
|
|
|
-In the following example, we create output variables for the two fields of the form `path.to.value` and `path.to.value2`:
|
|
|
|
|
|
|
+In the following example, we create output variables for the two fields of the form `path.to.value` and `path.to.value2` respectively:
|
|
|
|
|
|
|
|
-```tsx pure title="form-meta.ts"
|
|
|
|
|
|
|
+```tsx pure title="form-meta.ts" {27-38,41-52}
|
|
|
import {
|
|
import {
|
|
|
createEffectFromVariableProvider,
|
|
createEffectFromVariableProvider,
|
|
|
ASTFactory,
|
|
ASTFactory,
|
|
@@ -81,13 +86,13 @@ export const formMeta = {
|
|
|
'path.to.value': createEffectFromVariableProvider({
|
|
'path.to.value': createEffectFromVariableProvider({
|
|
|
// parse form value to variable
|
|
// parse form value to variable
|
|
|
parse(v: string) {
|
|
parse(v: string) {
|
|
|
- return {
|
|
|
|
|
|
|
+ return [{
|
|
|
meta: {
|
|
meta: {
|
|
|
title: `Your Output Variable Title`,
|
|
title: `Your Output Variable Title`,
|
|
|
},
|
|
},
|
|
|
key: `uid_${node.id}`,
|
|
key: `uid_${node.id}`,
|
|
|
type: createTypeFromValue(v)
|
|
type: createTypeFromValue(v)
|
|
|
- }
|
|
|
|
|
|
|
+ }]
|
|
|
}
|
|
}
|
|
|
}),
|
|
}),
|
|
|
// Create second variable
|
|
// Create second variable
|
|
@@ -95,13 +100,13 @@ export const formMeta = {
|
|
|
'path.to.value2': createEffectFromVariableProvider({
|
|
'path.to.value2': createEffectFromVariableProvider({
|
|
|
// parse form value to variable
|
|
// parse form value to variable
|
|
|
parse(v: string) {
|
|
parse(v: string) {
|
|
|
- return {
|
|
|
|
|
|
|
+ return [{
|
|
|
meta: {
|
|
meta: {
|
|
|
title: `Your Output Variable Title 2`,
|
|
title: `Your Output Variable Title 2`,
|
|
|
},
|
|
},
|
|
|
key: `uid_${node.id}_2`,
|
|
key: `uid_${node.id}_2`,
|
|
|
type: createTypeFromValue(v)
|
|
type: createTypeFromValue(v)
|
|
|
- }
|
|
|
|
|
|
|
+ }]
|
|
|
}
|
|
}
|
|
|
}),
|
|
}),
|
|
|
},
|
|
},
|
|
@@ -115,7 +120,8 @@ export const formMeta = {
|
|
|
|
|
|
|
|
If multiple fields are synchronized to one variable, you need to use the `namespace` field of `createEffectFromVariableProvider` to synchronize the variable data of multiple fields to the same namespace.
|
|
If multiple fields are synchronized to one variable, you need to use the `namespace` field of `createEffectFromVariableProvider` to synchronize the variable data of multiple fields to the same namespace.
|
|
|
|
|
|
|
|
-```tsx pure title="form-meta.ts"
|
|
|
|
|
|
|
+
|
|
|
|
|
+```tsx pure title="form-meta.ts" {11}
|
|
|
import {
|
|
import {
|
|
|
createEffectFromVariableProvider,
|
|
createEffectFromVariableProvider,
|
|
|
ASTFactory,
|
|
ASTFactory,
|
|
@@ -130,16 +136,13 @@ const variableSyncEffect = createEffectFromVariableProvider({
|
|
|
|
|
|
|
|
// Parse the form value into a variable
|
|
// Parse the form value into a variable
|
|
|
parse(_, { form, node }) {
|
|
parse(_, { form, node }) {
|
|
|
- return {
|
|
|
|
|
|
|
+ return [{
|
|
|
meta: {
|
|
meta: {
|
|
|
- title: `Your Output Variable Title`,
|
|
|
|
|
|
|
+ title: `Title_${form.getValueIn('path.to.value')}_${form.getValueIn('path.to.value2')}`,
|
|
|
},
|
|
},
|
|
|
key: `uid_${node.id}`,
|
|
key: `uid_${node.id}`,
|
|
|
- type: createTypeFromValue({
|
|
|
|
|
- value1: form.getValueIn('path.to.value'),
|
|
|
|
|
- value2: form.getValueIn('path.to.value2'),
|
|
|
|
|
- })
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ type: ASTFactory.createCustomType({ typeName: "CustomVariableType" })
|
|
|
|
|
+ }]
|
|
|
}
|
|
}
|
|
|
})
|
|
})
|
|
|
|
|
|
|
@@ -172,7 +175,7 @@ If `createEffectFromVariableProvider` does not meet your needs, you can also dir
|
|
|
:::
|
|
:::
|
|
|
|
|
|
|
|
|
|
|
|
|
-```tsx pure title="form-meta.tsx"
|
|
|
|
|
|
|
+```tsx pure title="form-meta.tsx" {10-18,29-38}
|
|
|
import { Effect } from '@flowgram.ai/editor';
|
|
import { Effect } from '@flowgram.ai/editor';
|
|
|
|
|
|
|
|
export const formMeta = {
|
|
export const formMeta = {
|
|
@@ -185,10 +188,10 @@ export const formMeta = {
|
|
|
context.node.scope.setVar(
|
|
context.node.scope.setVar(
|
|
|
ASTFactory.createVariableDeclaration({
|
|
ASTFactory.createVariableDeclaration({
|
|
|
meta: {
|
|
meta: {
|
|
|
- title: `Your Output Variable Title`,
|
|
|
|
|
|
|
+ title: `Title_${value}`,
|
|
|
},
|
|
},
|
|
|
key: `uid_${node.id}`,
|
|
key: `uid_${node.id}`,
|
|
|
- type: createTypeFromValue(value),
|
|
|
|
|
|
|
+ type: ASTFactory.createString(),
|
|
|
})
|
|
})
|
|
|
)
|
|
)
|
|
|
|
|
|
|
@@ -205,10 +208,10 @@ export const formMeta = {
|
|
|
'namespace_2',
|
|
'namespace_2',
|
|
|
ASTFactory.createVariableDeclaration({
|
|
ASTFactory.createVariableDeclaration({
|
|
|
meta: {
|
|
meta: {
|
|
|
- title: `Your Output Variable Title 2`,
|
|
|
|
|
|
|
+ title: `Title_${value}`,
|
|
|
},
|
|
},
|
|
|
key: `uid_${node.id}_2`,
|
|
key: `uid_${node.id}_2`,
|
|
|
- type: createTypeFromValue(value),
|
|
|
|
|
|
|
+ type: ASTFactory.createNumber(),
|
|
|
})
|
|
})
|
|
|
)
|
|
)
|
|
|
|
|
|
|
@@ -233,7 +236,7 @@ In addition to static configuration in the form, we can also freely and dynamica
|
|
|
|
|
|
|
|
The following example demonstrates how to get the `Scope` of the start node in the `onInit` life cycle of the plugin and perform a series of operations on its variables.
|
|
The following example demonstrates how to get the `Scope` of the start node in the `onInit` life cycle of the plugin and perform a series of operations on its variables.
|
|
|
|
|
|
|
|
-```tsx pure title="sync-variable-plugin.tsx"
|
|
|
|
|
|
|
+```tsx pure title="sync-variable-plugin.tsx" {10-22}
|
|
|
import {
|
|
import {
|
|
|
FlowDocument,
|
|
FlowDocument,
|
|
|
definePluginCreator,
|
|
definePluginCreator,
|
|
@@ -264,7 +267,7 @@ export const createSyncVariablePlugin: PluginCreator<SyncVariablePluginOptions>
|
|
|
|
|
|
|
|
The following example demonstrates how to get the Scope of a newly created node through `onNodeCreate` and synchronize variables by listening to `node.form.onFormValuesChange`.
|
|
The following example demonstrates how to get the Scope of a newly created node through `onNodeCreate` and synchronize variables by listening to `node.form.onFormValuesChange`.
|
|
|
|
|
|
|
|
-```tsx pure title="sync-variable-plugin.tsx"
|
|
|
|
|
|
|
+```tsx pure title="sync-variable-plugin.tsx" {10,29}
|
|
|
import {
|
|
import {
|
|
|
FlowDocument,
|
|
FlowDocument,
|
|
|
definePluginCreator,
|
|
definePluginCreator,
|
|
@@ -318,7 +321,9 @@ It breaks the principle of **separation of data and rendering**, leading to tigh
|
|
|
|
|
|
|
|
:::
|
|
:::
|
|
|
|
|
|
|
|
-```tsx pure title="form-meta.ts"
|
|
|
|
|
|
|
+The following example demonstrates how to synchronize and update variables through the `useCurrentScope` event in `formMeta.render`.
|
|
|
|
|
+
|
|
|
|
|
+```tsx pure title="form-meta.ts" {13}
|
|
|
import {
|
|
import {
|
|
|
createEffectFromVariableProvider,
|
|
createEffectFromVariableProvider,
|
|
|
ASTFactory,
|
|
ASTFactory,
|
|
@@ -355,28 +360,14 @@ export const formMeta = {
|
|
|
}
|
|
}
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-## Outputting Node Private Variables
|
|
|
|
|
|
|
|
|
|
-Private variables are variables that can only be accessed within the current node and its child nodes.
|
|
|
|
|
|
|
|
|
|
-Private variables can be set and obtained through the private scope `node.privateScope`. Its scope chain relationship is shown in the following figure:
|
|
|
|
|
|
|
|
|
|
-```mermaid
|
|
|
|
|
-graph BT
|
|
|
|
|
- subgraph Current_Node
|
|
|
|
|
- Child_Node_1.scope -.depends on.-> Current_Node.privateScope
|
|
|
|
|
- Current_Node.scope -.depends on.-> Current_Node.privateScope
|
|
|
|
|
- Child_Node_2.scope -.depends on.-> Current_Node.privateScope
|
|
|
|
|
- end
|
|
|
|
|
|
|
|
|
|
- Current_Node -.all depend on.-> Upstream_Node.scope
|
|
|
|
|
- Downstream_Node.scope -.depends on.-> Current_Node.scope
|
|
|
|
|
- Downstream_Node.scope -.depends on.-> Upstream_Node.scope
|
|
|
|
|
|
|
|
|
|
|
|
+## Outputting Node Private Variables
|
|
|
|
|
|
|
|
- style Current_Node.privateScope fill:#f9f,stroke:#333,stroke-width:3px
|
|
|
|
|
- style Current_Node.scope stroke:#333,stroke-width:3px
|
|
|
|
|
-```
|
|
|
|
|
|
|
+Private variables are variables that can only be accessed within the current node and its child nodes. (See also: [Node Private Scope](./concept#node-private-scope))
|
|
|
|
|
|
|
|
Only two of the methods are listed below, and other methods can be deduced from the [Output Node Variables](#outputting-node-variables) method.
|
|
Only two of the methods are listed below, and other methods can be deduced from the [Output Node Variables](#outputting-node-variables) method.
|
|
|
|
|
|
|
@@ -386,7 +377,7 @@ Only two of the methods are listed below, and other methods can be deduced from
|
|
|
- When `scope` is set to `private`, the scope of the variable is the private scope of the current node `node.privateScope`
|
|
- When `scope` is set to `private`, the scope of the variable is the private scope of the current node `node.privateScope`
|
|
|
- When `scope` is set to `public`, the scope of the variable is the scope of the current node `node.scope`
|
|
- When `scope` is set to `public`, the scope of the variable is the scope of the current node `node.scope`
|
|
|
|
|
|
|
|
-```tsx pure title="form-meta.ts"
|
|
|
|
|
|
|
+```tsx pure title="form-meta.ts" {11}
|
|
|
import {
|
|
import {
|
|
|
createEffectFromVariableProvider,
|
|
createEffectFromVariableProvider,
|
|
|
ASTFactory,
|
|
ASTFactory,
|
|
@@ -400,13 +391,13 @@ export const formMeta = {
|
|
|
scope: 'private',
|
|
scope: 'private',
|
|
|
// parse form value to variable
|
|
// parse form value to variable
|
|
|
parse(v: string) {
|
|
parse(v: string) {
|
|
|
- return {
|
|
|
|
|
|
|
+ return [{
|
|
|
meta: {
|
|
meta: {
|
|
|
- title: `Your Private Variable Title`,
|
|
|
|
|
|
|
+ title: `Private_${v}`,
|
|
|
},
|
|
},
|
|
|
key: `uid_${node.id}_locals`,
|
|
key: `uid_${node.id}_locals`,
|
|
|
- type: createTypeFromValue(v)
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ type: ASTFactory.createBoolean(),
|
|
|
|
|
+ }]
|
|
|
}
|
|
}
|
|
|
}),
|
|
}),
|
|
|
},
|
|
},
|
|
@@ -423,7 +414,7 @@ export const formMeta = {
|
|
|
The API of `node.privateScope` is designed to be almost identical to the node scope (`node.scope`), providing methods such as `setVar`, `getVar`, `clearVar`, and also supporting namespaces. For details, please refer to [`node.scope`](#using-the-nodescope-api-in-side-effects).
|
|
The API of `node.privateScope` is designed to be almost identical to the node scope (`node.scope`), providing methods such as `setVar`, `getVar`, `clearVar`, and also supporting namespaces. For details, please refer to [`node.scope`](#using-the-nodescope-api-in-side-effects).
|
|
|
|
|
|
|
|
|
|
|
|
|
-```tsx pure title="form-meta.tsx"
|
|
|
|
|
|
|
+```tsx pure title="form-meta.tsx" {10-18}
|
|
|
import { Effect } from '@flowgram.ai/editor';
|
|
import { Effect } from '@flowgram.ai/editor';
|
|
|
|
|
|
|
|
export const formMeta = {
|
|
export const formMeta = {
|
|
@@ -439,7 +430,7 @@ export const formMeta = {
|
|
|
title: `Your Private Variable Title`,
|
|
title: `Your Private Variable Title`,
|
|
|
},
|
|
},
|
|
|
key: `uid_${node.id}`,
|
|
key: `uid_${node.id}`,
|
|
|
- type: createTypeFromValue(value),
|
|
|
|
|
|
|
+ type: ASTFactory.createInteger(),
|
|
|
})
|
|
})
|
|
|
)
|
|
)
|
|
|
|
|
|
|
@@ -468,14 +459,13 @@ Similar to node variables, we also have two main ways to obtain the scope of glo
|
|
|
In the context of the plugin (`ctx`), we can directly "inject" the instance of `GlobalScope`:
|
|
In the context of the plugin (`ctx`), we can directly "inject" the instance of `GlobalScope`:
|
|
|
|
|
|
|
|
|
|
|
|
|
-```tsx pure title="global-variable-plugin.tsx"
|
|
|
|
|
|
|
+```tsx pure title="global-variable-plugin.tsx" {10-20}
|
|
|
import {
|
|
import {
|
|
|
GlobalScope,
|
|
GlobalScope,
|
|
|
definePluginCreator,
|
|
definePluginCreator,
|
|
|
PluginCreator
|
|
PluginCreator
|
|
|
} from '@flowgram.ai/fixed-layout-editor';
|
|
} from '@flowgram.ai/fixed-layout-editor';
|
|
|
|
|
|
|
|
-
|
|
|
|
|
export const createGlobalVariablePlugin: PluginCreator<SyncVariablePluginOptions> =
|
|
export const createGlobalVariablePlugin: PluginCreator<SyncVariablePluginOptions> =
|
|
|
definePluginCreator<SyncVariablePluginOptions, FixedLayoutPluginContext>({
|
|
definePluginCreator<SyncVariablePluginOptions, FixedLayoutPluginContext>({
|
|
|
onInit(ctx, options) {
|
|
onInit(ctx, options) {
|
|
@@ -500,14 +490,13 @@ export const createGlobalVariablePlugin: PluginCreator<SyncVariablePluginOptions
|
|
|
|
|
|
|
|
If you want to interact with global variables in the React component of the canvas, you can use the `useService` Hook to get the instance of `GlobalScope`:
|
|
If you want to interact with global variables in the React component of the canvas, you can use the `useService` Hook to get the instance of `GlobalScope`:
|
|
|
|
|
|
|
|
-```tsx pure title="global-variable-component.tsx"
|
|
|
|
|
|
|
+```tsx pure title="global-variable-component.tsx" {7}
|
|
|
import {
|
|
import {
|
|
|
GlobalScope,
|
|
GlobalScope,
|
|
|
useService,
|
|
useService,
|
|
|
} from '@flowgram.ai/fixed-layout-editor';
|
|
} from '@flowgram.ai/fixed-layout-editor';
|
|
|
|
|
|
|
|
function GlobalVariableComponent() {
|
|
function GlobalVariableComponent() {
|
|
|
-
|
|
|
|
|
const globalScope = useService(GlobalScope)
|
|
const globalScope = useService(GlobalScope)
|
|
|
|
|
|
|
|
// ...
|
|
// ...
|
|
@@ -537,7 +526,7 @@ The API of `GlobalScope` is designed to be almost identical to the node scope (`
|
|
|
|
|
|
|
|
Here is a comprehensive example of operating global variables in a plugin:
|
|
Here is a comprehensive example of operating global variables in a plugin:
|
|
|
|
|
|
|
|
-```tsx pure title="sync-variable-plugin.tsx"
|
|
|
|
|
|
|
+```tsx pure title="sync-variable-plugin.tsx" {11-39}
|
|
|
import {
|
|
import {
|
|
|
GlobalScope,
|
|
GlobalScope,
|
|
|
} from '@flowgram.ai/fixed-layout-editor';
|
|
} from '@flowgram.ai/fixed-layout-editor';
|
|
@@ -562,7 +551,6 @@ onInit(ctx, options) {
|
|
|
|
|
|
|
|
globalScope.clearVar()
|
|
globalScope.clearVar()
|
|
|
|
|
|
|
|
-
|
|
|
|
|
// 2. Create, Update, Read, Delete Variable in GlobalScope's namespace: 'namespace_1'
|
|
// 2. Create, Update, Read, Delete Variable in GlobalScope's namespace: 'namespace_1'
|
|
|
globalScope.setVar(
|
|
globalScope.setVar(
|
|
|
'namespace_1',
|
|
'namespace_1',
|