tachybase_todo/packages/plugins/workflow/src/client/variable.tsx
被雨水过滤的空气-Rairn 098140d511
feat(parse-variables): support to parse variables in filter params (#1558)
* fix: add field linkage on setting default datetime

* fix: fix dateonly timezone problem

* fix: improve test

* docs(DatePicker): add demos

* fix(DatePicker): should return the beginning of a second

* feat(DatePicker): support non-UTC

* refactor: rename

* fix(RangePicker): get correct end date

* test(mapDatePicker): add test

* test(mapRangePicker): add test

* feat(Filter): use non-UTC to filter

* feat(FilterBlock): use non-UTC to filter

* feat: add '$dateBetween' operator in datetime

* feat: use RangePicker on toggled to 'dateBetween' operator

* feat: set ranges for RangePicker

* feat: backend support to parse 'dateBetween' operator

* fix: fix build error

* fix: adaptive content width

* feat: support to use var on data scope

* feat: add parse-variables plugin

* feat: support to parse variables

* feat: support only to set system variables

* test: rename

* feat: cover all

* fix: fix build error

* feat(RangePicker): extend more shortcut keys

* feat(parse-variables): support more date var

* feat: support user variables

* feat: disable unmatched options

* fix: use component name to filter option

* fix: fix build error

* feat: remove some operator of id

* chore: remove useless operators

* fix: built in plugin

* refactor: move to core from plugin

* refactor: remove code of plugin

* refactor: remove useless code

* fix: should after acl

* Update server.ts

* fix: compatible with old version

* feat: test cases

* refactor: rename to 'is between'

* refactor: parse filter

* fix: improve code

* feat: test cases

* fix: fix error

* fix: improve parse date

* fix: date variables

* fix: day range

* fix: test error

* fix: typo

* fix: test error

* feat: $user variable

* fix: toDate

* fix: fix the value range of shortcuts

* feat: add quarter and test

* feat: support to use user's association fields to filter

* refactor: use maxDepth

* refactor: remove useless code

* fix: make AssociationSelect.Designer to support variables

* fix: getField

* fix: parse utc

* fix: remove only

* fix: filter by ctx.db.getFieldByPath

* fix: avoid error

* fix: add translation

* fix(RangePicker): can be set to empty

* feat(utils): add hasEmptyValue

* fix: should not save empty

* fix: last few days should include today

* fix: limit user variable type to display

* fix: parse filter error

* fix: empty

* test: [skip ci]

* fix: remove ';'

* feat: improve code

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
2023-03-30 23:49:57 +08:00

129 lines
3.9 KiB
TypeScript

import { useCollectionManager, useCompile } from '@nocobase/client';
import { useFlowContext } from './FlowContext';
import { NAMESPACE } from './locale';
import { instructions, useAvailableUpstreams, useNodeContext } from './nodes';
import { triggers } from './triggers';
export type VariableOption = {
key: string;
value: string;
label: string;
children?: VariableOption[];
};
const VariableTypes = [
{
title: `{{t("Node result", { ns: "${NAMESPACE}" })}}`,
value: '$jobsMapByNodeId',
options(types) {
const current = useNodeContext();
const upstreams = useAvailableUpstreams(current);
const options: VariableOption[] = [];
upstreams.forEach((node) => {
const instruction = instructions.get(node.type);
const subOptions = instruction.getOptions?.(node.config, types);
if (subOptions) {
options.push({
key: node.id.toString(),
value: node.id.toString(),
label: node.title ?? `#${node.id}`,
children: subOptions,
});
}
});
return options;
},
},
{
title: `{{t("Trigger variables", { ns: "${NAMESPACE}" })}}`,
value: '$context',
options(types) {
const { workflow } = useFlowContext();
const trigger = triggers.get(workflow.type);
return trigger?.getOptions?.(workflow.config, types) ?? null;
},
},
{
title: `{{t("System variables", { ns: "${NAMESPACE}" })}}`,
value: '$system',
options: [
{
key: 'now',
value: 'now',
label: `{{t("Now")}}`,
},
],
},
];
export const TypeSets = {
boolean: new Set(['boolean']),
number: new Set(['integer', 'bigInt', 'float', 'double', 'real', 'decimal']),
string: new Set(['string', 'text', 'password']),
date: new Set(['date', 'time']),
};
function matchFieldType(field, type): Boolean {
if (typeof type === 'string') {
return Boolean(TypeSets[type]?.has(field.type));
}
if (typeof type === 'object' && type.type === 'reference') {
return (
(field.collectionName === type.options?.collection && field.name === 'id') ||
(field.type === 'belongsTo' && field.target === type.options?.collection)
);
}
return false;
}
export function filterTypedFields(fields, types) {
return types ? fields.filter((field) => types.some((type) => matchFieldType(field, type))) : fields;
}
export function useWorkflowVariableOptions() {
const compile = useCompile();
const options = VariableTypes.map((item: any) => {
const options = typeof item.options === 'function' ? item.options().filter(Boolean) : item.options;
return {
label: compile(item.title),
value: item.value,
key: item.value,
children: compile(options),
disabled: options && !options.length,
};
});
return options;
}
export function useCollectionFieldOptions(props) {
const { fields, collection, types } = props;
const compile = useCompile();
const { getCollectionFields } = useCollectionManager();
const result = filterTypedFields(fields ?? getCollectionFields(collection), types).map((field) => ({
label: compile(field.uiSchema?.title || field.name),
key: field.name,
value: field.name,
children: ['linkTo', 'belongsTo', 'hasOne', 'hasMany', 'belongsToMany'].includes(field.type)
? getCollectionFields(field.target)
?.filter((subField) => subField.interface && (!subField.target || subField.type === 'belongsTo'))
.map((subField) =>
subField.type === 'belongsTo'
? {
label: `${compile(subField.uiSchema?.title || subField.name)} ID`,
key: subField.foreignKey,
value: subField.foreignKey,
}
: {
label: compile(subField.uiSchema?.title || subField.name),
key: subField.name,
value: subField.name,
},
)
: null,
}));
return result;
}