9f8460ca22
* refactor(plugin-snapshot): move AppendsTreeSelect component into client package * refactor(plugin-workflow): change all appends fields select to AppendsTreeSelect * refactor(plugin-workflow): change appends and toJSON logic on server side * fix(plugin-workflow): fix toJSON logic and build error * fix(plugin-workflow): fix missing component injection * fix(plugin-workflow): fix cycle association in variables * refactor(client): change AppendsTreeSelect to lazy load * fix(client): fix lazy load in option
186 lines
5.2 KiB
TypeScript
186 lines
5.2 KiB
TypeScript
import type { Field } from '@formily/core';
|
|
import { ISchema, useForm } from '@formily/react';
|
|
import { IField, interfacesProperties, useCollectionManager, useRecord } from '@nocobase/client';
|
|
import { lodash } from '@nocobase/utils/client';
|
|
import { NAMESPACE } from './locale';
|
|
|
|
const { defaultProps } = interfacesProperties;
|
|
|
|
const APPENDS = 'appends';
|
|
const TARGET_FIELD = 'targetField';
|
|
|
|
export const useTopRecord = () => {
|
|
let record = useRecord();
|
|
|
|
while (record && Object.keys(record.__parent).length > 0) {
|
|
record = record.__parent;
|
|
}
|
|
return record;
|
|
};
|
|
|
|
function useRecordCollection() {
|
|
const { getCollectionField } = useCollectionManager();
|
|
const record = useTopRecord();
|
|
const formValues = useForm().values;
|
|
return getCollectionField(`${record.name}.${formValues.targetField}`)?.target;
|
|
}
|
|
|
|
const onTargetFieldChange = (field: Field) => {
|
|
field.value; // for watch
|
|
const targetField = field.query(`.${APPENDS}`).take() as Field | undefined;
|
|
console.log(field.path);
|
|
if (!targetField) return;
|
|
!targetField.getState().disabled && targetField.setValue([]);
|
|
};
|
|
|
|
function MakeFieldsPathOptions(fields, appends = []) {
|
|
const { getCollection } = useCollectionManager();
|
|
const options = [];
|
|
fields.forEach((field) => {
|
|
if (['belongsTo', 'hasOne', 'hasMany', 'belongsToMany'].includes(field.type)) {
|
|
const currentAppends = appends.filter((key) => `${key}.`.startsWith(`${field.name}.`));
|
|
if (currentAppends.length) {
|
|
const nextCollection = getCollection(field.target);
|
|
const nextAppends = currentAppends
|
|
.filter((key) => key !== field.name)
|
|
.map((key) => key.replace(`${field.name}.`, ''))
|
|
.filter((key) => key);
|
|
options.push({
|
|
label: field.uiSchema?.title ?? field.name,
|
|
value: field.name,
|
|
children: MakeFieldsPathOptions(nextCollection.fields, nextAppends),
|
|
});
|
|
}
|
|
} else {
|
|
options.push({
|
|
label: field.uiSchema?.title ?? field.name,
|
|
value: field.name,
|
|
});
|
|
}
|
|
});
|
|
return options;
|
|
}
|
|
|
|
const recordPickerViewer = {
|
|
type: 'void',
|
|
title: `{{t('View record')}}`,
|
|
'x-component': 'RecordPicker.Viewer',
|
|
'x-component-props': {
|
|
className: 'nb-action-popup',
|
|
},
|
|
properties: {
|
|
tabs: {
|
|
type: 'void',
|
|
'x-component': 'Tabs',
|
|
'x-component-props': {},
|
|
// 'x-initializer': 'TabPaneInitializers',
|
|
properties: {
|
|
tab1: {
|
|
type: 'void',
|
|
title: `{{t('Detail')}}`,
|
|
'x-component': 'Tabs.TabPane',
|
|
'x-designer': 'Tabs.Designer',
|
|
'x-component-props': {},
|
|
properties: {
|
|
grid: {
|
|
type: 'void',
|
|
'x-component': 'Grid',
|
|
'x-initializer': 'SnapshotBlockInitializers',
|
|
properties: {},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
};
|
|
|
|
export const snapshot: IField = {
|
|
name: 'snapshot',
|
|
type: 'object',
|
|
group: 'advanced',
|
|
title: `{{t('Snapshot', {ns: '${NAMESPACE}'})}}`,
|
|
description: `{{t('When adding a new record, create a snapshot for its relational record and save in the current record. The snapshot is not updated when the record is subsequently updated.', {ns: '${NAMESPACE}'})}}`,
|
|
default: {
|
|
type: 'snapshot',
|
|
// name,
|
|
uiSchema: {
|
|
// title,
|
|
'x-component': 'SnapshotRecordPicker',
|
|
'x-component-props': {
|
|
multiple: true,
|
|
fieldNames: {
|
|
label: 'id',
|
|
value: 'id',
|
|
},
|
|
},
|
|
},
|
|
},
|
|
schemaInitialize(schema: ISchema, { field, readPretty, action, block }) {
|
|
schema['properties'] = {
|
|
viewer: lodash.cloneDeep(recordPickerViewer),
|
|
};
|
|
},
|
|
initialize: (values: any) => {},
|
|
usePathOptions(field) {
|
|
const { appends = [], targetCollection } = field;
|
|
const { getCollection } = useCollectionManager();
|
|
const { fields } = getCollection(targetCollection);
|
|
|
|
const result = MakeFieldsPathOptions(fields, appends);
|
|
|
|
return [
|
|
{
|
|
label: `{{t('Snapshot data', { ns: '${NAMESPACE}' })}}`,
|
|
value: 'data',
|
|
children: result,
|
|
},
|
|
];
|
|
},
|
|
properties: {
|
|
...defaultProps,
|
|
[TARGET_FIELD]: {
|
|
type: 'string',
|
|
title: `{{t('The association field to snapshot', {ns: '${NAMESPACE}'})}}`,
|
|
required: true,
|
|
'x-decorator': 'FormItem',
|
|
'x-component': 'SnapshotOwnerCollectionFieldsSelect',
|
|
'x-disabled': '{{ !createOnly || isOverride }}',
|
|
'x-reactions': [
|
|
{
|
|
target: APPENDS,
|
|
when: '{{$self.value != undefined}}',
|
|
fulfill: {
|
|
state: {
|
|
visible: true,
|
|
},
|
|
},
|
|
otherwise: {
|
|
state: {
|
|
visible: false,
|
|
},
|
|
},
|
|
},
|
|
],
|
|
},
|
|
[APPENDS]: {
|
|
type: 'string',
|
|
title: `{{t("Snapshot the snapshot's association fields", {ns: "${NAMESPACE}"})}}`,
|
|
'x-decorator': 'FormItem',
|
|
'x-component': 'AppendsTreeSelect',
|
|
'x-component-props': {
|
|
useCollection: useRecordCollection,
|
|
},
|
|
'x-reactions': [
|
|
{
|
|
dependencies: [TARGET_FIELD],
|
|
when: '{{$deps[0]}}',
|
|
fulfill: {
|
|
run: '{{$self.setValue($self.value)}}',
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
};
|