Feat(plugin workflow): add changed fields to model trigger config (#332)
* feat(plugin-workflow): add changed fields to model trigger config * fix(plugin-workflow): avoid system fields to input
This commit is contained in:
parent
27399f4e5e
commit
f5cc368cef
@ -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] };
|
||||
|
@ -12,8 +12,8 @@ export default {
|
||||
group: 'model',
|
||||
fieldset: {
|
||||
'config.collection': {
|
||||
name: 'config.collection',
|
||||
...collection,
|
||||
name: 'config.collection'
|
||||
},
|
||||
// multiple: {
|
||||
// type: 'boolean',
|
||||
|
@ -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<Field>();
|
||||
|
||||
return (
|
||||
<RecursionField basePath={field.address} schema={schema} />
|
||||
);
|
||||
}
|
||||
|
||||
export function NodeDefaultView(props) {
|
||||
const { data, children } = props;
|
||||
const instruction = instructions.get(data.type);
|
||||
@ -174,10 +162,7 @@ export function NodeDefaultView(props) {
|
||||
</div>
|
||||
<SchemaComponent
|
||||
scope={instruction.scope}
|
||||
components={{
|
||||
...instruction.components,
|
||||
Fieldset
|
||||
}}
|
||||
components={instruction.components}
|
||||
schema={{
|
||||
type: 'void',
|
||||
properties: {
|
||||
@ -197,9 +182,9 @@ export function NodeDefaultView(props) {
|
||||
'x-decorator': 'Form',
|
||||
'x-decorator-props': {
|
||||
useValues(options) {
|
||||
const data = useNodeContext();
|
||||
const d = useNodeContext();
|
||||
return useRequest(() => {
|
||||
return Promise.resolve({ data });
|
||||
return Promise.resolve({ data: d });
|
||||
}, options);
|
||||
}
|
||||
},
|
||||
|
@ -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`
|
||||
|
@ -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',
|
||||
|
@ -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();
|
||||
|
@ -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 } = <typeof WorkflowModel>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));
|
||||
}
|
||||
}
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user