diff --git a/packages/core/client/src/workflow/calculators.tsx b/packages/core/client/src/workflow/calculators.tsx index bd611829b..a7e0cf330 100644 --- a/packages/core/client/src/workflow/calculators.tsx +++ b/packages/core/client/src/workflow/calculators.tsx @@ -395,12 +395,7 @@ export const CollectionFieldset = observer(({ value, onChange, useProps }: any) } `}> {fields.length - ? fields - .filter(field => ( - !field.hidden - && (field.uiSchema ? !field.uiSchema['x-read-pretty'] : true) - )) - .map(field => { + ? fields.map(field => { const operand = typeof value[field.name] === 'string' ? parseStringValue(value[field.name], VTypes) : { type: 'constant', value: value[field.name] }; diff --git a/packages/core/client/src/workflow/nodes/create.tsx b/packages/core/client/src/workflow/nodes/create.tsx index 8c4d11446..94edd1aa2 100644 --- a/packages/core/client/src/workflow/nodes/create.tsx +++ b/packages/core/client/src/workflow/nodes/create.tsx @@ -12,8 +12,8 @@ export default { group: 'model', fieldset: { 'config.collection': { - name: 'config.collection', ...collection, + name: 'config.collection' }, // multiple: { // type: 'boolean', diff --git a/packages/core/client/src/workflow/nodes/index.tsx b/packages/core/client/src/workflow/nodes/index.tsx index 52a04fc83..4e7fa3605 100644 --- a/packages/core/client/src/workflow/nodes/index.tsx +++ b/packages/core/client/src/workflow/nodes/index.tsx @@ -1,13 +1,13 @@ import { CloseOutlined, DeleteOutlined } from '@ant-design/icons'; import { css, cx } from '@emotion/css'; -import { Field } from '@formily/core'; -import { ISchema, RecursionField, useField, useForm } from '@formily/react'; +import { ISchema, useForm } from '@formily/react'; import { Registry } from '@nocobase/utils'; import { Button, Modal, Tag } from 'antd'; import React, { useContext } from 'react'; import { SchemaComponent, useActionContext, useAPIClient, useCollection, useRequest, useResourceActionContext } from '../..'; import { nodeBlockClass, nodeCardClass, nodeClass, nodeHeaderClass, nodeTitleClass } from '../style'; import { AddButton, useFlowContext } from '../WorkflowCanvas'; + import calculation from './calculation'; import condition from './condition'; import create from './create'; @@ -18,10 +18,6 @@ import update from './update'; - - - - export interface Instruction { title: string; type: string; @@ -148,14 +144,6 @@ export function RemoveButton() { ); } -function Fieldset({ schema }) { - const field = useField(); - - return ( - - ); -} - export function NodeDefaultView(props) { const { data, children } = props; const instruction = instructions.get(data.type); @@ -174,10 +162,7 @@ export function NodeDefaultView(props) { { - return Promise.resolve({ data }); + return Promise.resolve({ data: d }); }, options); } }, diff --git a/packages/core/client/src/workflow/schemas/collection.ts b/packages/core/client/src/workflow/schemas/collection.ts index 21e6fae8b..62353a50b 100644 --- a/packages/core/client/src/workflow/schemas/collection.ts +++ b/packages/core/client/src/workflow/schemas/collection.ts @@ -29,7 +29,11 @@ export const values = { useProps() { const { getCollectionFields } = useCollectionManager(); const { values: form } = useForm(); - const fields = getCollectionFields(form?.config?.collection); + const fields = getCollectionFields(form?.config?.collection) + .filter(field => ( + !field.hidden + && (field.uiSchema ? !field.uiSchema['x-read-pretty'] : false) + )); return { fields }; } } @@ -50,7 +54,7 @@ export const filter = { 'x-component-props': { useProps() { const { values } = useForm(); - const options = useCollectionFilterOptions(values.config.collection); + const options = useCollectionFilterOptions(values.config?.collection); return { options, className: css` diff --git a/packages/core/client/src/workflow/triggers/index.tsx b/packages/core/client/src/workflow/triggers/index.tsx index e24b643cb..7ae927724 100644 --- a/packages/core/client/src/workflow/triggers/index.tsx +++ b/packages/core/client/src/workflow/triggers/index.tsx @@ -3,7 +3,7 @@ import { ISchema, useForm } from "@formily/react"; import { cx } from "@emotion/css"; import { Registry } from "@nocobase/utils"; -import { SchemaComponent, useActionContext, useAPIClient, useRecord, useResourceActionContext } from '../../'; +import { SchemaComponent, useActionContext, useAPIClient, useRecord, useRequest, useResourceActionContext } from '../../'; import model from './model'; import { nodeCardClass } from "../style"; @@ -19,12 +19,7 @@ function useUpdateConfigAction() { await form.submit(); await api.resource('workflows', record.id).update({ filterByTk: record.id, - values: { - config: { - ...record.config, - ...form.values - } - }, + values: form.values }); ctx.setVisible(false); refresh(); @@ -72,10 +67,16 @@ export const TriggerConfig = () => { 'x-component': 'Action.Drawer', 'x-decorator': 'Form', 'x-decorator-props': { - initialValue: config + initialValue: { config } }, properties: { - ...fieldset, + config: { + type: 'void', + name: 'config', + 'x-component': 'fieldset', + 'x-component-props': {}, + properties: fieldset + }, actions: { type: 'void', 'x-component': 'Action.Drawer.Footer', diff --git a/packages/core/client/src/workflow/triggers/model.tsx b/packages/core/client/src/workflow/triggers/model.tsx index b1206e373..37ce0d892 100644 --- a/packages/core/client/src/workflow/triggers/model.tsx +++ b/packages/core/client/src/workflow/triggers/model.tsx @@ -1,5 +1,7 @@ import React from 'react'; import { Select } from 'antd'; +import { action } from '@formily/reactive'; +import { useForm } from '@formily/react'; import { useCollectionDataSource, useCollectionManager } from '../../collection-manager'; import { useCompile } from '../../schema-component'; @@ -8,15 +10,36 @@ import { useFlowContext } from '../WorkflowCanvas'; import { BaseTypeSet } from '../calculators'; import { collection, filter } from '../schemas/collection'; +function useCollectionFieldsDataSource() { + const compile = useCompile(); + const { getCollectionFields } = useCollectionManager(); + const { values } = useForm(); + const fields = getCollectionFields(values?.config?.collection); + + return (field: any) => { + action.bound((data: any) => { + field.dataSource = data + .filter(field => ( + !field.hidden + && (field.uiSchema ? !field.uiSchema['x-read-pretty'] : true) + )) + .map(field => ({ + label: compile(field.uiSchema?.title), + value: field.name + })); + })(fields); + }; +} + export default { title: '数据表事件', type: 'model', fieldset: { - collection, - mode: { + 'config.collection': collection, + 'config.mode': { type: 'number', title: '触发时机', - name: 'mode', + name: 'config.mode', 'x-decorator': 'FormItem', 'x-component': 'Select', 'x-component-props': { @@ -28,13 +51,29 @@ export default { ] } }, - filter: { + 'config.changed': { + type: 'array', + name: 'changed', + title: '发生变动的字段', + description: '只有被选中的某个字段发生变动时才会触发。如果不选择,则表示任何字段变动时都会触发。新增或删除数据时,任意字段都被认为发生变动。', + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-component-props': { + mode: 'multiple', + }, + 'x-reactions': [ + '{{useCollectionFieldsDataSource()}}' + ] + }, + 'config.condition': { ...filter, + name: 'config.condition', title: '满足条件' } }, scope: { - useCollectionDataSource + useCollectionDataSource, + useCollectionFieldsDataSource }, getter({ type, options, onChange }) { const compile = useCompile(); diff --git a/packages/plugins/workflow/src/triggers/model.ts b/packages/plugins/workflow/src/triggers/model.ts index 993e565c7..ff1bb0d49 100644 --- a/packages/plugins/workflow/src/triggers/model.ts +++ b/packages/plugins/workflow/src/triggers/model.ts @@ -4,7 +4,7 @@ export interface ModelChangeTriggerConfig { collection: string; mode: number; // TODO: ICondition - filter: any; + condition: any; } const MODE_BITMAP = { @@ -18,26 +18,37 @@ MODE_BITMAP_EVENTS.set(MODE_BITMAP.CREATE, 'afterCreate'); MODE_BITMAP_EVENTS.set(MODE_BITMAP.UPDATE, 'afterUpdate'); MODE_BITMAP_EVENTS.set(MODE_BITMAP.DESTROY, 'afterDestroy'); +// async function, should return promise +function bindHandler(this: WorkflowModel, callback: Function) { + const { condition, changed } = this.config; + return (data: any, options) => { + // NOTE: if no configured fields changed, do not trigger + if (changed && changed.length && changed.every(name => !data.changed(name))) { + return; + } + // NOTE: if no configured condition match, do not trigger + if (condition && condition.$and.length) { + // TODO: check all conditions in condition against data + // const calculation = toCalculation(condition); + } + + return callback({ data: data.get() }, options); + }; +} + export default { name: 'model', on(this: WorkflowModel, callback: Function) { const { database } = this.constructor; - const { collection, mode, filter } = this.config; + const { collection, mode } = this.config; const Collection = database.getCollection(collection); if (!Collection) { return; } - // async function, should return promise - const handler = (data: any, options) => { - if (filter) { - // TODO: check all conditions in filter against data - } - return callback({ data: data.get() }, options); - }; // TODO: duplication when mode change should be considered for (let [key, event] of MODE_BITMAP_EVENTS.entries()) { if (mode & key) { - Collection.model.addHook(event, this.getHookId(), handler); + Collection.model.addHook(event, this.getHookId(), bindHandler.call(this, callback)); } } },