mirror of
https://gitee.com/ByteDance/flowgram.ai.git
synced 2025-07-07 17:43:29 +08:00
feat(material): auto rename effect (#261)
This commit is contained in:
parent
e9218afcaa
commit
dd727c8d63
@ -1,3 +1,4 @@
|
|||||||
|
import { autoRenameRefEffect } from '@flowgram.ai/form-materials';
|
||||||
import { FormRenderProps, FormMeta, ValidateTrigger } from '@flowgram.ai/fixed-layout-editor';
|
import { FormRenderProps, FormMeta, ValidateTrigger } from '@flowgram.ai/fixed-layout-editor';
|
||||||
|
|
||||||
import { FlowNodeJSON } from '../typings';
|
import { FlowNodeJSON } from '../typings';
|
||||||
@ -27,4 +28,7 @@ export const defaultFormMeta: FormMeta<FlowNodeJSON['data']> = {
|
|||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
effect: {
|
||||||
|
inputsValues: autoRenameRefEffect,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import { FormRenderProps, FormMeta, ValidateTrigger } from '@flowgram.ai/free-layout-editor';
|
import { FormRenderProps, FormMeta, ValidateTrigger } from '@flowgram.ai/free-layout-editor';
|
||||||
|
import { autoRenameRefEffect } from '@flowgram.ai/form-materials';
|
||||||
|
|
||||||
import { FlowNodeJSON } from '../typings';
|
import { FlowNodeJSON } from '../typings';
|
||||||
import { FormHeader, FormContent, FormInputs, FormOutputs } from '../form-components';
|
import { FormHeader, FormContent, FormInputs, FormOutputs } from '../form-components';
|
||||||
@ -27,4 +28,7 @@ export const defaultFormMeta: FormMeta<FlowNodeJSON> = {
|
|||||||
return undefined;
|
return undefined;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
effect: {
|
||||||
|
inputsValues: autoRenameRefEffect,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
7
common/config/rush/pnpm-lock.yaml
generated
7
common/config/rush/pnpm-lock.yaml
generated
@ -1916,6 +1916,9 @@ importers:
|
|||||||
commander:
|
commander:
|
||||||
specifier: ^11.0.0
|
specifier: ^11.0.0
|
||||||
version: 11.1.0
|
version: 11.1.0
|
||||||
|
immer:
|
||||||
|
specifier: ~10.1.1
|
||||||
|
version: 10.1.1
|
||||||
inquirer:
|
inquirer:
|
||||||
specifier: ^9.2.7
|
specifier: ^9.2.7
|
||||||
version: 9.3.7
|
version: 9.3.7
|
||||||
@ -11746,6 +11749,10 @@ packages:
|
|||||||
dev: true
|
dev: true
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
/immer@10.1.1:
|
||||||
|
resolution: {integrity: sha512-s2MPrmjovJcoMaHtx6K11Ra7oD05NT97w1IC5zpMkT6Atjr7H8LjaDd81iIxUYpMKSRRNMJE703M1Fhr/TctHw==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/immutable@5.0.3:
|
/immutable@5.0.3:
|
||||||
resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==}
|
resolution: {integrity: sha512-P8IdPQHq3lA1xVeBRi5VPqUm5HDgKnx0Ru51wZz5mjxHr5n3RWhjIpOFU7ybkUxfB+5IToy+OLaHYDBIWsv+uw==}
|
||||||
|
|
||||||
|
|||||||
@ -40,7 +40,8 @@
|
|||||||
"nanoid": "^4.0.2",
|
"nanoid": "^4.0.2",
|
||||||
"commander": "^11.0.0",
|
"commander": "^11.0.0",
|
||||||
"chalk": "^5.3.0",
|
"chalk": "^5.3.0",
|
||||||
"inquirer": "^9.2.7"
|
"inquirer": "^9.2.7",
|
||||||
|
"immer": "~10.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@flowgram.ai/eslint-config": "workspace:*",
|
"@flowgram.ai/eslint-config": "workspace:*",
|
||||||
|
|||||||
@ -0,0 +1,22 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import Input, { InputProps } from '@douyinfe/semi-ui/lib/es/input';
|
||||||
|
|
||||||
|
export function BlurInput(props: InputProps) {
|
||||||
|
const [value, setValue] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setValue(props.value as string);
|
||||||
|
}, [props.value]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
{...props}
|
||||||
|
value={value}
|
||||||
|
onChange={(value) => {
|
||||||
|
setValue(value);
|
||||||
|
}}
|
||||||
|
onBlur={(e) => props.onChange?.(value, e)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useMemo, useState } from 'react';
|
import React, { useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { Button, Checkbox, IconButton, Input } from '@douyinfe/semi-ui';
|
import { Button, Checkbox, IconButton } from '@douyinfe/semi-ui';
|
||||||
import {
|
import {
|
||||||
IconExpand,
|
IconExpand,
|
||||||
IconShrink,
|
IconShrink,
|
||||||
@ -31,6 +31,7 @@ import {
|
|||||||
import { UIName } from './styles';
|
import { UIName } from './styles';
|
||||||
import { UIRow } from './styles';
|
import { UIRow } from './styles';
|
||||||
import { usePropertiesEdit } from './hooks';
|
import { usePropertiesEdit } from './hooks';
|
||||||
|
import { BlurInput } from './components/blur-input';
|
||||||
|
|
||||||
export function JsonSchemaEditor(props: {
|
export function JsonSchemaEditor(props: {
|
||||||
value?: IJsonSchema;
|
value?: IJsonSchema;
|
||||||
@ -109,7 +110,7 @@ function PropertyEdit(props: {
|
|||||||
<UIPropertyMain $expand={expand}>
|
<UIPropertyMain $expand={expand}>
|
||||||
<UIRow>
|
<UIRow>
|
||||||
<UIName>
|
<UIName>
|
||||||
<Input
|
<BlurInput
|
||||||
placeholder={config?.placeholder ?? 'Input Variable Name'}
|
placeholder={config?.placeholder ?? 'Input Variable Name'}
|
||||||
size="small"
|
size="small"
|
||||||
value={name}
|
value={name}
|
||||||
@ -162,7 +163,7 @@ function PropertyEdit(props: {
|
|||||||
{expand && (
|
{expand && (
|
||||||
<UIExpandDetail>
|
<UIExpandDetail>
|
||||||
<UILabel>{config?.descTitle ?? 'Description'}</UILabel>
|
<UILabel>{config?.descTitle ?? 'Description'}</UILabel>
|
||||||
<Input
|
<BlurInput
|
||||||
size="small"
|
size="small"
|
||||||
value={description}
|
value={description}
|
||||||
onChange={(value) => onChange('description', value)}
|
onChange={(value) => onChange('description', value)}
|
||||||
|
|||||||
@ -100,7 +100,7 @@ export const VariableSelector = ({
|
|||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
showClear={false}
|
showClear={false}
|
||||||
arrowIcon={value ? null : <IconChevronDownStroked size="small" />}
|
arrowIcon={<IconChevronDownStroked size="small" />}
|
||||||
triggerRender={triggerRender}
|
triggerRender={triggerRender}
|
||||||
placeholder={config?.placeholder ?? 'Select Variable...'}
|
placeholder={config?.placeholder ?? 'Select Variable...'}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "auto-rename-ref",
|
||||||
|
"depMaterials": ["flow-value"],
|
||||||
|
"depPackages": ["lodash"]
|
||||||
|
}
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
import { isArray, isObject } from 'lodash';
|
||||||
|
import {
|
||||||
|
DataEvent,
|
||||||
|
Effect,
|
||||||
|
EffectOptions,
|
||||||
|
VariableFieldKeyRenameService,
|
||||||
|
} from '@flowgram.ai/editor';
|
||||||
|
|
||||||
|
import { IFlowRefValue } from '../../typings';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auto rename ref when form item's key is renamed
|
||||||
|
*
|
||||||
|
* Example:
|
||||||
|
*
|
||||||
|
* formMeta: {
|
||||||
|
* effects: {
|
||||||
|
* "inputsValues": autoRenameRefEffect,
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
export const autoRenameRefEffect: EffectOptions[] = [
|
||||||
|
{
|
||||||
|
event: DataEvent.onValueInit,
|
||||||
|
effect: ((params) => {
|
||||||
|
const { context, form, name } = params;
|
||||||
|
|
||||||
|
const renameService = context.node.getService(VariableFieldKeyRenameService);
|
||||||
|
|
||||||
|
const disposable = renameService.onRename(({ before, after }) => {
|
||||||
|
const beforeKeyPath = [
|
||||||
|
...before.parentFields.map((_field) => _field.key).reverse(),
|
||||||
|
before.key,
|
||||||
|
];
|
||||||
|
const afterKeyPath = [
|
||||||
|
...after.parentFields.map((_field) => _field.key).reverse(),
|
||||||
|
after.key,
|
||||||
|
];
|
||||||
|
|
||||||
|
// traverse rename refs inside form item 'name'
|
||||||
|
traverseRef(name, form.getValueIn(name), (_drilldownName, _v) => {
|
||||||
|
if (isRefMatch(_v, beforeKeyPath)) {
|
||||||
|
_v.content = [...afterKeyPath, ...(_v.content || [])?.slice(beforeKeyPath.length)];
|
||||||
|
form.setValueIn(_drilldownName, _v);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
disposable.dispose();
|
||||||
|
};
|
||||||
|
}) as Effect,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If ref value's keyPath is the under as targetKeyPath
|
||||||
|
* @param value
|
||||||
|
* @param targetKeyPath
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function isRefMatch(value: IFlowRefValue, targetKeyPath: string[]) {
|
||||||
|
return targetKeyPath.every((_key, index) => _key === value.content?.[index]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If value is ref
|
||||||
|
* @param value
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function isRef(value: any): value is IFlowRefValue {
|
||||||
|
return (
|
||||||
|
value?.type === 'ref' && Array.isArray(value?.content) && typeof value?.content[0] === 'string'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Traverse value to find ref
|
||||||
|
* @param value
|
||||||
|
* @param options
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
function traverseRef(name: string, value: any, cb: (name: string, _v: IFlowRefValue) => void) {
|
||||||
|
if (isObject(value)) {
|
||||||
|
if (isRef(value)) {
|
||||||
|
cb(name, value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.entries(value).forEach(([_key, _value]) => {
|
||||||
|
traverseRef(`${name}.${_key}`, _value, cb);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isArray(value)) {
|
||||||
|
value.forEach((_value, idx) => {
|
||||||
|
traverseRef(`${name}[${idx}]`, _value, cb);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
@ -1,2 +1,3 @@
|
|||||||
export * from './provide-batch-input';
|
export * from './provide-batch-input';
|
||||||
export * from './provide-batch-outputs';
|
export * from './provide-batch-outputs';
|
||||||
|
export * from './auto-rename-ref';
|
||||||
|
|||||||
@ -13,7 +13,12 @@ import {
|
|||||||
ObjectType,
|
ObjectType,
|
||||||
StringType,
|
StringType,
|
||||||
} from './type';
|
} from './type';
|
||||||
import { EnumerateExpression, KeyPathExpression, WrapArrayExpression } from './expression';
|
import {
|
||||||
|
EnumerateExpression,
|
||||||
|
// KeyPathExpression,
|
||||||
|
KeyPathExpressionV2,
|
||||||
|
WrapArrayExpression,
|
||||||
|
} from './expression';
|
||||||
import { Property, VariableDeclaration, VariableDeclarationList } from './declaration';
|
import { Property, VariableDeclaration, VariableDeclarationList } from './declaration';
|
||||||
import { DataNode, MapNode } from './common';
|
import { DataNode, MapNode } from './common';
|
||||||
import { ASTNode, ASTNodeRegistry } from './ast-node';
|
import { ASTNode, ASTNodeRegistry } from './ast-node';
|
||||||
@ -41,7 +46,9 @@ export class ASTRegisters {
|
|||||||
this.registerAST(Property);
|
this.registerAST(Property);
|
||||||
this.registerAST(VariableDeclaration);
|
this.registerAST(VariableDeclaration);
|
||||||
this.registerAST(VariableDeclarationList);
|
this.registerAST(VariableDeclarationList);
|
||||||
this.registerAST(KeyPathExpression);
|
// this.registerAST(KeyPathExpression);
|
||||||
|
this.registerAST(KeyPathExpressionV2);
|
||||||
|
|
||||||
this.registerAST(EnumerateExpression);
|
this.registerAST(EnumerateExpression);
|
||||||
this.registerAST(WrapArrayExpression);
|
this.registerAST(WrapArrayExpression);
|
||||||
this.registerAST(MapNode);
|
this.registerAST(MapNode);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user