feat(plugin-workflow): support context variables from model trigger (#284)
This commit is contained in:
parent
2f6aeacbd8
commit
d0e524a1a0
@ -40,7 +40,7 @@ export function WorkflowCanvas() {
|
|||||||
return <div>加载失败</div>;
|
return <div>加载失败</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { nodes = [] } = data?.data ?? {};
|
const { nodes = [], ...workflow } = data?.data ?? {};
|
||||||
|
|
||||||
makeNodes(nodes);
|
makeNodes(nodes);
|
||||||
|
|
||||||
@ -48,6 +48,7 @@ export function WorkflowCanvas() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<FlowContext.Provider value={{
|
<FlowContext.Provider value={{
|
||||||
|
workflow,
|
||||||
nodes,
|
nodes,
|
||||||
onNodeAdded: refresh,
|
onNodeAdded: refresh,
|
||||||
onNodeRemoved: refresh
|
onNodeRemoved: refresh
|
||||||
|
@ -4,6 +4,7 @@ import { css } from "@emotion/css";
|
|||||||
|
|
||||||
import { instructions, useNodeContext } from "./nodes";
|
import { instructions, useNodeContext } from "./nodes";
|
||||||
import { useFlowContext } from "./WorkflowCanvas";
|
import { useFlowContext } from "./WorkflowCanvas";
|
||||||
|
import { triggers } from "./triggers";
|
||||||
|
|
||||||
function NullRender() {
|
function NullRender() {
|
||||||
return null;
|
return null;
|
||||||
@ -68,6 +69,8 @@ export function parseStringValue(value: string, Types) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const BaseTypeSet = new Set(['boolean', 'number', 'string', 'date']);
|
||||||
|
|
||||||
const ConstantTypes = {
|
const ConstantTypes = {
|
||||||
string: {
|
string: {
|
||||||
title: '字符串',
|
title: '字符串',
|
||||||
@ -189,7 +192,25 @@ export const VariableTypes = {
|
|||||||
return `{{${stack.join('.')}}}`;
|
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
|
// calculation: Calculation
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -205,10 +226,15 @@ interface OperandProps {
|
|||||||
value?: any;
|
value?: any;
|
||||||
options?: 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 Types = useVariableTypes();
|
||||||
|
|
||||||
const { type } = operand;
|
const { type } = operand;
|
||||||
@ -226,13 +252,13 @@ export function Operand({ onChange, value: operand = { type: 'constant', value:
|
|||||||
allowClear={false}
|
allowClear={false}
|
||||||
value={[type, ...(appendTypeValue ? appendTypeValue(operand) : [])]}
|
value={[type, ...(appendTypeValue ? appendTypeValue(operand) : [])]}
|
||||||
options={Object.values(Types).map((item: any) => {
|
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 {
|
return {
|
||||||
label: item.title,
|
label: item.title,
|
||||||
value: item.value,
|
value: item.value,
|
||||||
children,
|
children: options,
|
||||||
disabled: children && !children.length,
|
disabled: options && !options.length,
|
||||||
isLeaf: !children
|
isLeaf: !options
|
||||||
};
|
};
|
||||||
})}
|
})}
|
||||||
onChange={(next: Array<string | number>) => {
|
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>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ export default {
|
|||||||
{ label: '分支模式', key: 'branch', value: { rejectOnFalse: false } }
|
{ label: '分支模式', key: 'branch', value: { rejectOnFalse: false } }
|
||||||
],
|
],
|
||||||
render(data) {
|
render(data) {
|
||||||
const { id, config: { calculation, rejectOnFalse } } = data;
|
const { id, config: { rejectOnFalse } } = data;
|
||||||
const { nodes } = useFlowContext();
|
const { nodes } = useFlowContext();
|
||||||
const trueEntry = nodes.find(item => item.upstreamId === id && item.branchIndex === 1);
|
const trueEntry = nodes.find(item => item.upstreamId === id && item.branchIndex === 1);
|
||||||
const falseEntry = nodes.find(item => item.upstreamId === id && item.branchIndex === 0);
|
const falseEntry = nodes.find(item => item.upstreamId === id && item.branchIndex === 0);
|
||||||
|
@ -8,9 +8,7 @@ import { css } from '@emotion/css';
|
|||||||
import { useCollectionManager } from '../..';
|
import { useCollectionManager } from '../..';
|
||||||
import { useCollectionFilterOptions } from '../../collection-manager/action-hooks';
|
import { useCollectionFilterOptions } from '../../collection-manager/action-hooks';
|
||||||
import { useFlowContext } from '../WorkflowCanvas';
|
import { useFlowContext } from '../WorkflowCanvas';
|
||||||
import { Operand, parseStringValue, VariableTypes, VariableTypesContext } from '../calculators';
|
import { Operand, parseStringValue, VariableTypes, VariableTypesContext, BaseTypeSet } from '../calculators';
|
||||||
|
|
||||||
const BaseTypeSet = new Set(['boolean', 'number', 'string', 'date']);
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: '数据查询',
|
title: '数据查询',
|
||||||
@ -89,10 +87,7 @@ export default {
|
|||||||
constant: {
|
constant: {
|
||||||
title: '常量',
|
title: '常量',
|
||||||
value: 'constant',
|
value: 'constant',
|
||||||
options: undefined,
|
options: undefined
|
||||||
component() {
|
|
||||||
return renderSchemaComponent;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -112,7 +107,9 @@ export default {
|
|||||||
onChange(stringify(next));
|
onChange(stringify(next));
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
>
|
||||||
|
{operand.type === 'constant' ? renderSchemaComponent() : null}
|
||||||
|
</Operand>
|
||||||
</VariableTypesContext.Provider>
|
</VariableTypesContext.Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useForm } from "@formily/react";
|
import { ISchema, useForm } from "@formily/react";
|
||||||
import { cx } from "@emotion/css";
|
import { cx } from "@emotion/css";
|
||||||
|
import { Registry } from "@nocobase/utils";
|
||||||
|
|
||||||
import { SchemaComponent, useActionContext, useAPIClient, useRecord, useResourceActionContext } from '../../';
|
import { SchemaComponent, useActionContext, useAPIClient, useRecord, useResourceActionContext } from '../../';
|
||||||
import model from './model';
|
import model from './model';
|
||||||
@ -30,18 +31,30 @@ function useUpdateConfigAction() {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface Trigger {
|
||||||
const triggerTypes = {
|
title: string;
|
||||||
model
|
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 = () => {
|
export const TriggerConfig = () => {
|
||||||
const { data } = useResourceActionContext();
|
const { data } = useResourceActionContext();
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const { type, config } = data.data;
|
const { type, config } = data.data;
|
||||||
const { title, fieldset, scope } = triggerTypes[type];
|
const { title, fieldset, scope } = triggers.get(type);
|
||||||
return (
|
return (
|
||||||
<div className={cx(nodeCardClass)}>
|
<div className={cx(nodeCardClass)}>
|
||||||
<h4>{title}</h4>
|
<h4>{title}</h4>
|
||||||
|
@ -1,9 +1,15 @@
|
|||||||
|
import React from 'react';
|
||||||
import { action } from '@formily/reactive';
|
import { action } from '@formily/reactive';
|
||||||
import { t } from 'i18next';
|
import { t } from 'i18next';
|
||||||
|
import { Select } from 'antd';
|
||||||
|
|
||||||
import { useCollectionManager } from '../../collection-manager';
|
import { useCollectionManager } from '../../collection-manager';
|
||||||
|
import { useFlowContext } from '../WorkflowCanvas';
|
||||||
|
import { BaseTypeSet } from '../calculators';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: '数据表事件',
|
title: '数据表事件',
|
||||||
|
type: 'model',
|
||||||
fieldset: {
|
fieldset: {
|
||||||
collection: {
|
collection: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@ -32,5 +38,22 @@ export default {
|
|||||||
})(collections);
|
})(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>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user