refactor(plugin-workflow): manual collection block migration (#2064)
* refactor(plugin-workflow): change all collection node initializer in manual config * refactor(plugin-workflow): clean code * fix(plugin-workflow): fix custom form field in manual config * refactor(plugin-workflow): add migration * fix(plugin-workflow): fix custom form block migration * fix(plugin-workflow): fix detail read-pretty for association fields
This commit is contained in:
parent
4faf64f905
commit
e5bab3249a
@ -1,44 +1,71 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { SchemaInitializer, useCollectionManager } from '@nocobase/client';
|
import {
|
||||||
|
CollectionProvider,
|
||||||
|
SchemaInitializer,
|
||||||
|
SchemaInitializerItemOptions,
|
||||||
|
useCollectionManager,
|
||||||
|
useRecordCollectionDataSourceItems,
|
||||||
|
useSchemaTemplateManager,
|
||||||
|
} from '@nocobase/client';
|
||||||
|
import { traverseSchema } from '../nodes/manual/utils';
|
||||||
|
|
||||||
export function CollectionBlockInitializer({ insert, collection, dataSource, ...props }) {
|
function InnerCollectionBlockInitializer({ insert, collection, dataSource, ...props }) {
|
||||||
|
const { getTemplateSchemaByMode } = useSchemaTemplateManager();
|
||||||
const { getCollection } = useCollectionManager();
|
const { getCollection } = useCollectionManager();
|
||||||
|
const items = useRecordCollectionDataSourceItems('FormItem') as SchemaInitializerItemOptions[];
|
||||||
const resovledCollection = getCollection(collection);
|
const resovledCollection = getCollection(collection);
|
||||||
return (
|
|
||||||
<SchemaInitializer.Item
|
async function onConfirm({ item }) {
|
||||||
{...props}
|
const template = item.template ? await getTemplateSchemaByMode(item) : null;
|
||||||
onClick={() => {
|
const result = {
|
||||||
insert({
|
|
||||||
type: 'void',
|
type: 'void',
|
||||||
name: resovledCollection.name,
|
name: resovledCollection.name,
|
||||||
title: resovledCollection.title,
|
title: resovledCollection.title,
|
||||||
'x-decorator': 'CollectionProvider',
|
'x-decorator': 'DetailsBlockProvider',
|
||||||
'x-decorator-props': {
|
'x-decorator-props': {
|
||||||
collection,
|
collection,
|
||||||
|
dataSource,
|
||||||
},
|
},
|
||||||
'x-component': 'CardItem',
|
'x-component': 'CardItem',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
// title: props.title
|
title: props.title,
|
||||||
},
|
},
|
||||||
'x-designer': 'SimpleDesigner',
|
'x-designer': 'SimpleDesigner',
|
||||||
'x-designer-props': {
|
|
||||||
type: 'record',
|
|
||||||
},
|
|
||||||
properties: {
|
properties: {
|
||||||
grid: {
|
grid: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'Form',
|
'x-component': 'FormV2',
|
||||||
'x-decorator-props': {
|
'x-component-props': {
|
||||||
useValues: '{{ useFlowRecordFromBlock }}',
|
useProps: '{{useDetailsBlockProps}}',
|
||||||
},
|
},
|
||||||
|
'x-read-pretty': true,
|
||||||
|
properties: {
|
||||||
|
grid: template || {
|
||||||
|
type: 'void',
|
||||||
'x-component': 'Grid',
|
'x-component': 'Grid',
|
||||||
'x-initializer': 'CollectionFieldInitializers',
|
'x-initializer': 'ReadPrettyFormItemInitializers',
|
||||||
'x-context-datasource': dataSource,
|
properties: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
traverseSchema(result, (node) => {
|
||||||
|
if (node['x-uid']) {
|
||||||
|
delete node['x-uid'];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}}
|
insert(result);
|
||||||
/>
|
}
|
||||||
|
|
||||||
|
return <SchemaInitializer.Item {...props} onClick={onConfirm} items={items} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function CollectionBlockInitializer(props) {
|
||||||
|
return (
|
||||||
|
<CollectionProvider collection={props.collection}>
|
||||||
|
<InnerCollectionBlockInitializer {...props} />
|
||||||
|
</CollectionProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { cloneDeep } from 'lodash';
|
|
||||||
import { SchemaInitializer, useCollection, InitializerWithSwitch, gridRowColWrap } from '@nocobase/client';
|
|
||||||
|
|
||||||
function CollectionFieldInitializer({ field, ...props }) {
|
|
||||||
const uiSchema = cloneDeep(field.uiSchema);
|
|
||||||
delete uiSchema['x-uid'];
|
|
||||||
|
|
||||||
return (
|
|
||||||
<InitializerWithSwitch
|
|
||||||
{...props}
|
|
||||||
schema={{
|
|
||||||
...uiSchema,
|
|
||||||
name: field.name,
|
|
||||||
title: uiSchema.title ?? field.name,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-read-pretty': true,
|
|
||||||
'x-designer': 'FormItem.Designer',
|
|
||||||
'x-collection-field': field.name,
|
|
||||||
}}
|
|
||||||
type="x-collection-field"
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function CollectionFieldInitializers(props) {
|
|
||||||
const { fields } = useCollection();
|
|
||||||
const items = fields
|
|
||||||
.filter((field) => !['belongsTo', 'hasOne', 'hasMany', 'belongsToMany'].includes(field.type) && field.uiSchema)
|
|
||||||
.map((field) => ({
|
|
||||||
key: field.name,
|
|
||||||
type: 'item',
|
|
||||||
title: field.uiSchema.title,
|
|
||||||
component: CollectionFieldInitializer,
|
|
||||||
field,
|
|
||||||
}));
|
|
||||||
|
|
||||||
return <SchemaInitializer.Button {...props} items={items} title="{{t('Configure fields')}}" wrap={gridRowColWrap} />;
|
|
||||||
}
|
|
@ -4,7 +4,6 @@ import { appends, collection, values } from '../schemas/collection';
|
|||||||
import CollectionFieldset from '../components/CollectionFieldset';
|
import CollectionFieldset from '../components/CollectionFieldset';
|
||||||
import { NAMESPACE } from '../locale';
|
import { NAMESPACE } from '../locale';
|
||||||
import { CollectionBlockInitializer } from '../components/CollectionBlockInitializer';
|
import { CollectionBlockInitializer } from '../components/CollectionBlockInitializer';
|
||||||
import { CollectionFieldInitializers } from '../components/CollectionFieldInitializers';
|
|
||||||
import { useCollectionFieldOptions } from '../variable';
|
import { useCollectionFieldOptions } from '../variable';
|
||||||
import { FieldsSelect } from '../components/FieldsSelect';
|
import { FieldsSelect } from '../components/FieldsSelect';
|
||||||
|
|
||||||
@ -63,7 +62,5 @@ export default {
|
|||||||
dataSource: `{{$jobsMapByNodeId.${node.id}}}`,
|
dataSource: `{{$jobsMapByNodeId.${node.id}}}`,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
initializers: {
|
initializers: {},
|
||||||
CollectionFieldInitializers,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
import React, { useRef, useMemo, useContext } from 'react';
|
||||||
|
import { createForm } from '@formily/core';
|
||||||
|
import { useField } from '@formily/react';
|
||||||
|
import {
|
||||||
|
BlockRequestContext,
|
||||||
|
CollectionProvider,
|
||||||
|
FormBlockContext,
|
||||||
|
RecordProvider,
|
||||||
|
useAPIClient,
|
||||||
|
useAssociationNames,
|
||||||
|
} from '@nocobase/client';
|
||||||
|
import { useFlowContext } from '../../FlowContext';
|
||||||
|
import { parse } from '@nocobase/utils/client';
|
||||||
|
|
||||||
|
function useFlowContextData(dataSource) {
|
||||||
|
const { execution } = useFlowContext();
|
||||||
|
const data = useMemo(
|
||||||
|
() => ({
|
||||||
|
$context: execution?.context,
|
||||||
|
$jobsMapByNodeId: (execution?.jobs ?? []).reduce(
|
||||||
|
(map, job) => Object.assign(map, { [job.nodeId]: job.result }),
|
||||||
|
{},
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
[execution],
|
||||||
|
);
|
||||||
|
|
||||||
|
const result = useMemo(() => parse(dataSource)(data), [execution]);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function DetailsBlockProvider(props) {
|
||||||
|
const field = useField();
|
||||||
|
const formBlockRef = useRef(null);
|
||||||
|
const { appends, updateAssociationValues } = useAssociationNames();
|
||||||
|
const values = useFlowContextData(props.dataSource);
|
||||||
|
|
||||||
|
const form = useMemo(
|
||||||
|
() =>
|
||||||
|
createForm({
|
||||||
|
values,
|
||||||
|
readPretty: true,
|
||||||
|
}),
|
||||||
|
[values],
|
||||||
|
);
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
appends,
|
||||||
|
};
|
||||||
|
const service = {
|
||||||
|
loading: false,
|
||||||
|
data: {
|
||||||
|
data: values,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const api = useAPIClient();
|
||||||
|
const resource = api.resource(props.collection);
|
||||||
|
const __parent = useContext(BlockRequestContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CollectionProvider collection={props.collection}>
|
||||||
|
<RecordProvider record={values} parent={false}>
|
||||||
|
<BlockRequestContext.Provider value={{ block: 'form', field, service, resource, __parent }}>
|
||||||
|
<FormBlockContext.Provider
|
||||||
|
value={{
|
||||||
|
params,
|
||||||
|
form,
|
||||||
|
field,
|
||||||
|
service,
|
||||||
|
updateAssociationValues,
|
||||||
|
formBlockRef,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</FormBlockContext.Provider>
|
||||||
|
</BlockRequestContext.Provider>
|
||||||
|
</RecordProvider>
|
||||||
|
</CollectionProvider>
|
||||||
|
);
|
||||||
|
}
|
@ -35,6 +35,9 @@ function InternalFormBlockInitializer({ insert, schema, ...others }) {
|
|||||||
useAction: '{{ useSubmit }}',
|
useAction: '{{ useSubmit }}',
|
||||||
},
|
},
|
||||||
'x-designer': 'Action.Designer',
|
'x-designer': 'Action.Designer',
|
||||||
|
'x-designer-props': {
|
||||||
|
type: 'record',
|
||||||
|
},
|
||||||
'x-action': `${JOB_STATUS.RESOLVED}`,
|
'x-action': `${JOB_STATUS.RESOLVED}`,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -15,6 +15,7 @@ import {
|
|||||||
GeneralSchemaDesigner,
|
GeneralSchemaDesigner,
|
||||||
SchemaSettings,
|
SchemaSettings,
|
||||||
useCompile,
|
useCompile,
|
||||||
|
useFormBlockContext,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import { Registry } from '@nocobase/utils/client';
|
import { Registry } from '@nocobase/utils/client';
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ import customForm from './forms/custom';
|
|||||||
import createForm from './forms/create';
|
import createForm from './forms/create';
|
||||||
import updateForm from './forms/update';
|
import updateForm from './forms/update';
|
||||||
import { FormBlockProvider } from './FormBlockProvider';
|
import { FormBlockProvider } from './FormBlockProvider';
|
||||||
|
import { DetailsBlockProvider } from './DetailsBlockProvider';
|
||||||
|
|
||||||
type ValueOf<T> = T[keyof T];
|
type ValueOf<T> = T[keyof T];
|
||||||
|
|
||||||
@ -229,10 +231,6 @@ function useSubmit() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function useFlowRecordFromBlock() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function SchemaConfig({ value, onChange }) {
|
export function SchemaConfig({ value, onChange }) {
|
||||||
const ctx = useContext(SchemaComponentContext);
|
const ctx = useContext(SchemaComponentContext);
|
||||||
const trigger = useTrigger();
|
const trigger = useTrigger();
|
||||||
@ -333,6 +331,7 @@ export function SchemaConfig({ value, onChange }) {
|
|||||||
{},
|
{},
|
||||||
),
|
),
|
||||||
FormBlockProvider,
|
FormBlockProvider,
|
||||||
|
DetailsBlockProvider,
|
||||||
// NOTE: fake provider component
|
// NOTE: fake provider component
|
||||||
ManualActionStatusProvider(props) {
|
ManualActionStatusProvider(props) {
|
||||||
return props.children;
|
return props.children;
|
||||||
@ -344,7 +343,7 @@ export function SchemaConfig({ value, onChange }) {
|
|||||||
}}
|
}}
|
||||||
scope={{
|
scope={{
|
||||||
useSubmit,
|
useSubmit,
|
||||||
useFlowRecordFromBlock,
|
useDetailsBlockProps: useFormBlockContext,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</SchemaInitializerProvider>
|
</SchemaInitializerProvider>
|
||||||
|
@ -14,7 +14,6 @@ import {
|
|||||||
useCollectionManager,
|
useCollectionManager,
|
||||||
useCurrentUserContext,
|
useCurrentUserContext,
|
||||||
useRecord,
|
useRecord,
|
||||||
useRequest,
|
|
||||||
useTableBlockContext,
|
useTableBlockContext,
|
||||||
FormBlockContext,
|
FormBlockContext,
|
||||||
useFormBlockContext,
|
useFormBlockContext,
|
||||||
@ -28,6 +27,7 @@ import { instructions, useAvailableUpstreams } from '..';
|
|||||||
import { linkNodes } from '../../utils';
|
import { linkNodes } from '../../utils';
|
||||||
import { manualFormTypes } from './SchemaConfig';
|
import { manualFormTypes } from './SchemaConfig';
|
||||||
import { FormBlockProvider } from './FormBlockProvider';
|
import { FormBlockProvider } from './FormBlockProvider';
|
||||||
|
import { DetailsBlockProvider } from './DetailsBlockProvider';
|
||||||
|
|
||||||
const nodeCollection = {
|
const nodeCollection = {
|
||||||
title: `{{t("Task", { ns: "${NAMESPACE}" })}}`,
|
title: `{{t("Task", { ns: "${NAMESPACE}" })}}`,
|
||||||
@ -421,23 +421,6 @@ function useSubmit() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse datasource block from execution context
|
|
||||||
function useFlowRecordFromBlock(opts) {
|
|
||||||
const { ['x-context-datasource']: dataSource } = useFieldSchema();
|
|
||||||
const { execution } = useFlowContext();
|
|
||||||
const result = parse(dataSource)({
|
|
||||||
$context: execution?.context,
|
|
||||||
$jobsMapByNodeId: (execution?.jobs ?? []).reduce(
|
|
||||||
(map, job) => Object.assign(map, { [job.nodeId]: job.result }),
|
|
||||||
{},
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
return useRequest(() => {
|
|
||||||
return Promise.resolve({ data: result });
|
|
||||||
}, opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
function FlowContextProvider(props) {
|
function FlowContextProvider(props) {
|
||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
const { id } = useRecord();
|
const { id } = useRecord();
|
||||||
@ -479,6 +462,7 @@ function FlowContextProvider(props) {
|
|||||||
<SchemaComponent
|
<SchemaComponent
|
||||||
components={{
|
components={{
|
||||||
FormBlockProvider,
|
FormBlockProvider,
|
||||||
|
DetailsBlockProvider,
|
||||||
ActionBarProvider,
|
ActionBarProvider,
|
||||||
ManualActionStatusProvider,
|
ManualActionStatusProvider,
|
||||||
...Array.from(manualFormTypes.getValues()).reduce(
|
...Array.from(manualFormTypes.getValues()).reduce(
|
||||||
@ -490,6 +474,7 @@ function FlowContextProvider(props) {
|
|||||||
scope={{
|
scope={{
|
||||||
useSubmit,
|
useSubmit,
|
||||||
useFormBlockProps,
|
useFormBlockProps,
|
||||||
|
useDetailsBlockProps,
|
||||||
...Array.from(manualFormTypes.getValues()).reduce(
|
...Array.from(manualFormTypes.getValues()).reduce(
|
||||||
(result, item) => Object.assign(result, item.block.scope),
|
(result, item) => Object.assign(result, item.block.scope),
|
||||||
{},
|
{},
|
||||||
@ -529,6 +514,11 @@ function useFormBlockProps() {
|
|||||||
return { form };
|
return { form };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function useDetailsBlockProps() {
|
||||||
|
const { form } = useFormBlockContext();
|
||||||
|
return { form };
|
||||||
|
}
|
||||||
|
|
||||||
function Drawer() {
|
function Drawer() {
|
||||||
const ctx = useContext(SchemaComponentContext);
|
const ctx = useContext(SchemaComponentContext);
|
||||||
const { id, node, workflow, status, updatedAt } = useRecord();
|
const { id, node, workflow, status, updatedAt } = useRecord();
|
||||||
@ -585,9 +575,6 @@ function Drawer() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
scope={{
|
|
||||||
useFlowRecordFromBlock,
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</SchemaComponentContext.Provider>
|
</SchemaComponentContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -1,19 +1,22 @@
|
|||||||
import React, { useState, useContext } from 'react';
|
import React, { useState, useContext, useMemo } from 'react';
|
||||||
|
|
||||||
import { cloneDeep, set } from 'lodash';
|
import { cloneDeep, set } from 'lodash';
|
||||||
import { Field } from '@formily/core';
|
import { Field, createForm } from '@formily/core';
|
||||||
import { useForm } from '@formily/react';
|
import { useForm, useField, useFieldSchema } from '@formily/react';
|
||||||
import { ArrayTable } from '@formily/antd';
|
import { ArrayTable } from '@formily/antd';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ActionContextProvider,
|
ActionContextProvider,
|
||||||
CollectionContext,
|
CollectionContext,
|
||||||
CollectionProvider,
|
CollectionProvider,
|
||||||
|
FormBlockContext,
|
||||||
gridRowColWrap,
|
gridRowColWrap,
|
||||||
|
RecordProvider,
|
||||||
SchemaComponent,
|
SchemaComponent,
|
||||||
SchemaInitializer,
|
SchemaInitializer,
|
||||||
SchemaInitializerItemOptions,
|
SchemaInitializerItemOptions,
|
||||||
useCollectionManager,
|
useCollectionManager,
|
||||||
|
useRecord,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import { merge, uid } from '@nocobase/utils/client';
|
import { merge, uid } from '@nocobase/utils/client';
|
||||||
|
|
||||||
@ -22,22 +25,41 @@ import { lang, NAMESPACE } from '../../../locale';
|
|||||||
import { findSchema } from '../utils';
|
import { findSchema } from '../utils';
|
||||||
import { ManualFormType } from '../SchemaConfig';
|
import { ManualFormType } from '../SchemaConfig';
|
||||||
|
|
||||||
const FormCollectionContext = React.createContext<any>(null);
|
function CustomFormBlockProvider(props) {
|
||||||
|
|
||||||
function FormCollectionProvider(props) {
|
|
||||||
const [fields, setCollectionFields] = useState(props.collection?.fields ?? []);
|
const [fields, setCollectionFields] = useState(props.collection?.fields ?? []);
|
||||||
|
const userJob = useRecord();
|
||||||
|
const field = useField();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const [formKey] = Object.keys(fieldSchema.toJSON().properties ?? {});
|
||||||
|
const values = userJob?.result?.[formKey];
|
||||||
|
|
||||||
|
const form = useMemo(
|
||||||
|
() =>
|
||||||
|
createForm({
|
||||||
|
initialValues: values,
|
||||||
|
}),
|
||||||
|
[values],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormCollectionContext.Provider value={{ setCollectionFields }}>
|
|
||||||
<CollectionProvider
|
<CollectionProvider
|
||||||
collection={{
|
collection={{
|
||||||
...props.collection,
|
...props.collection,
|
||||||
fields,
|
fields,
|
||||||
}}
|
}}
|
||||||
|
>
|
||||||
|
<RecordProvider record={values} parent={false}>
|
||||||
|
<FormBlockContext.Provider
|
||||||
|
value={{
|
||||||
|
form,
|
||||||
|
field,
|
||||||
|
setCollectionFields,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
</FormBlockContext.Provider>
|
||||||
|
</RecordProvider>
|
||||||
</CollectionProvider>
|
</CollectionProvider>
|
||||||
</FormCollectionContext.Provider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +70,7 @@ function CustomFormBlockInitializer({ insert, ...props }) {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
insert({
|
insert({
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'FormCollectionProvider',
|
'x-decorator': 'CustomFormBlockProvider',
|
||||||
'x-decorator-props': {
|
'x-decorator-props': {
|
||||||
collection: {
|
collection: {
|
||||||
name: uid(),
|
name: uid(),
|
||||||
@ -180,7 +202,7 @@ function AddCustomFormField(props) {
|
|||||||
const collection = useContext(CollectionContext);
|
const collection = useContext(CollectionContext);
|
||||||
const [interfaceOptions, setInterface] = useState<any>(null);
|
const [interfaceOptions, setInterface] = useState<any>(null);
|
||||||
const [insert, setCallback] = useState<any>();
|
const [insert, setCallback] = useState<any>();
|
||||||
const { setCollectionFields } = useContext(FormCollectionContext);
|
const { setCollectionFields } = useContext(FormBlockContext);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AddCustomFormFieldButtonContext.Provider
|
<AddCustomFormFieldButtonContext.Provider
|
||||||
@ -271,7 +293,9 @@ function AddCustomFormField(props) {
|
|||||||
type: options.uiSchema.type,
|
type: options.uiSchema.type,
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'CollectionField',
|
'x-component': 'CollectionField',
|
||||||
'x-interface-options': newField,
|
'x-component-props': {
|
||||||
|
field: newField,
|
||||||
|
},
|
||||||
'x-collection-field': `${collection.name}.${options.name}`,
|
'x-collection-field': `${collection.name}.${options.name}`,
|
||||||
'x-designer': 'FormItem.Designer',
|
'x-designer': 'FormItem.Designer',
|
||||||
});
|
});
|
||||||
@ -329,11 +353,11 @@ export default {
|
|||||||
AddCustomFormField,
|
AddCustomFormField,
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
FormCollectionProvider,
|
CustomFormBlockProvider,
|
||||||
},
|
},
|
||||||
parseFormOptions(root) {
|
parseFormOptions(root) {
|
||||||
const forms = {};
|
const forms = {};
|
||||||
const formBlocks: any[] = findSchema(root, (item) => item['x-decorator'] === 'FormCollectionProvider');
|
const formBlocks: any[] = findSchema(root, (item) => item['x-decorator'] === 'CustomFormBlockProvider');
|
||||||
formBlocks.forEach((formBlock) => {
|
formBlocks.forEach((formBlock) => {
|
||||||
const [formKey] = Object.keys(formBlock.properties);
|
const [formKey] = Object.keys(formBlock.properties);
|
||||||
const formSchema = formBlock.properties[formKey];
|
const formSchema = formBlock.properties[formKey];
|
||||||
@ -342,7 +366,9 @@ export default {
|
|||||||
(item) => item['x-component'] === 'CollectionField',
|
(item) => item['x-component'] === 'CollectionField',
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
formBlock['x-decorator-props'].collection.fields = fields.map((field) => field['x-interface-options']);
|
formBlock['x-decorator-props'].collection.fields = fields.map(
|
||||||
|
(field) => field['x-component-props']?.field ?? field['x-interface-options'],
|
||||||
|
);
|
||||||
forms[formKey] = {
|
forms[formKey] = {
|
||||||
type: 'custom',
|
type: 'custom',
|
||||||
title: formBlock['x-component-props']?.title || formKey,
|
title: formBlock['x-component-props']?.title || formKey,
|
||||||
@ -358,7 +384,7 @@ export default {
|
|||||||
block: {
|
block: {
|
||||||
scope: {},
|
scope: {},
|
||||||
components: {
|
components: {
|
||||||
FormCollectionProvider: CollectionProvider,
|
CustomFormBlockProvider,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
} as ManualFormType;
|
} as ManualFormType;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { BlockInitializers, SchemaInitializerItemOptions, useCollectionManager } from '@nocobase/client';
|
import { BlockInitializers, SchemaInitializerItemOptions, useCollectionManager } from '@nocobase/client';
|
||||||
|
|
||||||
import { CollectionBlockInitializer } from '../../components/CollectionBlockInitializer';
|
import { CollectionBlockInitializer } from '../../components/CollectionBlockInitializer';
|
||||||
import { CollectionFieldInitializers } from '../../components/CollectionFieldInitializers';
|
import { useCollectionFieldOptions } from '../../variable';
|
||||||
import { filterTypedFields, useCollectionFieldOptions } from '../../variable';
|
|
||||||
import { NAMESPACE } from '../../locale';
|
import { NAMESPACE } from '../../locale';
|
||||||
import { SchemaConfig, SchemaConfigButton } from './SchemaConfig';
|
import { SchemaConfig, SchemaConfigButton } from './SchemaConfig';
|
||||||
import { ModeConfig } from './ModeConfig';
|
import { ModeConfig } from './ModeConfig';
|
||||||
@ -149,7 +148,5 @@ export default {
|
|||||||
}
|
}
|
||||||
: null;
|
: null;
|
||||||
},
|
},
|
||||||
initializers: {
|
initializers: {},
|
||||||
CollectionFieldInitializers,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,6 @@ import { SchemaInitializerItemOptions, useCollectionDataSource } from '@nocobase
|
|||||||
import { appends, collection, filter } from '../schemas/collection';
|
import { appends, collection, filter } from '../schemas/collection';
|
||||||
import { NAMESPACE } from '../locale';
|
import { NAMESPACE } from '../locale';
|
||||||
import { CollectionBlockInitializer } from '../components/CollectionBlockInitializer';
|
import { CollectionBlockInitializer } from '../components/CollectionBlockInitializer';
|
||||||
import { CollectionFieldInitializers } from '../components/CollectionFieldInitializers';
|
|
||||||
import { FilterDynamicComponent } from '../components/FilterDynamicComponent';
|
import { FilterDynamicComponent } from '../components/FilterDynamicComponent';
|
||||||
import { useCollectionFieldOptions } from '../variable';
|
import { useCollectionFieldOptions } from '../variable';
|
||||||
import { FieldsSelect } from '../components/FieldsSelect';
|
import { FieldsSelect } from '../components/FieldsSelect';
|
||||||
@ -54,7 +53,7 @@ export default {
|
|||||||
return result?.length ? result : null;
|
return result?.length ? result : null;
|
||||||
},
|
},
|
||||||
useInitializers(node): SchemaInitializerItemOptions | null {
|
useInitializers(node): SchemaInitializerItemOptions | null {
|
||||||
if (!node.config.collection) {
|
if (!node.config.collection || node.config.multiple) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,7 +65,5 @@ export default {
|
|||||||
dataSource: `{{$jobsMapByNodeId.${node.id}}}`,
|
dataSource: `{{$jobsMapByNodeId.${node.id}}}`,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
initializers: {
|
initializers: {},
|
||||||
CollectionFieldInitializers,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,6 @@ import { SchemaInitializerItemOptions, useCollectionDataSource } from '@nocobase
|
|||||||
import { appends, collection, filter } from '../schemas/collection';
|
import { appends, collection, filter } from '../schemas/collection';
|
||||||
import { useCollectionFieldOptions } from '../variable';
|
import { useCollectionFieldOptions } from '../variable';
|
||||||
import { CollectionBlockInitializer } from '../components/CollectionBlockInitializer';
|
import { CollectionBlockInitializer } from '../components/CollectionBlockInitializer';
|
||||||
import { CollectionFieldInitializers } from '../components/CollectionFieldInitializers';
|
|
||||||
import { NAMESPACE, useWorkflowTranslation } from '../locale';
|
import { NAMESPACE, useWorkflowTranslation } from '../locale';
|
||||||
import { FieldsSelect } from '../components/FieldsSelect';
|
import { FieldsSelect } from '../components/FieldsSelect';
|
||||||
|
|
||||||
@ -168,7 +167,5 @@ export default {
|
|||||||
dataSource: '{{$context.data}}',
|
dataSource: '{{$context.data}}',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
initializers: {
|
initializers: {},
|
||||||
CollectionFieldInitializers,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
@ -3,7 +3,6 @@ import { useCollectionDataSource, SchemaInitializerItemOptions } from '@nocobase
|
|||||||
import { ScheduleConfig } from './ScheduleConfig';
|
import { ScheduleConfig } from './ScheduleConfig';
|
||||||
import { SCHEDULE_MODE } from './constants';
|
import { SCHEDULE_MODE } from './constants';
|
||||||
import { NAMESPACE, useWorkflowTranslation } from '../../locale';
|
import { NAMESPACE, useWorkflowTranslation } from '../../locale';
|
||||||
import { CollectionFieldInitializers } from '../../components/CollectionFieldInitializers';
|
|
||||||
import { CollectionBlockInitializer } from '../../components/CollectionBlockInitializer';
|
import { CollectionBlockInitializer } from '../../components/CollectionBlockInitializer';
|
||||||
import { useCollectionFieldOptions } from '../../variable';
|
import { useCollectionFieldOptions } from '../../variable';
|
||||||
import { appends } from '../../schemas/collection';
|
import { appends } from '../../schemas/collection';
|
||||||
@ -72,7 +71,5 @@ export default {
|
|||||||
dataSource: '{{$context.data}}',
|
dataSource: '{{$context.data}}',
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
initializers: {
|
initializers: {},
|
||||||
CollectionFieldInitializers,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,138 @@
|
|||||||
|
import { Migration } from '@nocobase/server';
|
||||||
|
import { uid } from '@nocobase/utils';
|
||||||
|
|
||||||
|
function findSchema(root, filter, onlyLeaf = false) {
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
if (!root) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter(root) && (!onlyLeaf || !root.properties)) {
|
||||||
|
result.push(root);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root.properties) {
|
||||||
|
Object.keys(root.properties).forEach((key) => {
|
||||||
|
result.push(...findSchema(root.properties[key], filter));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function migrateSchema(schema = {}): object {
|
||||||
|
const root = { properties: schema };
|
||||||
|
const collectionBlocks = findSchema(root, (item) => {
|
||||||
|
return (
|
||||||
|
item['x-component'] === 'CardItem' &&
|
||||||
|
item['x-designer'] === 'SimpleDesigner' &&
|
||||||
|
item['x-decorator'] === 'CollectionProvider'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
collectionBlocks.forEach((block) => {
|
||||||
|
const id = uid();
|
||||||
|
const { grid } = block.properties;
|
||||||
|
delete block.properties.grid;
|
||||||
|
const fields = findSchema(grid, (item) => {
|
||||||
|
return item['x-decorator'] === 'FormItem';
|
||||||
|
});
|
||||||
|
fields.forEach((field) => {
|
||||||
|
Object.assign(field, {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-collection-field': `${block['x-decorator-props'].collection}.${field['x-collection-field']}`,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.assign(block, {
|
||||||
|
'x-decorator': 'DetailsBlockProvider',
|
||||||
|
'x-decorator-props': {
|
||||||
|
...block['x-decorator-props'],
|
||||||
|
dataSource: grid['x-context-datasource'],
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
[id]: {
|
||||||
|
type: 'void',
|
||||||
|
name: id,
|
||||||
|
'x-component': 'FormV2',
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{useDetailsBlockProps}}',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
type: 'void',
|
||||||
|
name: 'grid',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'ReadPrettyFormItemInitializers',
|
||||||
|
properties: grid.properties,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const customForms = findSchema(root, (item) => {
|
||||||
|
return item['x-decorator'] === 'FormCollectionProvider';
|
||||||
|
});
|
||||||
|
customForms.forEach((item) => {
|
||||||
|
Object.assign(item, {
|
||||||
|
'x-decorator': 'CustomFormBlockProvider',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const customFormFields = findSchema(root, (item) => {
|
||||||
|
return item['x-interface-options'];
|
||||||
|
});
|
||||||
|
customFormFields.forEach((field) => {
|
||||||
|
const options = field['x-interface-options'];
|
||||||
|
delete field['x-interface-options'];
|
||||||
|
Object.assign(field, {
|
||||||
|
'x-component-props': {
|
||||||
|
field: options,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class extends Migration {
|
||||||
|
async up() {
|
||||||
|
const match = await this.app.version.satisfies('<0.9.4-alpha.3');
|
||||||
|
if (!match) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { db } = this.context;
|
||||||
|
const NodeRepo = db.getRepository('flow_nodes');
|
||||||
|
await db.sequelize.transaction(async (transaction) => {
|
||||||
|
const nodes = await NodeRepo.find({
|
||||||
|
filter: {
|
||||||
|
type: 'manual',
|
||||||
|
},
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
console.log('%d nodes need to be migrated.', nodes.length);
|
||||||
|
|
||||||
|
await nodes.reduce(
|
||||||
|
(promise, node) =>
|
||||||
|
promise.then(() => {
|
||||||
|
const { schema, ...config } = node.config;
|
||||||
|
node.set('config', {
|
||||||
|
...config,
|
||||||
|
schema: {
|
||||||
|
...migrateSchema(schema),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
node.changed('config', true);
|
||||||
|
return node.save({
|
||||||
|
silent: true,
|
||||||
|
transaction,
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
Promise.resolve(),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user