fix(plugin-workflow): fix variables and form changed (#2955)

This commit is contained in:
Junyi 2023-11-03 20:08:11 +08:00 committed by GitHub
parent 3220173e83
commit 1f9dae6ebd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 218 additions and 155 deletions

View File

@ -106,7 +106,7 @@ const WithForm = (props: WithFormProps) => {
return () => { return () => {
form.removeEffects(id); form.removeEffects(id);
}; };
}, [props.disabled]); }, [form, props.disabled, setFormValueChanged]);
useEffect(() => { useEffect(() => {
const id = uid(); const id = uid();

View File

@ -1,5 +1,5 @@
import { FormItem, FormLayout } from '@formily/antd-v5'; import { FormItem, FormLayout } from '@formily/antd-v5';
import { SchemaInitializerItemOptions, Variable, css, defaultFieldNames, useCollectionManager } from '@nocobase/client'; import { SchemaInitializerItemOptions, Variable, defaultFieldNames, useCollectionManager } from '@nocobase/client';
import { Evaluator, evaluators, getOptions } from '@nocobase/evaluators/client'; import { Evaluator, evaluators, getOptions } from '@nocobase/evaluators/client';
import { Radio } from 'antd'; import { Radio } from 'antd';
import React from 'react'; import React from 'react';
@ -8,7 +8,7 @@ import { RadioWithTooltip } from '../components/RadioWithTooltip';
import { ValueBlock } from '../components/ValueBlock'; import { ValueBlock } from '../components/ValueBlock';
import { renderEngineReference } from '../components/renderEngineReference'; import { renderEngineReference } from '../components/renderEngineReference';
import { NAMESPACE, lang } from '../locale'; import { NAMESPACE, lang } from '../locale';
import { BaseTypeSets, useWorkflowVariableOptions } from '../variable'; import { BaseTypeSets, WorkflowVariableInput, WorkflowVariableTextArea, useWorkflowVariableOptions } from '../variable';
function useDynamicExpressionCollectionFieldMatcher(field): boolean { function useDynamicExpressionCollectionFieldMatcher(field): boolean {
if (!['belongsTo', 'hasOne'].includes(field.type)) { if (!['belongsTo', 'hasOne'].includes(field.type)) {
@ -93,13 +93,10 @@ export default {
type: 'string', type: 'string',
title: `{{t("Calculation expression", { ns: "${NAMESPACE}" })}}`, title: `{{t("Calculation expression", { ns: "${NAMESPACE}" })}}`,
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'CalculationExpression', 'x-component': 'WorkflowVariableTextArea',
// NOTE: can not use Variable.Input and scope directly as below, 'x-component-props': {
// because the scope will be cached. changeOnSelect: true,
// 'x-component': 'Variable.Input', },
// 'x-component-props': {
// scope: '{{useWorkflowVariableOptions()}}',
// },
['x-validator'](value, rules, { form }) { ['x-validator'](value, rules, { form }) {
const { values } = form; const { values } = form;
const { evaluate } = evaluators.get(values.engine) as Evaluator; const { evaluate } = evaluators.get(values.engine) as Evaluator;
@ -135,9 +132,12 @@ export default {
type: 'string', type: 'string',
title: `{{t("Variable datasource", { ns: "${NAMESPACE}" })}}`, title: `{{t("Variable datasource", { ns: "${NAMESPACE}" })}}`,
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'ScopeSelect', 'x-component': 'WorkflowVariableInput',
'x-component-props': { 'x-component-props': {
changeOnSelect: true, changeOnSelect: true,
variableOptions: {
types: [{ type: 'reference', options: { collection: '*', entity: true } }],
},
}, },
'x-reactions': { 'x-reactions': {
dependencies: ['dynamic'], dependencies: ['dynamic'],
@ -154,17 +154,8 @@ export default {
renderEngineReference, renderEngineReference,
}, },
components: { components: {
CalculationExpression(props) { WorkflowVariableInput,
const scope = useWorkflowVariableOptions(); WorkflowVariableTextArea,
return <Variable.TextArea scope={scope} changeOnSelect {...props} />;
},
ScopeSelect(props) {
const scope = useWorkflowVariableOptions({
types: [{ type: 'reference', options: { collection: '*', entity: true } }],
});
return <Variable.Input scope={scope} {...props} />;
},
RadioWithTooltip, RadioWithTooltip,
DynamicConfig, DynamicConfig,
ValueBlock, ValueBlock,

View File

@ -1,5 +1,11 @@
import { CloseOutlined, DeleteOutlined } from '@ant-design/icons'; import React, { useCallback, useContext, useMemo, useState } from 'react';
import { DeleteOutlined } from '@ant-design/icons';
import { cloneDeep } from 'lodash';
import { createForm } from '@formily/core';
import { ISchema, useForm } from '@formily/react'; import { ISchema, useForm } from '@formily/react';
import { App, Button, Dropdown, Input, Tag, Tooltip, message } from 'antd';
import { useTranslation } from 'react-i18next';
import { import {
ActionContextProvider, ActionContextProvider,
SchemaComponent, SchemaComponent,
@ -9,13 +15,10 @@ import {
useAPIClient, useAPIClient,
useActionContext, useActionContext,
useCompile, useCompile,
useRequest,
useResourceActionContext, useResourceActionContext,
} from '@nocobase/client'; } from '@nocobase/client';
import { Registry, parse, str2moment } from '@nocobase/utils/client'; import { Registry, parse, str2moment } from '@nocobase/utils/client';
import { App, Button, Dropdown, Input, Tag, Tooltip, message } from 'antd';
import React, { useContext, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { AddButton } from '../AddButton'; import { AddButton } from '../AddButton';
import { useFlowContext } from '../FlowContext'; import { useFlowContext } from '../FlowContext';
import { DrawerDescription } from '../components/DrawerDescription'; import { DrawerDescription } from '../components/DrawerDescription';
@ -25,6 +28,7 @@ import { useGetAriaLabelOfAddButton } from '../hooks/useGetAriaLabelOfAddButton'
import { lang } from '../locale'; import { lang } from '../locale';
import useStyles from '../style'; import useStyles from '../style';
import { VariableOption, VariableOptions } from '../variable'; import { VariableOption, VariableOptions } from '../variable';
import aggregate from './aggregate'; import aggregate from './aggregate';
import calculation from './calculation'; import calculation from './calculation';
import condition from './condition'; import condition from './condition';
@ -96,6 +100,7 @@ function useUpdateAction() {
config: form.values, config: form.values,
}, },
}); });
ctx.setFormValueChanged(false);
ctx.setVisible(false); ctx.setVisible(false);
refresh(); refresh();
}, },
@ -281,23 +286,46 @@ export function NodeDefaultView(props) {
const [editingTitle, setEditingTitle] = useState<string>(data.title ?? typeTitle); const [editingTitle, setEditingTitle] = useState<string>(data.title ?? typeTitle);
const [editingConfig, setEditingConfig] = useState(false); const [editingConfig, setEditingConfig] = useState(false);
const [formValueChanged, setFormValueChanged] = useState(false);
async function onChangeTitle(next) { const form = useMemo(() => {
const title = next || typeTitle; const values = cloneDeep(data.config);
setEditingTitle(title); return createForm({
if (title === data.title) { initialValues: values,
return; values,
} disabled: workflow.executed,
await api.resource('flow_nodes').update?.({
filterByTk: data.id,
values: {
title,
},
}); });
refresh(); }, [data, workflow]);
}
function onOpenDrawer(ev) { const resetForm = useCallback(
(changed) => {
setFormValueChanged(changed);
if (!changed) {
form.reset();
}
},
[form],
);
const onChangeTitle = useCallback(
async function (next) {
const title = next || typeTitle;
setEditingTitle(title);
if (title === data.title) {
return;
}
await api.resource('flow_nodes').update?.({
filterByTk: data.id,
values: {
title,
},
});
refresh();
},
[data],
);
const onOpenDrawer = useCallback(function (ev) {
if (ev.target === ev.currentTarget) { if (ev.target === ev.currentTarget) {
setEditingConfig(true); setEditingConfig(true);
return; return;
@ -310,7 +338,7 @@ export function NodeDefaultView(props) {
return; return;
} }
} }
} }, []);
return ( return (
<div className={cx(styles.nodeClass, `workflow-node-type-${data.type}`)}> <div className={cx(styles.nodeClass, `workflow-node-type-${data.type}`)}>
@ -324,20 +352,25 @@ export function NodeDefaultView(props) {
<Tag>{typeTitle}</Tag> <Tag>{typeTitle}</Tag>
<span className="workflow-node-id">{data.id}</span> <span className="workflow-node-id">{data.id}</span>
</div> </div>
<div> <Input.TextArea
<Input.TextArea role="button"
role="button" aria-label="textarea"
aria-label="textarea" disabled={workflow.executed}
disabled={workflow.executed} value={editingTitle}
value={editingTitle} onChange={(ev) => setEditingTitle(ev.target.value)}
onChange={(ev) => setEditingTitle(ev.target.value)} onBlur={(ev) => onChangeTitle(ev.target.value)}
onBlur={(ev) => onChangeTitle(ev.target.value)} autoSize
autoSize />
/>
</div>
<RemoveButton /> <RemoveButton />
<JobButton /> <JobButton />
<ActionContextProvider value={{ visible: editingConfig, setVisible: setEditingConfig }}> <ActionContextProvider
value={{
visible: editingConfig,
setVisible: setEditingConfig,
formValueChanged,
setFormValueChanged: resetForm,
}}
>
<SchemaComponent <SchemaComponent
scope={instruction.scope} scope={instruction.scope}
components={instruction.components} components={instruction.components}
@ -383,17 +416,11 @@ export function NodeDefaultView(props) {
</Tooltip> </Tooltip>
</div> </div>
), ),
'x-component': 'Action.Drawer', 'x-decorator': 'FormV2',
'x-decorator': 'Form',
'x-decorator-props': { 'x-decorator-props': {
disabled: workflow.executed, form,
useValues(options) {
const { config } = useNodeContext();
return useRequest(() => {
return Promise.resolve({ data: config });
}, options);
},
}, },
'x-component': 'Action.Drawer',
properties: { properties: {
...(instruction.description ...(instruction.description
? { ? {

View File

@ -1,18 +1,14 @@
import { ArrowUpOutlined } from '@ant-design/icons';
import { css, cx, useCompile } from '@nocobase/client';
import React from 'react'; import React from 'react';
import { ArrowUpOutlined } from '@ant-design/icons';
import { css, cx, useCompile } from '@nocobase/client';
import { NodeDefaultView } from '.'; import { NodeDefaultView } from '.';
import { Branch } from '../Branch'; import { Branch } from '../Branch';
import { useFlowContext } from '../FlowContext'; import { useFlowContext } from '../FlowContext';
import { NAMESPACE, lang } from '../locale'; import { NAMESPACE, lang } from '../locale';
import useStyles from '../style'; import useStyles from '../style';
import { import { VariableOption, WorkflowVariableInput, defaultFieldNames, nodesOptions, triggerOptions } from '../variable';
VariableOption,
defaultFieldNames,
nodesOptions,
triggerOptions,
useWorkflowVariableOptions,
} from '../variable';
function findOption(options: VariableOption[], paths: string[]) { function findOption(options: VariableOption[], paths: string[]) {
let opts = options; let opts = options;
@ -45,9 +41,8 @@ export default {
title: `{{t("Loop target", { ns: "${NAMESPACE}" })}}`, title: `{{t("Loop target", { ns: "${NAMESPACE}" })}}`,
description: `{{t("A single number will be treated as a loop count, a single string will be treated as an array of characters, and other non-array values will be converted to arrays. The loop node ends when the loop count is reached, or when the array loop is completed. You can also add condition nodes to the loop to terminate it.", { ns: "${NAMESPACE}" })}}`, description: `{{t("A single number will be treated as a loop count, a single string will be treated as an array of characters, and other non-array values will be converted to arrays. The loop node ends when the loop count is reached, or when the array loop is completed. You can also add condition nodes to the loop to terminate it.", { ns: "${NAMESPACE}" })}}`,
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Variable.Input', 'x-component': 'WorkflowVariableInput',
'x-component-props': { 'x-component-props': {
scope: '{{useWorkflowVariableOptions()}}',
changeOnSelect: true, changeOnSelect: true,
useTypedConstant: ['string', 'number', 'null'], useTypedConstant: ['string', 'number', 'null'],
className: css` className: css`
@ -95,10 +90,10 @@ export default {
</NodeDefaultView> </NodeDefaultView>
); );
}, },
scope: { scope: {},
useWorkflowVariableOptions, components: {
WorkflowVariableInput,
}, },
components: {},
useScopeVariables(node, options) { useScopeVariables(node, options) {
const compile = useCompile(); const compile = useCompile();
const { target } = node.config; const { target } = node.config;

View File

@ -12,7 +12,7 @@ import { appends, collection, filter, pagination, sort } from '../schemas/collec
import { NAMESPACE } from '../locale'; import { NAMESPACE } from '../locale';
import { CollectionBlockInitializer } from '../components/CollectionBlockInitializer'; import { CollectionBlockInitializer } from '../components/CollectionBlockInitializer';
import { FilterDynamicComponent } from '../components/FilterDynamicComponent'; import { FilterDynamicComponent } from '../components/FilterDynamicComponent';
import { getCollectionFieldOptions, useWorkflowVariableOptions } from '../variable'; import { WorkflowVariableInput, getCollectionFieldOptions } from '../variable';
import { useForm } from '@formily/react'; import { useForm } from '@formily/react';
export default { export default {
@ -59,7 +59,6 @@ export default {
view: {}, view: {},
scope: { scope: {
useCollectionDataSource, useCollectionDataSource,
useWorkflowVariableOptions,
useSortableFields() { useSortableFields() {
const compile = useCompile(); const compile = useCompile();
const { getCollectionFields, getInterface } = useCollectionManager(); const { getCollectionFields, getInterface } = useCollectionManager();
@ -88,6 +87,7 @@ export default {
ArrayItems, ArrayItems,
FilterDynamicComponent, FilterDynamicComponent,
SchemaComponentContext, SchemaComponentContext,
WorkflowVariableInput,
}, },
useVariables({ key: name, title, config }, options) { useVariables({ key: name, title, config }, options) {
const compile = useCompile(); const compile = useCompile();

View File

@ -1,9 +1,8 @@
import { ArrayItems } from '@formily/antd-v5'; import { ArrayItems } from '@formily/antd-v5';
import React from 'react';
import { Variable } from '@nocobase/client'; import { defaultFieldNames } from '@nocobase/client';
import { NAMESPACE } from '../locale'; import { NAMESPACE } from '../locale';
import { useWorkflowVariableOptions } from '../variable'; import { WorkflowVariableInput } from '../variable';
export default { export default {
title: `{{t("HTTP request", { ns: "${NAMESPACE}" })}}`, title: `{{t("HTTP request", { ns: "${NAMESPACE}" })}}`,
@ -66,9 +65,8 @@ export default {
value: { value: {
type: 'string', type: 'string',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Variable.Input', 'x-component': 'WorkflowVariableInput',
'x-component-props': { 'x-component-props': {
scope: '{{useWorkflowVariableOptions()}}',
useTypedConstant: true, useTypedConstant: true,
}, },
}, },
@ -112,9 +110,8 @@ export default {
value: { value: {
type: 'string', type: 'string',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Variable.Input', 'x-component': 'WorkflowVariableInput',
'x-component-props': { 'x-component-props': {
scope: '{{useWorkflowVariableOptions()}}',
useTypedConstant: true, useTypedConstant: true,
}, },
}, },
@ -140,7 +137,7 @@ export default {
title: `{{t("Body", { ns: "${NAMESPACE}" })}}`, title: `{{t("Body", { ns: "${NAMESPACE}" })}}`,
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-decorator-props': {}, 'x-decorator-props': {},
'x-component': 'RequestBody', 'x-component': 'WorkflowVariableJSON',
'x-component-props': { 'x-component-props': {
changeOnSelect: true, changeOnSelect: true,
autoSize: { autoSize: {
@ -171,14 +168,15 @@ export default {
}, },
}, },
view: {}, view: {},
scope: { scope: {},
useWorkflowVariableOptions,
},
components: { components: {
ArrayItems, ArrayItems,
RequestBody(props) { WorkflowVariableInput,
const scope = useWorkflowVariableOptions(); },
return <Variable.JSON scope={scope} {...props} />; useVariables({ key, title }, { types, fieldNames = defaultFieldNames }) {
}, return {
[fieldNames.value]: key,
[fieldNames.label]: title,
};
}, },
}; };

View File

@ -1,9 +1,7 @@
import React from 'react'; import { css, defaultFieldNames } from '@nocobase/client';
import { Variable, css } from '@nocobase/client';
import { NAMESPACE } from '../locale'; import { NAMESPACE } from '../locale';
import { useWorkflowVariableOptions } from '../variable'; import { WorkflowVariableRawTextArea } from '../variable';
export default { export default {
title: `{{t("SQL action", { ns: "${NAMESPACE}" })}}`, title: `{{t("SQL action", { ns: "${NAMESPACE}" })}}`,
@ -17,7 +15,7 @@ export default {
title: 'SQL', title: 'SQL',
description: `{{t("Usage of SQL query result is not supported yet.", { ns: "${NAMESPACE}" })}}`, description: `{{t("Usage of SQL query result is not supported yet.", { ns: "${NAMESPACE}" })}}`,
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'SQLInput', 'x-component': 'WorkflowVariableRawTextArea',
'x-component-props': { 'x-component-props': {
rows: 20, rows: 20,
className: css` className: css`
@ -29,9 +27,12 @@ export default {
}, },
scope: {}, scope: {},
components: { components: {
SQLInput(props) { WorkflowVariableRawTextArea,
const scope = useWorkflowVariableOptions(); },
return <Variable.RawTextArea scope={scope} {...props} />; useVariables({ key, title }, { types, fieldNames = defaultFieldNames }) {
}, return {
[fieldNames.value]: key,
[fieldNames.label]: title,
};
}, },
}; };

View File

@ -135,9 +135,8 @@ export const pagination = {
type: 'number', type: 'number',
title: '{{t("Page number")}}', title: '{{t("Page number")}}',
'x-decorator': 'FormItem', 'x-decorator': 'FormItem',
'x-component': 'Variable.Input', 'x-component': 'WorkflowVariableInput',
'x-component-props': { 'x-component-props': {
scope: '{{useWorkflowVariableOptions()}}',
useTypedConstant: ['number', 'null'], useTypedConstant: ['number', 'null'],
}, },
default: 1, default: 1,

View File

@ -14,7 +14,7 @@ import {
} from '@nocobase/client'; } from '@nocobase/client';
import { Registry } from '@nocobase/utils/client'; import { Registry } from '@nocobase/utils/client';
import { Button, Input, Tag, message } from 'antd'; import { Button, Input, Tag, message } from 'antd';
import React, { useEffect, useMemo, useState } from 'react'; import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { useFlowContext } from '../FlowContext'; import { useFlowContext } from '../FlowContext';
import { DrawerDescription } from '../components/DrawerDescription'; import { DrawerDescription } from '../components/DrawerDescription';
import { NAMESPACE, lang } from '../locale'; import { NAMESPACE, lang } from '../locale';
@ -23,6 +23,7 @@ import { VariableOptions } from '../variable';
import collection from './collection'; import collection from './collection';
import formTrigger from './form'; import formTrigger from './form';
import schedule from './schedule/'; import schedule from './schedule/';
import { cloneDeep } from 'lodash';
function useUpdateConfigAction() { function useUpdateConfigAction() {
const form = useForm(); const form = useForm();
@ -43,6 +44,7 @@ function useUpdateConfigAction() {
config: form.values, config: form.values,
}, },
}); });
ctx.setFormValueChanged(false);
ctx.setVisible(false); ctx.setVisible(false);
refresh(); refresh();
}, },
@ -146,50 +148,61 @@ export const TriggerConfig = () => {
const { workflow, refresh } = useFlowContext(); const { workflow, refresh } = useFlowContext();
const [editingTitle, setEditingTitle] = useState<string>(''); const [editingTitle, setEditingTitle] = useState<string>('');
const [editingConfig, setEditingConfig] = useState(false); const [editingConfig, setEditingConfig] = useState(false);
const [formValueChanged, setFormValueChanged] = useState(false);
const { styles } = useStyles(); const { styles } = useStyles();
let typeTitle = ''; const compile = useCompile();
const { title, type, executed } = workflow;
const trigger = triggers.get(type);
const typeTitle = compile(trigger.title);
const { fieldset, scope, components } = trigger;
const detailText = executed ? '{{t("View")}}' : '{{t("Configure")}}';
const titleText = lang('Trigger');
useEffect(() => { useEffect(() => {
if (workflow) { if (workflow) {
setEditingTitle(workflow.title ?? typeTitle); setEditingTitle(workflow.title ?? typeTitle);
} }
}, [workflow]); }, [workflow]);
const form = useMemo( const form = useMemo(() => {
() => const values = cloneDeep(workflow?.config);
createForm({ return createForm({
initialValues: workflow?.config, initialValues: values,
values: workflow?.config, values,
disabled: workflow?.executed, disabled: workflow?.executed,
}), });
}, [workflow]);
const resetForm = useCallback(
(changed) => {
setFormValueChanged(changed);
if (!changed) {
form.reset();
}
},
[form],
);
const onChangeTitle = useCallback(
async function (next) {
const t = next || typeTitle;
setEditingTitle(t);
if (t === title) {
return;
}
await api.resource('workflows').update?.({
filterByTk: workflow.id,
values: {
title: t,
},
});
refresh();
},
[workflow], [workflow],
); );
if (!workflow || !workflow.type) { const onOpenDrawer = useCallback(function (ev) {
return null;
}
const { title, type, executed } = workflow;
const trigger = triggers.get(type);
const { fieldset, scope, components } = trigger;
typeTitle = trigger.title;
const detailText = executed ? '{{t("View")}}' : '{{t("Configure")}}';
const titleText = lang('Trigger');
async function onChangeTitle(next) {
const t = next || typeTitle;
setEditingTitle(t);
if (t === title) {
return;
}
await api.resource('workflows').update?.({
filterByTk: workflow.id,
values: {
title: t,
},
});
refresh();
}
function onOpenDrawer(ev) {
if (ev.target === ev.currentTarget) { if (ev.target === ev.currentTarget) {
setEditingConfig(true); setEditingConfig(true);
return; return;
@ -202,7 +215,7 @@ export const TriggerConfig = () => {
return; return;
} }
} }
} }, []);
return ( return (
<div <div
@ -225,7 +238,14 @@ export const TriggerConfig = () => {
/> />
</div> </div>
<TriggerExecution /> <TriggerExecution />
<ActionContextProvider value={{ visible: editingConfig, setVisible: setEditingConfig }}> <ActionContextProvider
value={{
visible: editingConfig,
setVisible: setEditingConfig,
formValueChanged,
setFormValueChanged: resetForm,
}}
>
<SchemaComponent <SchemaComponent
schema={{ schema={{
name: `workflow-trigger-${workflow.id}`, name: `workflow-trigger-${workflow.id}`,

View File

@ -1,4 +1,7 @@
import { useCompile } from '@nocobase/client'; import React from 'react';
import { Variable, useCompile } from '@nocobase/client';
import { useFlowContext } from './FlowContext'; import { useFlowContext } from './FlowContext';
import { NAMESPACE, lang } from './locale'; import { NAMESPACE, lang } from './locale';
import { instructions, useAvailableUpstreams, useNodeContext, useUpstreamScopes } from './nodes'; import { instructions, useAvailableUpstreams, useNodeContext, useUpstreamScopes } from './nodes';
@ -211,20 +214,29 @@ function filterTypedFields({ fields, types, appends, depth = 1, compile, getColl
}); });
} }
function useOptions(scope, opts) {
const compile = useCompile();
const children = scope.useOptions?.(opts)?.filter(Boolean);
const { fieldNames } = opts;
return {
[fieldNames.label]: compile(scope.label),
[fieldNames.value]: scope.value,
key: scope[fieldNames.value],
[fieldNames.children]: children,
disabled: !children || !children.length,
};
}
export function useWorkflowVariableOptions(options: OptionsOfUseVariableOptions = {}) { export function useWorkflowVariableOptions(options: OptionsOfUseVariableOptions = {}) {
const fieldNames = Object.assign({}, defaultFieldNames, options.fieldNames ?? {}); const fieldNames = Object.assign({}, defaultFieldNames, options.fieldNames ?? {});
const opts = Object.assign(options, { fieldNames }); const opts = Object.assign(options, { fieldNames });
const compile = useCompile(); const result = [
const result = [scopeOptions, nodesOptions, triggerOptions, systemOptions].map((item: any) => { useOptions(scopeOptions, opts),
const children = item.useOptions?.(opts)?.filter(Boolean); useOptions(nodesOptions, opts),
return { useOptions(triggerOptions, opts),
[fieldNames.label]: compile(item.label), useOptions(systemOptions, opts),
[fieldNames.value]: item.value, ];
key: item[fieldNames.value], // const cache = useMemo(() => result, [result]);
[fieldNames.children]: children,
disabled: !children || !children.length,
};
});
return result; return result;
} }
@ -349,3 +361,23 @@ export function getCollectionFieldOptions(options): VariableOption[] {
return result; return result;
} }
export function WorkflowVariableInput({ variableOptions, ...props }): JSX.Element {
const scope = useWorkflowVariableOptions(variableOptions);
return <Variable.Input scope={scope} {...props} />;
}
export function WorkflowVariableTextArea({ variableOptions, ...props }): JSX.Element {
const scope = useWorkflowVariableOptions(variableOptions);
return <Variable.TextArea scope={scope} {...props} />;
}
export function WorkflowVariableRawTextArea({ variableOptions, ...props }): JSX.Element {
const scope = useWorkflowVariableOptions(variableOptions);
return <Variable.RawTextArea scope={scope} {...props} />;
}
export function WorkflowVariableJSON({ variableOptions, ...props }): JSX.Element {
const scope = useWorkflowVariableOptions(variableOptions);
return <Variable.JSON scope={scope} {...props} />;
}

View File

@ -511,7 +511,7 @@ export default class ScheduleTrigger extends Trigger {
const should = await this.shouldCache(workflow, now); const should = await this.shouldCache(workflow, now);
if (should) { if (should) {
this.plugin.app.logger.info('caching scheduled workflow will run in next minute:', workflow.id); this.plugin.getLogger(workflow.id).info('caching scheduled workflow will run in next minute');
} }
this.setCache(workflow, !should); this.setCache(workflow, !should);