katherinehhh 55efa40cdd
refactor: association field (#1838)
* feat: association field

* fix: bug

* refactor: association field

* style: style improve

* style: style improve

* refactor: support subtable

* refactor: support file collection

* refactor: locale improve

* refactor: subtable improve

* refactor: association select  improve

* refactor: association select  improve

* refactor: association select  improve

* refactor: useAssociationNames

* refactor: enable link

* refactor: selector

* refactor: selector

* refactor: locale improve

* refactor: on demand loading of relational data

* refactor: locale improve

* refactor: select button

* refactor: association field

* refactor: formformBlock provider

* refactor: formformBlock provider

* refactor: internalSelect recordPicker

* refactor: formBlocklockProvider

* fix: addNewer schema

* fix: useServiceOptions

* fix: useCreateActionProps

* fix: useCreateActionProps

* refactor: nester delete

* refactor: nester delete in detail

* refactor: subTable suport select

* refactor: subTable suport select

* style: style improve

* style: style improve

* chore: fileManger

* fix: association readPrety

* fix: filemanger

* refactor: field mode

* refactor: enable link

* chore: error message

* refactor: association schemaInitialize

* refactor: association schemaInitialize

* refactor: currentMode

* refactor: field mode default value

* fix: file manage readPretty

* fix: appends

* chore: file manage readPretty

* fix: updateAssociationValues

* fix: updateAssociationValues

* fix: updateAssociationValues

* fix: nester appends

* fix: nester appends

* fix:  tree collection association fields

* fix:  tree collection association fields

* fix: nester appends

* fix: subtable to select field value missing

* fix: subtable to select field value missing

* fix: compatible with historical blocks

* fix: compatible with historical blocks

* fix: compatible with historical blocks

* feat: add migration

* fix: filter block allow add new

* fix: compatible with historical blocks

* fix: skip if not RecordPicker

* fix: compatible with historical blocks

* fix: detail block not support nester

* fix: association select support data scope and sort setting

* fix: appends on demand loading

* fix: asociationSelect support multiple

* fix: recordPicker -> AssociationField

* fix: add migration

* fix: audit logs not show assication data

* fix: flattenNestedList

* refactor: file manager field mode

* refactor: field mode refactor

* fix: subtable action

* fix: subtable appends

* refactor: code improve

* fix: nester add new

* feat: sub table

* fix: data scope not effect immediately

* fix: association add new

* fix: association field failed to  add new and mutual influence

* style: style improve

* style: style improve

* refactor: updateAssociationValues

* refactor: form init values

* refactor: select options

* fix: form initialValues

* fix: record picker values

* fix: field value change when field mode change

* fix: select data scope

* feat: add migration

* fix: table column enable link

* fix: table column enable link

* refactor: locale improve

* fix: migration

* fix: mutiple config

* fix: readPretty enable link

* fix: appends on demand

* fix: enable link style

* refactor: locale improve

* refactor: locale improve

* feat: sub-form migration

* fix: skip migration

* fix: translation

* fix: skip migration

* fix: getLabelFormatValue

* fix: error TS2339: Property 'find' does not exist on type 'string | SchemaEnum<any>'

* refactor: remove the logic code for converting old record picker

* refactor: locale

* refactor: locale

* fix: sub-table should not support add new

* refactor: code improve

* refactor: locale

* fix: compatibility history Subtable

* fix: improve

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
Co-authored-by: Chareice <chareice@live.com>
2023-05-11 12:47:31 +08:00

1630 lines
49 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { ISchema, Schema, useFieldSchema, useForm } from '@formily/react';
import { uid } from '@formily/shared';
import React, { useContext, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { BlockRequestContext, SchemaInitializerItemOptions } from '../';
import { FieldOptions, useCollection, useCollectionManager } from '../collection-manager';
import { isAssocField } from '../filter-provider/utils';
import { useActionContext, useDesignable } from '../schema-component';
import { useSchemaTemplateManager } from '../schema-templates';
import { SelectCollection } from './SelectCollection';
export const itemsMerge = (items1) => {
return items1;
};
export const gridRowColWrap = (schema: ISchema) => {
return {
type: 'void',
'x-component': 'Grid.Row',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Grid.Col',
properties: {
[schema.name || uid()]: schema,
},
},
},
};
};
export const removeTableColumn = (schema, cb) => {
cb(schema.parent);
};
export const removeGridFormItem = (schema, cb) => {
cb(schema, {
removeParentsIfNoChildren: true,
breakRemoveOn: {
'x-component': 'Grid',
},
});
};
export const useRemoveGridFormItem = () => {
const form = useForm();
return (schema, cb) => {
cb(schema, {
removeParentsIfNoChildren: true,
breakRemoveOn: {
'x-component': 'Grid',
},
});
delete form.values?.[schema.name];
};
};
export const findTableColumn = (schema: Schema, key: string, action: string, deepth = 0) => {
return schema.reduceProperties((buf, s) => {
if (s[key] === action) {
return s;
}
const c = s.reduceProperties((buf, s) => {
if (s[key] === action) {
return s;
}
return buf;
});
if (c) {
return c;
}
return buf;
});
};
export const useTableColumnInitializerFields = () => {
const { name, currentFields = [] } = useCollection();
const { getInterface, getCollection } = useCollectionManager();
return currentFields
.filter(
(field) => field?.interface && field?.interface !== 'subTable' && !field?.isForeignKey && !field?.treeChildren,
)
.map((field) => {
const interfaceConfig = getInterface(field.interface);
const schema = {
name: field.name,
'x-collection-field': `${name}.${field.name}`,
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-component-props': {},
};
// interfaceConfig?.schemaInitialize?.(schema, { field, readPretty: true, block: 'Table' });
return {
type: 'item',
title: field?.uiSchema?.title || field.name,
component: 'TableCollectionFieldInitializer',
find: findTableColumn,
remove: removeTableColumn,
schemaInitialize: (s) => {
interfaceConfig?.schemaInitialize?.(s, {
field,
readPretty: true,
block: 'Table',
targetCollection: getCollection(field.target),
});
},
field,
schema,
} as SchemaInitializerItemOptions;
});
};
export const useAssociatedTableColumnInitializerFields = () => {
const { name, fields } = useCollection();
const { getInterface, getCollectionFields, getCollection } = useCollectionManager();
const groups = fields
?.filter((field) => {
return ['o2o', 'oho', 'obo', 'm2o'].includes(field.interface);
})
?.map((field) => {
const subFields = getCollectionFields(field.target);
const items = subFields
// ?.filter((subField) => subField?.interface && !['o2o', 'oho', 'obo', 'o2m', 'm2o', 'subTable', 'linkTo'].includes(subField?.interface))
?.filter(
(subField) => subField?.interface && !['subTable'].includes(subField?.interface) && !subField?.treeChildren,
)
?.map((subField) => {
const interfaceConfig = getInterface(subField.interface);
const schema = {
// type: 'string',
name: `${field.name}.${subField.name}`,
// title: subField?.uiSchema?.title || subField.name,
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-collection-field': `${name}.${field.name}.${subField.name}`,
'x-component-props': {},
};
return {
type: 'item',
title: subField?.uiSchema?.title || subField.name,
component: 'TableCollectionFieldInitializer',
find: findTableColumn,
remove: removeTableColumn,
schemaInitialize: (s) => {
interfaceConfig?.schemaInitialize?.(s, {
field: subField,
readPretty: true,
block: 'Table',
targetCollection: getCollection(field.target),
});
},
field: subField,
schema,
} as SchemaInitializerItemOptions;
});
return {
type: 'subMenu',
title: field.uiSchema?.title,
children: items,
} as SchemaInitializerItemOptions;
});
return groups;
};
export const useInheritsTableColumnInitializerFields = () => {
const { name } = useCollection();
const { getInterface, getInheritCollections, getCollection, getParentCollectionFields } = useCollectionManager();
const inherits = getInheritCollections(name);
return inherits?.map((v) => {
const fields = getParentCollectionFields(v, name);
const targetCollection = getCollection(v);
return {
[targetCollection?.title]: fields
?.filter((field) => {
return field?.interface;
})
.map((k) => {
const interfaceConfig = getInterface(k.interface);
const schema = {
name: `${k.name}`,
'x-component': 'CollectionField',
'x-read-pretty': true,
'x-collection-field': `${name}.${k.name}`,
'x-component-props': {},
};
return {
type: 'item',
title: k?.uiSchema?.title || k.name,
component: 'TableCollectionFieldInitializer',
find: findTableColumn,
remove: removeTableColumn,
schemaInitialize: (s) => {
interfaceConfig?.schemaInitialize?.(s, {
field: k,
readPretty: true,
block: 'Table',
targetCollection: getCollection(k?.target),
});
},
field: k,
schema,
} as SchemaInitializerItemOptions;
}),
};
});
};
export const useFormItemInitializerFields = (options?: any) => {
const { name, currentFields, template } = useCollection();
const { getInterface, getCollection } = useCollectionManager();
const form = useForm();
const { readPretty = form.readPretty, block = 'Form' } = options || {};
const { snapshot, fieldSchema } = useActionContext();
const action = fieldSchema?.['x-action'];
return currentFields
?.filter((field) => field?.interface && !field?.isForeignKey && !field?.treeChildren)
?.map((field) => {
const interfaceConfig = getInterface(field.interface);
const targetCollection = getCollection(field.target);
// const component =
// field.interface === 'o2m' && targetCollection?.template !== 'file' && !snapshot
// ? 'TableField'
// : 'CollectionField';
const schema = {
type: 'string',
name: field.name,
'x-designer': 'FormItem.Designer',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': `${name}.${field.name}`,
'x-component-props': {},
'x-read-pretty': field?.uiSchema?.['x-read-pretty'],
};
// interfaceConfig?.schemaInitialize?.(schema, { field, block: 'Form', readPretty: form.readPretty });
const resultItem = {
type: 'item',
title: field?.uiSchema?.title || field.name,
component: 'CollectionFieldInitializer',
remove: removeGridFormItem,
schemaInitialize: (s) => {
interfaceConfig?.schemaInitialize?.(s, {
field,
block,
readPretty,
action,
targetCollection,
});
},
schema,
} as SchemaInitializerItemOptions;
if (block == 'Kanban') {
resultItem['find'] = (schema: Schema, key: string, action: string) => {
const s = findSchema(schema, 'x-component', block);
return findSchema(s, key, action);
};
}
return resultItem;
});
};
// 筛选表单相关
export const useFilterFormItemInitializerFields = (options?: any) => {
const { name, currentFields } = useCollection();
const { getInterface, getCollection } = useCollectionManager();
const form = useForm();
const { readPretty = form.readPretty, block = 'FilterForm' } = options || {};
const { snapshot, fieldSchema } = useActionContext();
const action = fieldSchema?.['x-action'];
return currentFields
?.filter((field) => field?.interface && !field?.isForeignKey && getInterface(field.interface)?.filterable)
?.map((field) => {
const interfaceConfig = getInterface(field.interface);
const targetCollection = getCollection(field.target);
// const component =
// field.interface === 'o2m' && targetCollection?.template !== 'file' && !snapshot
// ? 'TableField'
// : 'CollectionField';
let schema = {
type: 'string',
name: field.name,
required: false,
'x-designer': 'FormItem.FilterFormDesigner',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': `${name}.${field.name}`,
'x-component-props': {},
};
if (isAssocField(field)) {
schema = {
type: 'string',
name: `${field.name}`,
required: false,
'x-designer': 'FormItem.FilterFormDesigner',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': `${name}.${field.name}`,
'x-component-props': field.uiSchema?.['x-component-props'],
};
}
const resultItem = {
type: 'item',
title: field?.uiSchema?.title || field.name,
component: 'CollectionFieldInitializer',
remove: removeGridFormItem,
schemaInitialize: (s) => {
interfaceConfig?.schemaInitialize?.(s, {
field,
block,
readPretty,
action,
targetCollection,
});
},
schema,
} as SchemaInitializerItemOptions;
return resultItem;
});
};
export const useAssociatedFormItemInitializerFields = (options?: any) => {
const { name, fields } = useCollection();
const { getInterface, getCollectionFields, getCollection } = useCollectionManager();
const form = useForm();
const { readPretty = form.readPretty, block = 'Form' } = options || {};
const interfaces = block === 'Form' ? ['m2o'] : ['o2o', 'oho', 'obo', 'm2o'];
const groups = fields
?.filter((field) => {
return interfaces.includes(field.interface);
})
?.map((field) => {
const subFields = getCollectionFields(field.target);
const items = subFields
?.filter(
(subField) => subField?.interface && !['subTable'].includes(subField?.interface) && !subField.treeChildren,
)
?.map((subField) => {
const interfaceConfig = getInterface(subField.interface);
const schema = {
type: 'string',
name: `${field.name}.${subField.name}`,
'x-designer': 'FormItem.Designer',
'x-component': 'CollectionField',
'x-read-pretty': readPretty,
'x-component-props': {
'pattern-disable': block === 'Form' && readPretty,
},
'x-decorator': 'FormItem',
'x-collection-field': `${name}.${field.name}.${subField.name}`,
};
return {
type: 'item',
title: subField?.uiSchema?.title || subField.name,
component: 'CollectionFieldInitializer',
remove: removeGridFormItem,
schemaInitialize: (s) => {
interfaceConfig?.schemaInitialize?.(s, {
field: subField,
block,
readPretty,
targetCollection: getCollection(field.target),
});
},
schema,
} as SchemaInitializerItemOptions;
});
return {
type: 'subMenu',
title: field.uiSchema?.title,
children: items,
} as SchemaInitializerItemOptions;
});
return groups;
};
const getItem = (
field: FieldOptions,
schemaName: string,
collectionName: string,
getCollectionFields,
processedCollections: string[],
) => {
if (field.interface === 'm2o') {
if (processedCollections.includes(field.target)) return null;
const subFields = getCollectionFields(field.target);
return {
type: 'subMenu',
title: field.uiSchema?.title,
children: subFields
.map((subField) =>
// 使用 | 分隔,是为了防止 form.values 中出现 { a: { b: 1 } } 的情况
// 使用 | 分隔后form.values 中会出现 { 'a|b': 1 } 的情况,这种情况下
// 就可以知道该字段是一个关系字段中的输入框,进而特殊处理
getItem(subField, `${schemaName}.${subField.name}`, collectionName, getCollectionFields, [
...processedCollections,
field.target,
]),
)
.filter(Boolean),
} as SchemaInitializerItemOptions;
}
if (isAssocField(field)) return null;
const schema = {
type: 'string',
name: schemaName,
'x-designer': 'FormItem.FilterFormDesigner',
'x-designer-props': {
// 在 useOperatorList 中使用,用于获取对应的操作符列表
interface: field.interface,
},
'x-component': 'CollectionField',
'x-read-pretty': false,
'x-decorator': 'FormItem',
'x-collection-field': `${collectionName}.${schemaName}`,
};
return {
type: 'item',
title: field.uiSchema?.title || field.name,
component: 'CollectionFieldInitializer',
remove: removeGridFormItem,
schema,
} as SchemaInitializerItemOptions;
};
// 筛选表单相关
export const useFilterAssociatedFormItemInitializerFields = () => {
const { name, fields } = useCollection();
const { getCollectionFields } = useCollectionManager();
const interfaces = ['m2o'];
const groups = fields
?.filter((field) => {
return interfaces.includes(field.interface);
})
?.map((field) => getItem(field, field.name, name, getCollectionFields, []));
return groups;
};
export const useInheritsFormItemInitializerFields = (options?) => {
const { name } = useCollection();
const { getInterface, getInheritCollections, getCollection, getParentCollectionFields } = useCollectionManager();
const inherits = getInheritCollections(name);
const { snapshot } = useActionContext();
const form = useForm();
return inherits?.map((v) => {
const fields = getParentCollectionFields(v, name);
const { readPretty = form.readPretty, block = 'Form' } = options || {};
const targetCollection = getCollection(v);
return {
[targetCollection?.title]: fields
?.filter((field) => field?.interface && !field?.isForeignKey)
?.map((field) => {
const interfaceConfig = getInterface(field.interface);
const targetCollection = getCollection(field.target);
// const component =
// field.interface === 'o2m' && targetCollection?.template !== 'file' && !snapshot
// ? 'TableField'
// : 'CollectionField';
const schema = {
type: 'string',
name: field.name,
title: field?.uiSchema?.title || field.name,
'x-designer': 'FormItem.Designer',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': `${name}.${field.name}`,
'x-component-props': {},
'x-read-pretty': field?.uiSchema?.['x-read-pretty'],
};
return {
type: 'item',
title: field?.uiSchema?.title || field.name,
component: 'CollectionFieldInitializer',
remove: removeGridFormItem,
schemaInitialize: (s) => {
interfaceConfig?.schemaInitialize?.(s, {
field,
block,
readPretty,
targetCollection,
});
},
schema,
} as SchemaInitializerItemOptions;
}),
};
});
};
// 筛选表单相关
export const useFilterInheritsFormItemInitializerFields = (options?) => {
const { name } = useCollection();
const { getInterface, getInheritCollections, getCollection, getParentCollectionFields } = useCollectionManager();
const inherits = getInheritCollections(name);
const { snapshot } = useActionContext();
return inherits?.map((v) => {
const fields = getParentCollectionFields(v, name);
const form = useForm();
const { readPretty = form.readPretty, block = 'Form' } = options || {};
const targetCollection = getCollection(v);
return {
[targetCollection.title]: fields
?.filter((field) => field?.interface && !field?.isForeignKey && getInterface(field.interface)?.filterable)
?.map((field) => {
const interfaceConfig = getInterface(field.interface);
const targetCollection = getCollection(field.target);
// const component =
// field.interface === 'o2m' && targetCollection?.template !== 'file' && !snapshot
// ? 'TableField'
// : 'CollectionField';
const schema = {
type: 'string',
name: field.name,
title: field?.uiSchema?.title || field.name,
required: false,
'x-designer': 'FormItem.FilterFormDesigner',
'x-component': 'CollectionField',
'x-decorator': 'FormItem',
'x-collection-field': `${name}.${field.name}`,
'x-component-props': {},
'x-read-pretty': field?.uiSchema?.['x-read-pretty'],
};
return {
type: 'item',
title: field?.uiSchema?.title || field.name,
component: 'CollectionFieldInitializer',
remove: removeGridFormItem,
schemaInitialize: (s) => {
interfaceConfig?.schemaInitialize?.(s, {
field,
block,
readPretty,
targetCollection,
});
},
schema,
} as SchemaInitializerItemOptions;
}),
};
});
};
export const useCustomFormItemInitializerFields = (options?: any) => {
const { name, currentFields } = useCollection();
const { getInterface, getCollection } = useCollectionManager();
const form = useForm();
const { readPretty = form.readPretty, block = 'Form' } = options || {};
const remove = useRemoveGridFormItem();
return currentFields
?.filter((field) => {
return (
field?.interface &&
!field?.uiSchema?.['x-read-pretty'] &&
field.interface !== 'snapshot' &&
field.type !== 'sequence'
);
})
?.map((field) => {
const interfaceConfig = getInterface(field.interface);
const schema = {
type: 'string',
name: field.name,
title: field?.uiSchema?.title || field.name,
'x-designer': 'FormItem.Designer',
'x-component': 'AssignedField',
'x-decorator': 'FormItem',
'x-collection-field': `${name}.${field.name}`,
};
return {
type: 'item',
title: field?.uiSchema?.title || field.name,
component: 'CollectionFieldInitializer',
remove: remove,
schemaInitialize: (s) => {
interfaceConfig?.schemaInitialize?.(s, {
field,
block,
readPretty,
targetCollection: getCollection(field.target),
});
},
schema,
} as SchemaInitializerItemOptions;
});
};
export const useCustomBulkEditFormItemInitializerFields = (options?: any) => {
const { name, fields } = useCollection();
const { getInterface, getCollection } = useCollectionManager();
const form = useForm();
const { readPretty = form.readPretty, block = 'Form' } = options || {};
const remove = useRemoveGridFormItem();
const filterFields = useMemo(
() =>
fields
?.filter((field) => {
return (
field?.interface &&
!field?.uiSchema?.['x-read-pretty'] &&
field.interface !== 'snapshot' &&
field.type !== 'sequence'
);
})
.map((field) => {
const interfaceConfig = getInterface(field.interface);
const schema = {
type: 'string',
name: field.name,
title: field?.uiSchema?.title || field.name,
'x-designer': 'FormItem.Designer',
'x-component': 'BulkEditField',
'x-decorator': 'FormItem',
'x-collection-field': `${name}.${field.name}`,
};
return {
type: 'item',
title: field?.uiSchema?.title || field.name,
component: 'CollectionFieldInitializer',
remove: remove,
schemaInitialize: (s) => {
interfaceConfig?.schemaInitialize?.(s, {
field,
block,
readPretty,
targetCollection: getCollection(field.target),
});
},
schema,
} as SchemaInitializerItemOptions;
}),
[fields],
);
return filterFields;
};
const findSchema = (schema: Schema, key: string, action: string) => {
if (!Schema.isSchemaInstance(schema)) return null;
return schema.reduceProperties((buf, s) => {
if (s[key] === action) {
return s;
}
const c = findSchema(s, key, action);
if (c) {
return c;
}
return buf;
});
};
const removeSchema = (schema, cb) => {
return cb(schema);
};
const recursiveParent = (schema: Schema) => {
if (!schema.parent) return null;
if (schema.parent['x-initializer']) return schema.parent;
return recursiveParent(schema.parent);
};
export const useCurrentSchema = (action: string, key: string, find = findSchema, rm = removeSchema) => {
let fieldSchema = useFieldSchema();
if (!fieldSchema?.['x-initializer']) {
const recursiveInitializerSchema = recursiveParent(fieldSchema);
if (recursiveInitializerSchema) {
fieldSchema = recursiveInitializerSchema;
}
}
const { remove } = useDesignable();
const schema = find(fieldSchema, key, action);
const ctx = useContext(BlockRequestContext);
return {
schema,
exists: !!schema,
remove() {
if (ctx.field) {
ctx.field.data = ctx.field.data || {};
ctx.field.data.activeFields = ctx.field.data.activeFields || new Set();
ctx.field.data.activeFields.delete(schema.name);
}
schema && rm(schema, remove);
},
};
};
export const useRecordCollectionDataSourceItems = (
componentName,
item = null,
collectionName = null,
resourceName = null,
) => {
const { t } = useTranslation();
const collection = useCollection();
const { getTemplatesByCollection } = useSchemaTemplateManager();
const templates = getTemplatesByCollection(collectionName || collection.name)
.filter((template) => {
return componentName && template.componentName === componentName;
})
.filter((template) => {
return ['FormItem', 'ReadPrettyFormItem'].includes(componentName) || template.resourceName === resourceName;
});
if (!templates.length) {
return [];
}
const index = 0;
return [
{
key: `${collectionName || componentName}_table_blank`,
type: 'item',
name: collection.name,
title: t('Blank block'),
item,
},
{
type: 'divider',
},
{
key: `${collectionName || componentName}_table_subMenu_${index}_copy`,
type: 'subMenu',
name: 'copy',
title: t('Duplicate template'),
children: templates.map((template) => {
const templateName = ['FormItem', 'ReadPrettyFormItem'].includes(template?.componentName)
? `${template?.name} ${t('(Fields only)')}`
: template?.name;
return {
type: 'item',
mode: 'copy',
name: collection.name,
template,
item,
title: templateName || t('Untitled'),
};
}),
},
{
key: `${collectionName || componentName}_table_subMenu_${index}_ref`,
type: 'subMenu',
name: 'ref',
title: t('Reference template'),
children: templates.map((template) => {
const templateName = ['FormItem', 'ReadPrettyFormItem'].includes(template?.componentName)
? `${template?.name} ${t('(Fields only)')}`
: template?.name;
return {
type: 'item',
mode: 'reference',
name: collection.name,
template,
item,
title: templateName || t('Untitled'),
};
}),
},
];
};
export const useCollectionDataSourceItems = (componentName) => {
const { t } = useTranslation();
const { collections, getCollectionFields } = useCollectionManager();
const { getTemplatesByCollection } = useSchemaTemplateManager();
const [selected, setSelected] = useState([]);
const [value, onChange] = useState(null);
const clearKeywords = () => {
setSelected([]);
onChange(null);
};
return [
{
key: 'tableBlock',
type: 'itemGroup',
title: React.createElement(SelectCollection, {
value,
onChange,
setSelected,
}),
children: collections
?.filter((item) => {
const b = !value || selected.includes(item.name);
if (item.inherit) {
return false;
}
const fields = getCollectionFields(item.name);
if (item.autoGenId === false && !fields.find((v) => v.primaryKey)) {
return false;
} else if (['Kanban', 'FormItem'].includes(componentName) && item.template === 'view') {
return false;
} else if (item.template === 'file' && ['Kanban', 'FormItem', 'Calendar'].includes(componentName)) {
return false;
} else {
return b && !(item?.isThrough && item?.autoCreate);
}
})
?.map((item, index) => {
const templates = getTemplatesByCollection(item.name).filter((template) => {
return (
componentName &&
template.componentName === componentName &&
(!template.resourceName || template.resourceName === item.name)
);
});
if (!templates.length) {
return {
type: 'item',
name: item.name,
title: item.title,
clearKeywords,
};
}
return {
key: `${componentName}_table_subMenu_${index}`,
type: 'subMenu',
name: `${item.name}_${index}`,
title: item.title,
children: [
{
type: 'item',
name: item.name,
title: t('Blank block'),
clearKeywords,
},
{
type: 'divider',
},
{
key: `${componentName}_table_subMenu_${index}_copy`,
type: 'subMenu',
name: 'copy',
title: t('Duplicate template'),
children: templates.map((template) => {
const templateName =
template?.componentName === 'FormItem' ? `${template?.name} ${t('(Fields only)')}` : template?.name;
return {
type: 'item',
mode: 'copy',
name: item.name,
template,
clearKeywords,
title: templateName || t('Untitled'),
};
}),
},
{
key: `${componentName}_table_subMenu_${index}_ref`,
type: 'subMenu',
name: 'ref',
title: t('Reference template'),
children: templates.map((template) => {
const templateName =
template?.componentName === 'FormItem' ? `${template?.name} ${t('(Fields only)')}` : template?.name;
return {
type: 'item',
mode: 'reference',
clearKeywords,
name: item.name,
template,
title: templateName || t('Untitled'),
};
}),
},
],
};
}),
},
];
};
export const createDetailsBlockSchema = (options) => {
const {
formItemInitializers = 'ReadPrettyFormItemInitializers',
actionInitializers = 'DetailsActionInitializers',
collection,
association,
resource,
template,
...others
} = options;
const resourceName = resource || association || collection;
const schema: ISchema = {
type: 'void',
'x-acl-action': `${resourceName}:view`,
'x-decorator': 'DetailsBlockProvider',
'x-decorator-props': {
resource: resourceName,
collection,
association,
readPretty: true,
action: 'list',
params: {
pageSize: 1,
},
// useParams: '{{ useParamsFromRecord }}',
...others,
},
'x-designer': 'DetailsDesigner',
'x-component': 'CardItem',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Details',
'x-read-pretty': true,
'x-component-props': {
useProps: '{{ useDetailsBlockProps }}',
},
properties: {
[uid()]: {
type: 'void',
'x-initializer': actionInitializers,
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 24,
},
},
properties: {},
},
grid: template || {
type: 'void',
'x-component': 'Grid',
'x-initializer': formItemInitializers,
properties: {},
},
pagination: {
type: 'void',
'x-component': 'Pagination',
'x-component-props': {
useProps: '{{ useDetailsPaginationProps }}',
},
},
},
},
},
};
console.log(JSON.stringify(schema, null, 2));
return schema;
};
export const createFormBlockSchema = (options) => {
const {
formItemInitializers = 'FormItemInitializers',
actionInitializers = 'FormActionInitializers',
collection,
resource,
association,
action,
template,
...others
} = options;
const resourceName = resource || association || collection;
const schema: ISchema = {
type: 'void',
'x-acl-action-props': {
skipScopeCheck: !action,
},
'x-acl-action': action ? `${resourceName}:update` : `${resourceName}:create`,
'x-decorator': 'FormBlockProvider',
'x-decorator-props': {
...others,
action,
resource: resourceName,
collection,
association,
// action: 'get',
// useParams: '{{ useParamsFromRecord }}',
},
'x-designer': 'FormV2.Designer',
'x-component': 'CardItem',
properties: {
[uid()]: {
type: 'void',
'x-component': 'FormV2',
'x-component-props': {
useProps: '{{ useFormBlockProps }}',
},
properties: {
grid: template || {
type: 'void',
'x-component': 'Grid',
'x-initializer': formItemInitializers,
properties: {},
},
actions: {
type: 'void',
'x-initializer': actionInitializers,
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
style: {
marginTop: 24,
},
},
properties: {},
},
},
},
},
};
return schema;
};
export const createFilterFormBlockSchema = (options) => {
const {
formItemInitializers = 'FilterFormItemInitializers',
actionInitializers = 'FilterFormActionInitializers',
collection,
resource,
association,
action,
template,
...others
} = options;
const resourceName = resource || association || collection;
const schema: ISchema = {
type: 'void',
'x-decorator': 'FilterFormBlockProvider',
'x-decorator-props': {
...others,
action,
resource: resourceName,
collection,
association,
},
'x-designer': 'FormV2.FilterDesigner',
'x-component': 'CardItem',
// 保存当前筛选区块所能过滤的数据区块
'x-filter-targets': [],
// 用于存储用户设置的每个字段的运算符,目前仅筛选表单区块支持自定义
'x-filter-operators': {},
properties: {
[uid()]: {
type: 'void',
'x-component': 'FormV2',
'x-component-props': {
useProps: '{{ useFormBlockProps }}',
},
properties: {
grid: template || {
type: 'void',
'x-component': 'Grid',
'x-initializer': formItemInitializers,
properties: {},
},
actions: {
type: 'void',
'x-initializer': actionInitializers,
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
style: {
float: 'right',
},
},
properties: {},
},
},
},
},
};
return schema;
};
export const createReadPrettyFormBlockSchema = (options) => {
const {
formItemInitializers = 'ReadPrettyFormItemInitializers',
actionInitializers = 'ReadPrettyFormActionInitializers',
collection,
association,
resource,
template,
...others
} = options;
const resourceName = resource || association || collection;
const schema: ISchema = {
type: 'void',
'x-acl-action': `${resourceName}:get`,
'x-decorator': 'FormBlockProvider',
'x-decorator-props': {
resource: resourceName,
collection,
association,
readPretty: true,
action: 'get',
useParams: '{{ useParamsFromRecord }}',
...others,
},
'x-designer': 'FormV2.ReadPrettyDesigner',
'x-component': 'CardItem',
properties: {
[uid()]: {
type: 'void',
'x-component': 'FormV2',
'x-read-pretty': true,
'x-component-props': {
useProps: '{{ useFormBlockProps }}',
},
properties: {
actions: {
type: 'void',
'x-initializer': actionInitializers,
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 24,
},
},
properties: {},
},
grid: template || {
type: 'void',
'x-component': 'Grid',
'x-initializer': formItemInitializers,
properties: {},
},
},
},
},
};
// console.log(JSON.stringify(schema, null, 2));
return schema;
};
export const createTableBlockSchema = (options) => {
const {
collection,
resource,
rowKey,
tableActionInitializers,
tableColumnInitializers,
tableActionColumnInitializers,
tableBlockProvider,
disableTemplate,
TableBlockDesigner,
blockType,
pageSize = 20,
...others
} = options;
const schema: ISchema = {
type: 'void',
'x-decorator': tableBlockProvider ?? 'TableBlockProvider',
'x-acl-action': `${resource || collection}:list`,
'x-decorator-props': {
collection,
resource: resource || collection,
action: 'list',
params: {
pageSize,
},
rowKey,
showIndex: true,
dragSort: false,
disableTemplate: disableTemplate ?? false,
blockType,
...others,
},
'x-designer': TableBlockDesigner ?? 'TableBlockDesigner',
'x-component': 'CardItem',
'x-filter-targets': [],
properties: {
actions: {
type: 'void',
'x-initializer': tableActionInitializers ?? 'TableActionInitializers',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 16,
},
},
properties: {},
},
[uid()]: {
type: 'array',
'x-initializer': tableColumnInitializers ?? 'TableColumnInitializers',
'x-component': 'TableV2',
'x-component-props': {
rowKey: 'id',
rowSelection: {
type: 'checkbox',
},
useProps: '{{ useTableBlockProps }}',
},
properties: {
actions: {
type: 'void',
title: '{{ t("Actions") }}',
'x-action-column': 'actions',
'x-decorator': 'TableV2.Column.ActionBar',
'x-component': 'TableV2.Column',
'x-designer': 'TableV2.ActionColumnDesigner',
'x-initializer': tableActionColumnInitializers ?? 'TableActionColumnInitializers',
properties: {
actions: {
type: 'void',
'x-decorator': 'DndContext',
'x-component': 'Space',
'x-component-props': {
split: '|',
},
properties: {},
},
},
},
},
},
},
};
// console.log(JSON.stringify(schema, null, 2));
return schema;
};
export const createCollapseBlockSchema = (options) => {
const { collection, blockType } = options;
const schema: ISchema = {
type: 'void',
'x-decorator': 'AssociationFilter.Provider',
'x-decorator-props': {
collection,
blockType,
associationFilterStyle: {
width: '100%',
},
},
'x-designer': 'AssociationFilter.BlockDesigner',
'x-component': 'CardItem',
'x-filter-targets': [],
properties: {
[uid()]: {
type: 'void',
'x-action': 'associateFilter',
'x-initializer': 'AssociationFilter.FilterBlockInitializer',
'x-component': 'AssociationFilter',
properties: {},
},
},
};
return schema;
};
export const createTableSelectorSchema = (options) => {
const { collection, resource, rowKey, ...others } = options;
const schema: ISchema = {
type: 'void',
'x-acl-action': `${resource || collection}:list`,
'x-decorator': 'TableSelectorProvider',
'x-decorator-props': {
collection,
resource: resource || collection,
action: 'list',
params: {
pageSize: 20,
},
rowKey,
...others,
},
'x-designer': 'TableSelectorDesigner',
'x-component': 'BlockItem',
properties: {
actions: {
type: 'void',
'x-initializer': 'TableActionInitializers',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 16,
},
},
properties: {},
},
value: {
type: 'array',
'x-initializer': 'TableColumnInitializers',
'x-component': 'TableV2.Selector',
'x-component-props': {
rowSelection: {
type: 'checkbox',
},
useProps: '{{ useTableSelectorProps }}',
},
properties: {},
},
},
};
console.log(JSON.stringify(schema, null, 2));
return schema;
};
export const createCalendarBlockSchema = (options) => {
const { collection, resource, fieldNames, ...others } = options;
const schema: ISchema = {
type: 'void',
'x-acl-action': `${resource || collection}:list`,
'x-decorator': 'CalendarBlockProvider',
'x-decorator-props': {
collection: collection,
resource: resource || collection,
action: 'list',
fieldNames: {
id: 'id',
...fieldNames,
},
params: {
paginate: false,
},
...others,
},
'x-designer': 'CalendarV2.Designer',
'x-component': 'CardItem',
properties: {
[uid()]: {
type: 'void',
'x-component': 'CalendarV2',
'x-component-props': {
useProps: '{{ useCalendarBlockProps }}',
},
properties: {
toolBar: {
type: 'void',
'x-component': 'CalendarV2.ActionBar',
'x-component-props': {
style: {
marginBottom: 24,
},
},
'x-initializer': 'CalendarActionInitializers',
properties: {},
},
event: {
type: 'void',
'x-component': 'CalendarV2.Event',
properties: {
drawer: {
type: 'void',
'x-component': 'Action.Drawer',
'x-component-props': {
className: 'nb-action-popup',
},
title: '{{ t("View record") }}',
properties: {
tabs: {
type: 'void',
'x-component': 'Tabs',
'x-component-props': {},
'x-initializer': 'TabPaneInitializers',
'x-initializer-props': {
gridInitializer: 'RecordBlockInitializers',
},
properties: {
tab1: {
type: 'void',
title: '{{t("Details")}}',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-initializer-props': {
actionInitializers: 'CalendarFormActionInitializers',
},
'x-initializer': 'RecordBlockInitializers',
properties: {},
},
},
},
},
},
},
},
},
},
},
},
},
};
console.log(JSON.stringify(schema, null, 2));
return schema;
};
export const createGanttBlockSchema = (options) => {
const { collection, resource, fieldNames, ...others } = options;
const schema: ISchema = {
type: 'void',
'x-acl-action': `${resource || collection}:list`,
'x-decorator': 'GanttBlockProvider',
'x-decorator-props': {
collection: collection,
resource: resource || collection,
action: 'list',
fieldNames: {
id: 'id',
...fieldNames,
},
params: {
paginate: false,
},
...others,
},
'x-designer': 'Gantt.Designer',
'x-component': 'CardItem',
properties: {
[uid()]: {
type: 'void',
'x-component': 'Gantt',
'x-component-props': {
useProps: '{{ useGanttBlockProps }}',
},
properties: {
toolBar: {
type: 'void',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 24,
},
},
'x-initializer': 'GanttActionInitializers',
properties: {},
},
table: {
type: 'array',
'x-decorator': 'div',
'x-decorator-props': {
style: {
float: 'left',
maxWidth: '35%',
},
},
'x-initializer': 'TableColumnInitializers',
'x-component': 'TableV2',
'x-component-props': {
rowKey: 'id',
rowSelection: {
type: 'checkbox',
},
useProps: '{{ useTableBlockProps }}',
pagination: false,
},
properties: {
actions: {
type: 'void',
title: '{{ t("Actions") }}',
'x-action-column': 'actions',
'x-decorator': 'TableV2.Column.ActionBar',
'x-component': 'TableV2.Column',
'x-designer': 'TableV2.ActionColumnDesigner',
'x-initializer': 'TableActionColumnInitializers',
properties: {
actions: {
type: 'void',
'x-decorator': 'DndContext',
'x-component': 'Space',
'x-component-props': {
split: '|',
},
properties: {},
},
},
},
},
},
detail: {
type: 'void',
'x-component': 'Gantt.Event',
properties: {
drawer: {
type: 'void',
'x-component': 'Action.Drawer',
'x-component-props': {
className: 'nb-action-popup',
},
title: '{{ t("View record") }}',
properties: {
tabs: {
type: 'void',
'x-component': 'Tabs',
'x-component-props': {},
'x-initializer': 'TabPaneInitializers',
properties: {
tab1: {
type: 'void',
title: '{{t("Details")}}',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-initializer': 'RecordBlockInitializers',
properties: {},
},
},
},
},
},
},
},
},
},
},
},
},
};
console.log(JSON.stringify(schema, null, 2));
return schema;
};
export const createKanbanBlockSchema = (options) => {
const { collection, resource, groupField, ...others } = options;
const schema: ISchema = {
type: 'void',
'x-acl-action': `${resource || collection}:list`,
'x-decorator': 'KanbanBlockProvider',
'x-decorator-props': {
collection: collection,
resource: resource || collection,
action: 'list',
groupField,
params: {
paginate: false,
},
...others,
},
'x-designer': 'Kanban.Designer',
'x-component': 'CardItem',
properties: {
actions: {
type: 'void',
'x-initializer': 'KanbanActionInitializers',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 16,
},
},
properties: {},
},
[uid()]: {
type: 'array',
'x-component': 'Kanban',
'x-component-props': {
useProps: '{{ useKanbanBlockProps }}',
},
properties: {
card: {
type: 'void',
'x-read-pretty': true,
'x-label-disabled': true,
'x-decorator': 'BlockItem',
'x-component': 'Kanban.Card',
'x-component-props': {
openMode: 'drawer',
},
'x-designer': 'Kanban.Card.Designer',
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-component-props': { dndContext: false },
},
},
},
cardViewer: {
type: 'void',
title: '{{ t("View") }}',
'x-designer': 'Action.Designer',
'x-component': 'Kanban.CardViewer',
'x-action': 'view',
'x-component-props': {
openMode: 'drawer',
},
properties: {
drawer: {
type: 'void',
title: '{{ t("View record") }}',
'x-component': 'Action.Container',
'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("Details")}}',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-initializer': 'RecordBlockInitializers',
properties: {},
},
},
},
},
},
},
},
},
},
},
},
},
};
return schema;
};