feat(plugin-workflow): add create node component (#292)

This commit is contained in:
Junyi 2022-04-15 23:54:20 +08:00 committed by GitHub
parent 5039896b16
commit e002777b63
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 212 additions and 46 deletions

View File

@ -65,7 +65,7 @@ export function parseStringValue(value: string, Types) {
return { return {
type, type,
options: paths.length ? (Types || VariableTypes)[type].parse(paths) : {} options: paths.length ? (Types || VariableTypes)[type]?.parse(paths) : {}
}; };
} }
@ -252,7 +252,7 @@ export function Operand({
const { type } = operand; const { type } = operand;
const { component, appendTypeValue } = Types[type]; const { component, appendTypeValue } = Types[type] || {};
const VariableComponent = typeof component === 'function' ? component(operand) : NullRender; const VariableComponent = typeof component === 'function' ? component(operand) : NullRender;
return ( return (

View File

@ -0,0 +1,156 @@
import React from 'react';
import { observer, useForm } from '@formily/react';
import { action } from '@formily/reactive';
import { Select } from 'antd';
import { t } from 'i18next';
import { css } from '@emotion/css';
import { SchemaComponent, useCollectionManager } from '../..';
import { useCollectionFilterOptions } from '../../collection-manager/action-hooks';
import { useFlowContext } from '../WorkflowCanvas';
import { Operand, parseStringValue, VariableTypes, VariableTypesContext, BaseTypeSet } from '../calculators';
import { FormItem } from '@formily/antd';
export default {
title: '新增',
type: 'create',
group: 'model',
fieldset: {
collection: {
type: 'string',
title: '数据表',
name: 'collection',
required: true,
'x-reactions': ['{{useCollectionDataSource()}}'],
'x-decorator': 'FormItem',
'x-component': 'Select',
},
// multiple: {
// type: 'boolean',
// title: '多条数据',
// name: 'multiple',
// 'x-decorator': 'FormItem',
// 'x-component': 'Checkbox',
// 'x-component-props': {
// disabled: true
// }
// },
params: {
type: 'object',
name: 'params',
title: '数据',
'x-decorator': 'FormItem',
properties: {
values: {
type: 'object',
title: '',
name: 'values',
'x-component': 'DynamicFieldset',
'x-component-props': {
useProps() {
const { values } = useForm();
return { fields: useCollectionFilterOptions(values.collection) };
}
}
}
}
}
},
view: {
},
scope: {
useCollectionDataSource() {
return (field: any) => {
const { collections = [] } = useCollectionManager();
action.bound((data: any) => {
field.dataSource = data.map(item => ({
label: t(item.title),
value: item.name
}));
})(collections);
}
}
},
components: {
// NOTE: observer for watching useProps
DynamicFieldset: observer(({ value, onChange, useProps }: any) => {
const { fields } = useProps();
const VTypes = { ...VariableTypes,
constant: {
title: '常量',
value: 'constant',
options: undefined
}
};
return (
<fieldset className={css`
margin-top: .5em;
.ant-formily-item{
.ant-formily-item-label{
line-height: 32px;
}
.ant-select,
.ant-cascader-picker,
.ant-picker,
.ant-input-number,
.ant-input-affix-wrapper{
width: auto;
}
}
`}>
{fields.map(field => {
const operand = typeof value[field.name] === 'string'
? parseStringValue(value[field.name], VTypes)
: { type: 'constant', value: value[field.name] };
return (
<FormItem label={field.title}>
<VariableTypesContext.Provider value={VTypes}>
<Operand
value={operand}
onChange={(next) => {
if (next.type !== operand.type && next.type === 'constant') {
onChange({ ...value, [field.name]: null });
} else {
const { stringify } = VTypes[next.type];
onChange({ ...value, [field.name]: stringify(next) });
}
}}
>
{operand.type === 'constant'
? <SchemaComponent schema={field.schema} />
: null
}
</Operand>
</VariableTypesContext.Provider>
</FormItem>
);
})}
</fieldset>
);
})
},
getter({ type, options, onChange }) {
const { collections = [] } = useCollectionManager();
const { nodes } = useFlowContext();
const { config } = nodes.find(n => n.id == options.nodeId);
const collection = collections.find(item => item.name === config.collection) ?? { fields: [] };
return (
<Select value={options.path} placeholder="选择字段" onChange={path => {
onChange({ type, options: { ...options, path } });
}}>
{collection.fields
.filter(field => BaseTypeSet.has(field.uiSchema.type))
.map(field => (
<Select.Option key={field.name} value={field.name}>{t(field.uiSchema.title)}</Select.Option>
))}
</Select>
);
}
};

View File

@ -12,6 +12,7 @@ import { AddButton, useFlowContext } from '../WorkflowCanvas';
import { nodeClass, nodeCardClass, nodeHeaderClass, nodeTitleClass, nodeBlockClass } from '../style'; import { nodeClass, nodeCardClass, nodeHeaderClass, nodeTitleClass, nodeBlockClass } from '../style';
import query from './query'; import query from './query';
import create from './create';
import condition from './condition'; import condition from './condition';
import parallel from './parallel'; import parallel from './parallel';
import calculation from './calculation'; import calculation from './calculation';
@ -59,6 +60,7 @@ export interface Instruction {
export const instructions = new Registry<Instruction>(); export const instructions = new Registry<Instruction>();
instructions.register('query', query); instructions.register('query', query);
instructions.register('create', create);
instructions.register('condition', condition); instructions.register('condition', condition);
instructions.register('parallel', parallel); instructions.register('parallel', parallel);
instructions.register('calculation', calculation); instructions.register('calculation', calculation);
@ -159,54 +161,58 @@ export function NodeDefaultView(props) {
type: 'void', type: 'void',
properties: { properties: {
view: instruction.view, view: instruction.view,
config: { ...(Object.keys(instruction.fieldset).length
type: 'void', ? {
title: '配置节点', config: {
'x-component': 'Action.Link',
'x-component-props': {
type: 'primary',
},
properties: {
drawer: {
type: 'void', type: 'void',
title: '配置节点', title: '配置节点',
'x-component': 'Action.Drawer', 'x-component': 'Action.Link',
'x-decorator': 'Form', 'x-component-props': {
'x-decorator-props': { type: 'primary',
useValues(options) {
const node = useNodeContext();
return useRequest(() => {
return Promise.resolve({ data: node.config });
}, options);
}
}, },
properties: { properties: {
...instruction.fieldset, drawer: {
actions: {
type: 'void', type: 'void',
'x-component': 'Action.Drawer.Footer', title: '配置节点',
properties: { 'x-component': 'Action.Drawer',
cancel: { 'x-decorator': 'Form',
title: '{{t("Cancel")}}', 'x-decorator-props': {
'x-component': 'Action', useValues(options) {
'x-component-props': { const node = useNodeContext();
useAction: '{{ cm.useCancelAction }}', return useRequest(() => {
}, return Promise.resolve({ data: node.config });
}, }, options);
submit: { }
title: '{{t("Submit")}}',
'x-component': 'Action',
'x-component-props': {
type: 'primary',
useAction: useUpdateConfigAction,
},
},
}, },
} as ISchema properties: {
...instruction.fieldset,
actions: {
type: 'void',
'x-component': 'Action.Drawer.Footer',
properties: {
cancel: {
title: '{{t("Cancel")}}',
'x-component': 'Action',
'x-component-props': {
useAction: '{{ cm.useCancelAction }}',
},
},
submit: {
title: '{{t("Submit")}}',
'x-component': 'Action',
'x-component-props': {
type: 'primary',
useAction: useUpdateConfigAction,
},
},
},
} as ISchema
}
}
} }
} }
} }
} : {})
} }
}} }}
/> />

View File

@ -11,7 +11,7 @@ import { useFlowContext } from '../WorkflowCanvas';
import { Operand, parseStringValue, VariableTypes, VariableTypesContext, BaseTypeSet } from '../calculators'; import { Operand, parseStringValue, VariableTypes, VariableTypesContext, BaseTypeSet } from '../calculators';
export default { export default {
title: '数据查询', title: '查询',
type: 'query', type: 'query',
group: 'model', group: 'model',
fieldset: { fieldset: {

View File

@ -72,11 +72,15 @@ export default {
const collection = collections.find(item => item.name === workflow.config.collection) ?? { fields: [] }; const collection = collections.find(item => item.name === workflow.config.collection) ?? { fields: [] };
return ( return (
<Select value={options?.path.replace(/^data\./, '')} placeholder="选择字段" onChange={path => { <Select
onChange({ type, options: { ...options, path: `data.${path}` } }); placeholder="选择字段"
}}> value={options?.path?.replace(/^data\./, '')}
onChange={(path) => {
onChange({ type, options: { ...options, path: `data.${path}` } });
}}
>
{collection.fields {collection.fields
.filter(field => BaseTypeSet.has(field.uiSchema.type)) .filter(field => BaseTypeSet.has(field?.uiSchema?.type))
.map(field => ( .map(field => (
<Select.Option key={field.name} value={field.name}>{t(field.uiSchema.title)}</Select.Option> <Select.Option key={field.name} value={field.name}>{t(field.uiSchema.title)}</Select.Option>
))} ))}