mirror of
https://gitee.com/ByteDance/flowgram.ai.git
synced 2025-07-07 17:43:29 +08:00
feat(variable): global variable + variable panel plugin in demo (#435)
* feat: global variable panel * feat(variable): on any change to on list or any var change * feat: fix layout add variable panel
This commit is contained in:
parent
94bdba02d1
commit
7c6c7ab7a2
@ -46,6 +46,7 @@
|
|||||||
"@flowgram.ai/eslint-config": "workspace:*",
|
"@flowgram.ai/eslint-config": "workspace:*",
|
||||||
"@rsbuild/core": "^1.2.16",
|
"@rsbuild/core": "^1.2.16",
|
||||||
"@rsbuild/plugin-react": "^1.1.1",
|
"@rsbuild/plugin-react": "^1.1.1",
|
||||||
|
"@rsbuild/plugin-less": "^1.1.1",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^18",
|
"@types/node": "^18",
|
||||||
"@types/react": "^18",
|
"@types/react": "^18",
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { pluginReact } from '@rsbuild/plugin-react';
|
import { pluginReact } from '@rsbuild/plugin-react';
|
||||||
|
import { pluginLess } from '@rsbuild/plugin-less';
|
||||||
import { defineConfig } from '@rsbuild/core';
|
import { defineConfig } from '@rsbuild/core';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [pluginReact()],
|
plugins: [pluginReact(), pluginLess()],
|
||||||
source: {
|
source: {
|
||||||
entry: {
|
entry: {
|
||||||
index: './src/app.tsx',
|
index: './src/app.tsx',
|
||||||
|
|||||||
BIN
apps/demo-fixed-layout/src/assets/icon-variable.png
Normal file
BIN
apps/demo-fixed-layout/src/assets/icon-variable.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
@ -17,7 +17,7 @@ import { type FlowNodeRegistry } from '../typings';
|
|||||||
import { shortcutGetter } from '../shortcuts';
|
import { shortcutGetter } from '../shortcuts';
|
||||||
import { CustomService } from '../services';
|
import { CustomService } from '../services';
|
||||||
import { GroupBoxHeader, GroupNode } from '../plugins/group-plugin';
|
import { GroupBoxHeader, GroupNode } from '../plugins/group-plugin';
|
||||||
import { createClipboardPlugin } from '../plugins';
|
import { createClipboardPlugin, createVariablePanelPlugin } from '../plugins';
|
||||||
import { SelectorBoxPopover } from '../components/selector-box-popover';
|
import { SelectorBoxPopover } from '../components/selector-box-popover';
|
||||||
import NodeAdder from '../components/node-adder';
|
import NodeAdder from '../components/node-adder';
|
||||||
import BranchAdder from '../components/branch-adder';
|
import BranchAdder from '../components/branch-adder';
|
||||||
@ -260,6 +260,12 @@ export function useEditorProps(
|
|||||||
* 剪切板插件
|
* 剪切板插件
|
||||||
*/
|
*/
|
||||||
createClipboardPlugin(),
|
createClipboardPlugin(),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable panel plugin
|
||||||
|
* 变量面板插件
|
||||||
|
*/
|
||||||
|
createVariablePanelPlugin({}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
|
|||||||
@ -1 +1,2 @@
|
|||||||
export { createClipboardPlugin } from './clipboard-plugin/create-clipboard-plugin';
|
export { createClipboardPlugin } from './clipboard-plugin/create-clipboard-plugin';
|
||||||
|
export { createVariablePanelPlugin } from './variable-panel-plugin';
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
import { useVariableTree } from '@flowgram.ai/form-materials';
|
||||||
|
import { Tree } from '@douyinfe/semi-ui';
|
||||||
|
|
||||||
|
export function FullVariableList() {
|
||||||
|
const treeData = useVariableTree({});
|
||||||
|
|
||||||
|
return <Tree treeData={treeData} />;
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import { JsonSchemaEditor, JsonSchemaUtils } from '@flowgram.ai/form-materials';
|
||||||
|
import {
|
||||||
|
BaseVariableField,
|
||||||
|
GlobalScope,
|
||||||
|
useRefresh,
|
||||||
|
useService,
|
||||||
|
} from '@flowgram.ai/fixed-layout-editor';
|
||||||
|
|
||||||
|
export function GlobalVariableEditor() {
|
||||||
|
const globalScope = useService(GlobalScope);
|
||||||
|
|
||||||
|
const refresh = useRefresh();
|
||||||
|
|
||||||
|
const globalVar = globalScope.getVar() as BaseVariableField;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const disposable = globalScope.output.onVariableListChange(() => {
|
||||||
|
refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposable.dispose();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!globalVar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = globalVar.type ? JsonSchemaUtils.astToSchema(globalVar.type) : { type: 'object' };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<JsonSchemaEditor
|
||||||
|
value={value}
|
||||||
|
onChange={(_schema) => globalVar.updateType(JsonSchemaUtils.schemaToAST(_schema))}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
.panel-wrapper {
|
||||||
|
position: relative;
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-panel-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
&.close {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-container {
|
||||||
|
width: 500px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #fff;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 4px 4px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
z-index: 30;
|
||||||
|
|
||||||
|
:global(.semi-tabs-bar) {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.semi-tabs-content) {
|
||||||
|
padding: 20px;
|
||||||
|
height: 500px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
import { Button, Collapsible, Tabs, Tooltip } from '@douyinfe/semi-ui';
|
||||||
|
import { IconMinus } from '@douyinfe/semi-icons';
|
||||||
|
|
||||||
|
import iconVariable from '../../../assets/icon-variable.png';
|
||||||
|
import { GlobalVariableEditor } from './global-variable-editor';
|
||||||
|
import { FullVariableList } from './full-variable-list';
|
||||||
|
|
||||||
|
import styles from './index.module.less';
|
||||||
|
|
||||||
|
export function VariablePanel() {
|
||||||
|
const [isOpen, setOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles['panel-wrapper']}>
|
||||||
|
<Tooltip content="Toggle Variable Panel">
|
||||||
|
<Button
|
||||||
|
className={`${styles['variable-panel-button']} ${isOpen ? styles.close : ''}`}
|
||||||
|
theme={isOpen ? 'borderless' : 'light'}
|
||||||
|
onClick={() => setOpen((_open) => !_open)}
|
||||||
|
>
|
||||||
|
{isOpen ? <IconMinus /> : <img src={iconVariable} width={20} height={20} />}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Collapsible isOpen={isOpen}>
|
||||||
|
<div className={styles['panel-container']}>
|
||||||
|
<Tabs>
|
||||||
|
<Tabs.TabPane itemKey="variables" tab="Variable List">
|
||||||
|
<FullVariableList />
|
||||||
|
</Tabs.TabPane>
|
||||||
|
<Tabs.TabPane itemKey="global" tab="Global Editor">
|
||||||
|
<GlobalVariableEditor />
|
||||||
|
</Tabs.TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
</Collapsible>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export { createVariablePanelPlugin } from './variable-panel-plugin';
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { domUtils, injectable, Layer } from '@flowgram.ai/fixed-layout-editor';
|
||||||
|
|
||||||
|
import { VariablePanel } from './components/variable-panel';
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class VariablePanelLayer extends Layer {
|
||||||
|
onReady(): void {
|
||||||
|
// Fix variable panel in the right of canvas
|
||||||
|
this.config.onDataChange(() => {
|
||||||
|
const { scrollX, scrollY } = this.config.config;
|
||||||
|
domUtils.setStyle(this.node, {
|
||||||
|
position: 'absolute',
|
||||||
|
right: 25 - scrollX,
|
||||||
|
top: scrollY + 25,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): JSX.Element {
|
||||||
|
return <VariablePanel />;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
import { JsonSchemaUtils } from '@flowgram.ai/form-materials';
|
||||||
|
import { ASTFactory, definePluginCreator, GlobalScope } from '@flowgram.ai/fixed-layout-editor';
|
||||||
|
|
||||||
|
import iconVariable from '../../assets/icon-variable.png';
|
||||||
|
import { VariablePanelLayer } from './variable-panel-layer';
|
||||||
|
|
||||||
|
const fetchMockVariableFromRemote = async () => {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
userId: { type: 'string' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createVariablePanelPlugin = definePluginCreator({
|
||||||
|
onInit(ctx) {
|
||||||
|
ctx.playground.registerLayer(VariablePanelLayer);
|
||||||
|
|
||||||
|
// Fetch Global Variable
|
||||||
|
fetchMockVariableFromRemote().then((v) => {
|
||||||
|
ctx.get(GlobalScope).setVar(
|
||||||
|
ASTFactory.createVariableDeclaration({
|
||||||
|
key: 'global',
|
||||||
|
meta: {
|
||||||
|
title: 'Global',
|
||||||
|
icon: iconVariable,
|
||||||
|
},
|
||||||
|
type: JsonSchemaUtils.schemaToAST(v),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
1
apps/demo-fixed-layout/src/type.d.ts
vendored
1
apps/demo-fixed-layout/src/type.d.ts
vendored
@ -1,3 +1,4 @@
|
|||||||
declare module '*.svg'
|
declare module '*.svg'
|
||||||
declare module '*.png'
|
declare module '*.png'
|
||||||
declare module '*.jpg'
|
declare module '*.jpg'
|
||||||
|
declare module '*.module.less'
|
||||||
|
|||||||
BIN
apps/demo-free-layout/src/assets/icon-variable.png
Normal file
BIN
apps/demo-free-layout/src/assets/icon-variable.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
@ -15,7 +15,11 @@ import { FlowNodeRegistry, FlowDocumentJSON } from '../typings';
|
|||||||
import { shortcuts } from '../shortcuts';
|
import { shortcuts } from '../shortcuts';
|
||||||
import { CustomService } from '../services';
|
import { CustomService } from '../services';
|
||||||
import { WorkflowRuntimeService } from '../plugins/runtime-plugin/runtime-service';
|
import { WorkflowRuntimeService } from '../plugins/runtime-plugin/runtime-service';
|
||||||
import { createRuntimePlugin, createContextMenuPlugin } from '../plugins';
|
import {
|
||||||
|
createRuntimePlugin,
|
||||||
|
createContextMenuPlugin,
|
||||||
|
createVariablePanelPlugin,
|
||||||
|
} from '../plugins';
|
||||||
import { defaultFormMeta } from '../nodes/default-form-meta';
|
import { defaultFormMeta } from '../nodes/default-form-meta';
|
||||||
import { WorkflowNodeType } from '../nodes';
|
import { WorkflowNodeType } from '../nodes';
|
||||||
import { SelectorBoxPopover } from '../components/selector-box-popover';
|
import { SelectorBoxPopover } from '../components/selector-box-popover';
|
||||||
@ -294,6 +298,12 @@ export function useEditorProps(
|
|||||||
// protocol: 'http',
|
// protocol: 'http',
|
||||||
// },
|
// },
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Variable panel plugin
|
||||||
|
* 变量面板插件
|
||||||
|
*/
|
||||||
|
createVariablePanelPlugin({}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
[]
|
[]
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
export { createContextMenuPlugin } from './context-menu-plugin';
|
export { createContextMenuPlugin } from './context-menu-plugin';
|
||||||
export { createRuntimePlugin } from './runtime-plugin';
|
export { createRuntimePlugin } from './runtime-plugin';
|
||||||
|
export { createVariablePanelPlugin } from './variable-panel-plugin';
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
import { useVariableTree } from '@flowgram.ai/form-materials';
|
||||||
|
import { Tree } from '@douyinfe/semi-ui';
|
||||||
|
|
||||||
|
export function FullVariableList() {
|
||||||
|
const treeData = useVariableTree({});
|
||||||
|
|
||||||
|
return <Tree treeData={treeData} />;
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
import {
|
||||||
|
BaseVariableField,
|
||||||
|
GlobalScope,
|
||||||
|
useRefresh,
|
||||||
|
useService,
|
||||||
|
} from '@flowgram.ai/free-layout-editor';
|
||||||
|
import { JsonSchemaEditor, JsonSchemaUtils } from '@flowgram.ai/form-materials';
|
||||||
|
|
||||||
|
export function GlobalVariableEditor() {
|
||||||
|
const globalScope = useService(GlobalScope);
|
||||||
|
|
||||||
|
const refresh = useRefresh();
|
||||||
|
|
||||||
|
const globalVar = globalScope.getVar() as BaseVariableField;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const disposable = globalScope.output.onVariableListChange(() => {
|
||||||
|
refresh();
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposable.dispose();
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
if (!globalVar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = globalVar.type ? JsonSchemaUtils.astToSchema(globalVar.type) : { type: 'object' };
|
||||||
|
|
||||||
|
return (
|
||||||
|
<JsonSchemaEditor
|
||||||
|
value={value}
|
||||||
|
onChange={(_schema) => globalVar.updateType(JsonSchemaUtils.schemaToAST(_schema))}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
.panel-wrapper {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.variable-panel-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
&.close {
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
top: 10px;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-container {
|
||||||
|
width: 500px;
|
||||||
|
border-radius: 5px;
|
||||||
|
background-color: #fff;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 4px 4px 4px rgba(0, 0, 0, 0.1);
|
||||||
|
z-index: 30;
|
||||||
|
|
||||||
|
:global(.semi-tabs-bar) {
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:global(.semi-tabs-content) {
|
||||||
|
padding: 20px;
|
||||||
|
height: 500px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,40 @@
|
|||||||
|
import { useState } from 'react';
|
||||||
|
|
||||||
|
import { Button, Collapsible, Tabs, Tooltip } from '@douyinfe/semi-ui';
|
||||||
|
import { IconMinus } from '@douyinfe/semi-icons';
|
||||||
|
|
||||||
|
import iconVariable from '../../../assets/icon-variable.png';
|
||||||
|
import { GlobalVariableEditor } from './global-variable-editor';
|
||||||
|
import { FullVariableList } from './full-variable-list';
|
||||||
|
|
||||||
|
import styles from './index.module.less';
|
||||||
|
|
||||||
|
export function VariablePanel() {
|
||||||
|
const [isOpen, setOpen] = useState<boolean>(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles['panel-wrapper']}>
|
||||||
|
<Tooltip content="Toggle Variable Panel">
|
||||||
|
<Button
|
||||||
|
className={`${styles['variable-panel-button']} ${isOpen ? styles.close : ''}`}
|
||||||
|
theme={isOpen ? 'borderless' : 'light'}
|
||||||
|
onClick={() => setOpen((_open) => !_open)}
|
||||||
|
>
|
||||||
|
{isOpen ? <IconMinus /> : <img src={iconVariable} width={20} height={20} />}
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
<Collapsible isOpen={isOpen}>
|
||||||
|
<div className={styles['panel-container']}>
|
||||||
|
<Tabs>
|
||||||
|
<Tabs.TabPane itemKey="variables" tab="Variable List">
|
||||||
|
<FullVariableList />
|
||||||
|
</Tabs.TabPane>
|
||||||
|
<Tabs.TabPane itemKey="global" tab="Global Editor">
|
||||||
|
<GlobalVariableEditor />
|
||||||
|
</Tabs.TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</div>
|
||||||
|
</Collapsible>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -0,0 +1 @@
|
|||||||
|
export { createVariablePanelPlugin } from './variable-panel-plugin';
|
||||||
@ -0,0 +1,22 @@
|
|||||||
|
import { domUtils, injectable, Layer } from '@flowgram.ai/free-layout-editor';
|
||||||
|
|
||||||
|
import { VariablePanel } from './components/variable-panel';
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class VariablePanelLayer extends Layer {
|
||||||
|
onReady(): void {
|
||||||
|
// Fix variable panel in the right of canvas
|
||||||
|
this.config.onDataChange(() => {
|
||||||
|
const { scrollX, scrollY } = this.config.config;
|
||||||
|
domUtils.setStyle(this.node, {
|
||||||
|
position: 'absolute',
|
||||||
|
right: 25 - scrollX,
|
||||||
|
top: scrollY + 25,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): JSX.Element {
|
||||||
|
return <VariablePanel />;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,35 @@
|
|||||||
|
import { ASTFactory, definePluginCreator, GlobalScope } from '@flowgram.ai/free-layout-editor';
|
||||||
|
import { JsonSchemaUtils } from '@flowgram.ai/form-materials';
|
||||||
|
|
||||||
|
import iconVariable from '../../assets/icon-variable.png';
|
||||||
|
import { VariablePanelLayer } from './variable-panel-layer';
|
||||||
|
|
||||||
|
const fetchMockVariableFromRemote = async () => {
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
userId: { type: 'string' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createVariablePanelPlugin = definePluginCreator({
|
||||||
|
onInit(ctx) {
|
||||||
|
ctx.playground.registerLayer(VariablePanelLayer);
|
||||||
|
|
||||||
|
// Fetch Global Variable
|
||||||
|
fetchMockVariableFromRemote().then((v) => {
|
||||||
|
ctx.get(GlobalScope).setVar(
|
||||||
|
ASTFactory.createVariableDeclaration({
|
||||||
|
key: 'global',
|
||||||
|
meta: {
|
||||||
|
title: 'Global',
|
||||||
|
icon: iconVariable,
|
||||||
|
},
|
||||||
|
type: JsonSchemaUtils.schemaToAST(v),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
1
apps/demo-free-layout/src/type.d.ts
vendored
1
apps/demo-free-layout/src/type.d.ts
vendored
@ -1,3 +1,4 @@
|
|||||||
declare module '*.svg'
|
declare module '*.svg'
|
||||||
declare module '*.png'
|
declare module '*.png'
|
||||||
declare module '*.jpg'
|
declare module '*.jpg'
|
||||||
|
declare module '*.module.less'
|
||||||
|
|||||||
3
common/config/rush/pnpm-lock.yaml
generated
3
common/config/rush/pnpm-lock.yaml
generated
@ -102,6 +102,9 @@ importers:
|
|||||||
'@rsbuild/core':
|
'@rsbuild/core':
|
||||||
specifier: ^1.2.16
|
specifier: ^1.2.16
|
||||||
version: 1.2.19
|
version: 1.2.19
|
||||||
|
'@rsbuild/plugin-less':
|
||||||
|
specifier: ^1.1.1
|
||||||
|
version: 1.1.1(@rsbuild/core@1.2.19)
|
||||||
'@rsbuild/plugin-react':
|
'@rsbuild/plugin-react':
|
||||||
specifier: ^1.1.1
|
specifier: ^1.1.1
|
||||||
version: 1.1.1(@rsbuild/core@1.2.19)
|
version: 1.1.1(@rsbuild/core@1.2.19)
|
||||||
|
|||||||
@ -25,6 +25,8 @@ interface PropTypes {
|
|||||||
|
|
||||||
export type VariableSelectorProps = PropTypes;
|
export type VariableSelectorProps = PropTypes;
|
||||||
|
|
||||||
|
export { useVariableTree };
|
||||||
|
|
||||||
export const VariableSelector = ({
|
export const VariableSelector = ({
|
||||||
value,
|
value,
|
||||||
config = {},
|
config = {},
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useCallback } from 'react';
|
||||||
|
|
||||||
import { useScopeAvailable, ASTMatch, BaseVariableField } from '@flowgram.ai/editor';
|
import { ASTMatch, BaseVariableField, useAvailableVariables } from '@flowgram.ai/editor';
|
||||||
import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
|
import { TreeNodeData } from '@douyinfe/semi-ui/lib/es/tree';
|
||||||
import { Icon } from '@douyinfe/semi-ui';
|
import { Icon } from '@douyinfe/semi-ui';
|
||||||
|
|
||||||
@ -16,7 +16,7 @@ export function useVariableTree(params: {
|
|||||||
}): TreeNodeData[] {
|
}): TreeNodeData[] {
|
||||||
const { includeSchema, excludeSchema } = params;
|
const { includeSchema, excludeSchema } = params;
|
||||||
|
|
||||||
const available = useScopeAvailable();
|
const variables = useAvailableVariables();
|
||||||
|
|
||||||
const getVariableTypeIcon = useCallback((variable: VariableField) => {
|
const getVariableTypeIcon = useCallback((variable: VariableField) => {
|
||||||
if (variable.meta?.icon) {
|
if (variable.meta?.icon) {
|
||||||
@ -92,7 +92,7 @@ export function useVariableTree(params: {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return [...available.variables.slice(0).reverse()]
|
return [...variables.slice(0).reverse()]
|
||||||
.map((_variable) => renderVariable(_variable as VariableField))
|
.map((_variable) => renderVariable(_variable as VariableField))
|
||||||
.filter(Boolean) as TreeNodeData[];
|
.filter(Boolean) as TreeNodeData[];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -109,7 +109,7 @@ export namespace JsonSchemaUtils {
|
|||||||
type: 'object',
|
type: 'object',
|
||||||
properties: drilldown
|
properties: drilldown
|
||||||
? Object.fromEntries(
|
? Object.fromEntries(
|
||||||
Object.entries(typeAST.properties).map(([key, value]) => [key, astToSchema(value)!])
|
typeAST.properties.map((property) => [property.key, astToSchema(property.type)!])
|
||||||
)
|
)
|
||||||
: {},
|
: {},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -18,7 +18,7 @@ export function useAvailableVariables(): VariableDeclaration[] {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 没有作用域时,监听全局变量表
|
// 没有作用域时,监听全局变量表
|
||||||
if (!scope) {
|
if (!scope) {
|
||||||
const disposable = variableEngine.globalVariableTable.onAnyChange(() => {
|
const disposable = variableEngine.globalVariableTable.onListOrAnyVarChange(() => {
|
||||||
refresh();
|
refresh();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -70,8 +70,8 @@ export class ScopeAvailableData {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听任意变量变化
|
* listen to any variable update in list
|
||||||
* @param observer 监听器,变量变化时会吐出值
|
* @param observer
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
onAnyVariableChange(observer: (changedVariable: VariableDeclaration) => void) {
|
onAnyVariableChange(observer: (changedVariable: VariableDeclaration) => void) {
|
||||||
@ -79,7 +79,7 @@ export class ScopeAvailableData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听变量列表变化
|
* listen to variable list change
|
||||||
* @param observer
|
* @param observer
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
@ -87,22 +87,34 @@ export class ScopeAvailableData {
|
|||||||
return subsToDisposable(this.variables$.subscribe(observer));
|
return subsToDisposable(this.variables$.subscribe(observer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
*/
|
||||||
protected onDataChangeEmitter = new Emitter<VariableDeclaration[]>();
|
protected onDataChangeEmitter = new Emitter<VariableDeclaration[]>();
|
||||||
|
|
||||||
|
protected onListOrAnyVarChangeEmitter = new Emitter<VariableDeclaration[]>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听变量列表变化 + 任意子变量变化
|
* @deprecated use available.onListOrAnyVarChange instead
|
||||||
*/
|
*/
|
||||||
public onDataChange = this.onDataChangeEmitter.event;
|
public onDataChange = this.onDataChangeEmitter.event;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* listen to variable list change + any variable drilldown change
|
||||||
|
*/
|
||||||
|
public onListOrAnyVarChange = this.onListOrAnyVarChangeEmitter.event;
|
||||||
|
|
||||||
constructor(public readonly scope: Scope) {
|
constructor(public readonly scope: Scope) {
|
||||||
this.scope.toDispose.pushAll([
|
this.scope.toDispose.pushAll([
|
||||||
this.onVariableListChange((_variables) => {
|
this.onVariableListChange((_variables) => {
|
||||||
this._variables = _variables;
|
this._variables = _variables;
|
||||||
this.memo.clear();
|
this.memo.clear();
|
||||||
this.onDataChangeEmitter.fire(this._variables);
|
this.onDataChangeEmitter.fire(this._variables);
|
||||||
|
this.onListOrAnyVarChangeEmitter.fire(this._variables);
|
||||||
}),
|
}),
|
||||||
this.onAnyVariableChange(() => {
|
this.onAnyVariableChange(() => {
|
||||||
this.onDataChangeEmitter.fire(this._variables);
|
this.onDataChangeEmitter.fire(this._variables);
|
||||||
|
this.onListOrAnyVarChangeEmitter.fire(this._variables);
|
||||||
}),
|
}),
|
||||||
Disposable.create(() => {
|
Disposable.create(() => {
|
||||||
this.refresh$.complete();
|
this.refresh$.complete();
|
||||||
|
|||||||
@ -24,14 +24,34 @@ export class ScopeOutputData {
|
|||||||
return this.scope.variableEngine.globalVariableTable;
|
return this.scope.variableEngine.globalVariableTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use onListOrAnyVarChange instead
|
||||||
|
*/
|
||||||
get onDataChange() {
|
get onDataChange() {
|
||||||
return this.variableTable.onDataChange.bind(this.variableTable);
|
return this.variableTable.onDataChange.bind(this.variableTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* listen to variable list change
|
||||||
|
*/
|
||||||
|
get onVariableListChange() {
|
||||||
|
return this.variableTable.onVariableListChange.bind(this.variableTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* listen to any variable update in list
|
||||||
|
*/
|
||||||
get onAnyVariableChange() {
|
get onAnyVariableChange() {
|
||||||
return this.variableTable.onAnyVariableChange.bind(this.variableTable);
|
return this.variableTable.onAnyVariableChange.bind(this.variableTable);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* listen to variable list change + any variable update in list
|
||||||
|
*/
|
||||||
|
get onListOrAnyVarChange() {
|
||||||
|
return this.variableTable.onListOrAnyVarChange.bind(this.variableTable);
|
||||||
|
}
|
||||||
|
|
||||||
protected _hasChanges = false;
|
protected _hasChanges = false;
|
||||||
|
|
||||||
constructor(public readonly scope: Scope) {
|
constructor(public readonly scope: Scope) {
|
||||||
|
|||||||
@ -25,6 +25,7 @@ export interface IVariableTable extends Disposable {
|
|||||||
// addVariableToTable(variable: VariableDeclaration): void;
|
// addVariableToTable(variable: VariableDeclaration): void;
|
||||||
// removeVariableFromTable(key: string): void;
|
// removeVariableFromTable(key: string): void;
|
||||||
dispose(): void;
|
dispose(): void;
|
||||||
|
onVariableListChange(observer: (variables: VariableDeclaration[]) => void): Disposable;
|
||||||
onAnyVariableChange(observer: (changedVariable: VariableDeclaration) => void): Disposable;
|
onAnyVariableChange(observer: (changedVariable: VariableDeclaration) => void): Disposable;
|
||||||
onAnyChange(observer: () => void): Disposable;
|
onListOrAnyVarChange(observer: () => void): Disposable;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,8 +29,8 @@ export class VariableTable implements IVariableTable {
|
|||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 监听任意变量变化
|
* listen to any variable update in list
|
||||||
* @param observer 监听器,变量变化时会吐出值
|
* @param observer
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
onAnyVariableChange(observer: (changedVariable: VariableDeclaration) => void) {
|
onAnyVariableChange(observer: (changedVariable: VariableDeclaration) => void) {
|
||||||
@ -38,15 +38,27 @@ export class VariableTable implements IVariableTable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 列表或者任意变量变化
|
* listen to variable list change
|
||||||
|
* @param observer
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
onVariableListChange(observer: (variables: VariableDeclaration[]) => void) {
|
||||||
|
return subsToDisposable(this.variables$.subscribe(observer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* listen to variable list change + any variable update in list
|
||||||
* @param observer
|
* @param observer
|
||||||
*/
|
*/
|
||||||
onAnyChange(observer: () => void) {
|
onListOrAnyVarChange(observer: () => void) {
|
||||||
const disposables = new DisposableCollection();
|
const disposables = new DisposableCollection();
|
||||||
disposables.pushAll([this.onDataChange(observer), this.onAnyVariableChange(observer)]);
|
disposables.pushAll([this.onVariableListChange(observer), this.onAnyVariableChange(observer)]);
|
||||||
return disposables;
|
return disposables;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use onListOrAnyVarChange instead
|
||||||
|
*/
|
||||||
public onDataChange = this.onDataChangeEmitter.event;
|
public onDataChange = this.onDataChangeEmitter.event;
|
||||||
|
|
||||||
protected _version: number = 0;
|
protected _version: number = 0;
|
||||||
@ -54,6 +66,7 @@ export class VariableTable implements IVariableTable {
|
|||||||
fireChange() {
|
fireChange() {
|
||||||
this._version++;
|
this._version++;
|
||||||
this.onDataChangeEmitter.fire();
|
this.onDataChangeEmitter.fire();
|
||||||
|
this.variables$.next(this.variables);
|
||||||
this.parentTable?.fireChange();
|
this.parentTable?.fireChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +121,6 @@ export class VariableTable implements IVariableTable {
|
|||||||
if (this.parentTable) {
|
if (this.parentTable) {
|
||||||
(this.parentTable as VariableTable).addVariableToTable(variable);
|
(this.parentTable as VariableTable).addVariableToTable(variable);
|
||||||
}
|
}
|
||||||
this.variables$.next(this.variables);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,13 +132,15 @@ export class VariableTable implements IVariableTable {
|
|||||||
if (this.parentTable) {
|
if (this.parentTable) {
|
||||||
(this.parentTable as VariableTable).removeVariableFromTable(key);
|
(this.parentTable as VariableTable).removeVariableFromTable(key);
|
||||||
}
|
}
|
||||||
this.variables$.next(this.variables);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
this.variableKeys.forEach((_key) =>
|
this.variableKeys.forEach((_key) =>
|
||||||
(this.parentTable as VariableTable)?.removeVariableFromTable(_key)
|
(this.parentTable as VariableTable)?.removeVariableFromTable(_key)
|
||||||
);
|
);
|
||||||
|
this.parentTable?.fireChange();
|
||||||
|
this.variables$.complete();
|
||||||
|
this.variables$.unsubscribe();
|
||||||
this.onDataChangeEmitter.dispose();
|
this.onDataChangeEmitter.dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user