feat(plugin-workflow): support context variables from model trigger (#284)

This commit is contained in:
Junyi 2022-04-11 22:06:41 +08:00 committed by GitHub
parent 2f6aeacbd8
commit d0e524a1a0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 83 additions and 23 deletions

View File

@ -40,7 +40,7 @@ export function WorkflowCanvas() {
return <div></div>;
}
const { nodes = [] } = data?.data ?? {};
const { nodes = [], ...workflow } = data?.data ?? {};
makeNodes(nodes);
@ -48,6 +48,7 @@ export function WorkflowCanvas() {
return (
<FlowContext.Provider value={{
workflow,
nodes,
onNodeAdded: refresh,
onNodeRemoved: refresh

View File

@ -4,6 +4,7 @@ import { css } from "@emotion/css";
import { instructions, useNodeContext } from "./nodes";
import { useFlowContext } from "./WorkflowCanvas";
import { triggers } from "./triggers";
function NullRender() {
return null;
@ -68,6 +69,8 @@ export function parseStringValue(value: string, Types) {
};
}
export const BaseTypeSet = new Set(['boolean', 'number', 'string', 'date']);
const ConstantTypes = {
string: {
title: '字符串',
@ -189,7 +192,25 @@ export const VariableTypes = {
return `{{${stack.join('.')}}}`;
}
},
// context: ContextSelect,
context: {
title: '触发数据',
value: 'context',
component() {
const { workflow } = useFlowContext();
const trigger = triggers.get(workflow.type);
return trigger?.getter ?? NullRender;
},
parse([prefix, ...path]) {
return { path: path.join('.') };
},
stringify({ options }) {
const stack = ['context'];
if (options?.path) {
stack.push(options.path);
}
return `{{${stack.join('.')}}}`;
}
},
// calculation: Calculation
};
@ -205,10 +226,15 @@ interface OperandProps {
value?: any;
options?: any;
};
onChange(v: any): void
onChange(v: any): void;
children?: React.ReactNode;
}
export function Operand({ onChange, value: operand = { type: 'constant', value: '', options: { type: 'string' } } }: OperandProps) {
export function Operand({
value: operand = { type: 'constant', value: '', options: { type: 'string' } },
onChange,
children
}: OperandProps) {
const Types = useVariableTypes();
const { type } = operand;
@ -226,13 +252,13 @@ export function Operand({ onChange, value: operand = { type: 'constant', value:
allowClear={false}
value={[type, ...(appendTypeValue ? appendTypeValue(operand) : [])]}
options={Object.values(Types).map((item: any) => {
const children = typeof item.options === 'function' ? item.options() : item.options;
const options = typeof item.options === 'function' ? item.options() : item.options;
return {
label: item.title,
value: item.value,
children,
disabled: children && !children.length,
isLeaf: !children
children: options,
disabled: options && !options.length,
isLeaf: !options
};
})}
onChange={(next: Array<string | number>) => {
@ -246,7 +272,7 @@ export function Operand({ onChange, value: operand = { type: 'constant', value:
}
}}
/>
<VariableComponent {...operand} onChange={op => onChange({ ...op })} />
{children ?? <VariableComponent {...operand} onChange={op => onChange({ ...op })} />}
</div>
);
}

View File

@ -161,7 +161,7 @@ export default {
{ label: '分支模式', key: 'branch', value: { rejectOnFalse: false } }
],
render(data) {
const { id, config: { calculation, rejectOnFalse } } = data;
const { id, config: { rejectOnFalse } } = data;
const { nodes } = useFlowContext();
const trueEntry = nodes.find(item => item.upstreamId === id && item.branchIndex === 1);
const falseEntry = nodes.find(item => item.upstreamId === id && item.branchIndex === 0);

View File

@ -8,9 +8,7 @@ import { css } from '@emotion/css';
import { useCollectionManager } from '../..';
import { useCollectionFilterOptions } from '../../collection-manager/action-hooks';
import { useFlowContext } from '../WorkflowCanvas';
import { Operand, parseStringValue, VariableTypes, VariableTypesContext } from '../calculators';
const BaseTypeSet = new Set(['boolean', 'number', 'string', 'date']);
import { Operand, parseStringValue, VariableTypes, VariableTypesContext, BaseTypeSet } from '../calculators';
export default {
title: '数据查询',
@ -89,10 +87,7 @@ export default {
constant: {
title: '常量',
value: 'constant',
options: undefined,
component() {
return renderSchemaComponent;
}
options: undefined
}
};
@ -112,7 +107,9 @@ export default {
onChange(stringify(next));
}
}}
/>
>
{operand.type === 'constant' ? renderSchemaComponent() : null}
</Operand>
</VariableTypesContext.Provider>
);
}

View File

@ -1,6 +1,7 @@
import React from "react";
import { useForm } from "@formily/react";
import { ISchema, useForm } from "@formily/react";
import { cx } from "@emotion/css";
import { Registry } from "@nocobase/utils";
import { SchemaComponent, useActionContext, useAPIClient, useRecord, useResourceActionContext } from '../../';
import model from './model';
@ -30,18 +31,30 @@ function useUpdateConfigAction() {
};
};
const triggerTypes = {
model
export interface Trigger {
title: string;
type: string;
// group: string;
options?: { label: string; value: any; key: string }[];
fieldset: { [key: string]: ISchema };
view?: ISchema;
scope?: { [key: string]: any };
components?: { [key: string]: any };
render?(props): React.ReactElement;
getter?(node: any): React.ReactElement;
};
export const triggers = new Registry<Trigger>();
triggers.register('model', model);
export const TriggerConfig = () => {
const { data } = useResourceActionContext();
if (!data) {
return null;
}
const { type, config } = data.data;
const { title, fieldset, scope } = triggerTypes[type];
const { title, fieldset, scope } = triggers.get(type);
return (
<div className={cx(nodeCardClass)}>
<h4>{title}</h4>

View File

@ -1,9 +1,15 @@
import React from 'react';
import { action } from '@formily/reactive';
import { t } from 'i18next';
import { Select } from 'antd';
import { useCollectionManager } from '../../collection-manager';
import { useFlowContext } from '../WorkflowCanvas';
import { BaseTypeSet } from '../calculators';
export default {
title: '数据表事件',
type: 'model',
fieldset: {
collection: {
type: 'string',
@ -32,5 +38,22 @@ export default {
})(collections);
}
}
},
getter({ type, options, onChange }) {
const { collections = [] } = useCollectionManager();
const { workflow } = useFlowContext();
const collection = collections.find(item => item.name === workflow.config.collection) ?? { fields: [] };
return (
<Select value={options.path} placeholder="选择字段" onChange={path => {
onChange({ type, options: { ...options, path: `data.${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>
);
}
};