From 000e4e50b82a85fd81bdad191aff1512f92c4f7d Mon Sep 17 00:00:00 2001 From: chenos Date: Sun, 5 Jun 2022 22:46:14 +0800 Subject: [PATCH] feat: relationships (#473) * feat: relationship fields * feat: improve schema --- .../Configuration/AddFieldAction.tsx | 3 +- .../Configuration/AddSubFieldAction.tsx | 3 +- .../Configuration/EditFieldAction.tsx | 7 +- .../Configuration/EditSubFieldAction.tsx | 3 +- .../Configuration/components/index.tsx | 103 ++++++++ .../interfaces/components/index.tsx | 50 ++++ .../collection-manager/interfaces/index.ts | 4 + .../src/collection-manager/interfaces/m2m.tsx | 244 ++++++++++++++++++ .../src/collection-manager/interfaces/m2o.tsx | 200 ++++++++++++++ .../src/collection-manager/interfaces/o2m.tsx | 224 ++++++++++++++++ .../src/collection-manager/interfaces/o2o.tsx | 199 ++++++++++++++ 11 files changed, 1036 insertions(+), 4 deletions(-) create mode 100644 packages/core/client/src/collection-manager/Configuration/components/index.tsx create mode 100644 packages/core/client/src/collection-manager/interfaces/components/index.tsx create mode 100644 packages/core/client/src/collection-manager/interfaces/m2m.tsx create mode 100644 packages/core/client/src/collection-manager/interfaces/m2o.tsx create mode 100644 packages/core/client/src/collection-manager/interfaces/o2m.tsx create mode 100644 packages/core/client/src/collection-manager/interfaces/o2o.tsx diff --git a/packages/core/client/src/collection-manager/Configuration/AddFieldAction.tsx b/packages/core/client/src/collection-manager/Configuration/AddFieldAction.tsx index d0c150ca4..cabe0ed99 100644 --- a/packages/core/client/src/collection-manager/Configuration/AddFieldAction.tsx +++ b/packages/core/client/src/collection-manager/Configuration/AddFieldAction.tsx @@ -12,6 +12,7 @@ import { ActionContext, SchemaComponent, useCompile } from '../../schema-compone import { useCreateAction } from '../action-hooks'; import { useCollectionManager } from '../hooks'; import { IField } from '../interfaces/types'; +import * as components from './components'; import { options } from './interfaces'; const getSchema = (schema: IField): ISchema => { @@ -160,7 +161,7 @@ export const AddFieldAction = () => { {t('Add field')} - + ); }; diff --git a/packages/core/client/src/collection-manager/Configuration/AddSubFieldAction.tsx b/packages/core/client/src/collection-manager/Configuration/AddSubFieldAction.tsx index a99d8b887..19d2abebd 100644 --- a/packages/core/client/src/collection-manager/Configuration/AddSubFieldAction.tsx +++ b/packages/core/client/src/collection-manager/Configuration/AddSubFieldAction.tsx @@ -11,6 +11,7 @@ import { RecordProvider } from '../../record-provider'; import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component'; import { useCollectionManager } from '../hooks'; import { IField } from '../interfaces/types'; +import * as components from './components'; import { options } from './interfaces'; const getSchema = (schema: IField): ISchema => { @@ -133,7 +134,7 @@ export const AddSubFieldAction = () => { - + ); diff --git a/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx b/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx index 61af82c4e..09ce0f952 100644 --- a/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx +++ b/packages/core/client/src/collection-manager/Configuration/EditFieldAction.tsx @@ -10,6 +10,7 @@ import { ActionContext, SchemaComponent } from '../../schema-component'; import { useUpdateAction } from '../action-hooks'; import { useCollectionManager } from '../hooks'; import { IField } from '../interfaces/types'; +import * as components from './components'; const getSchema = (schema: IField): ISchema => { if (!schema) { @@ -133,7 +134,11 @@ export const EditFieldAction = (props) => { > {t('Edit')} - + ); }; diff --git a/packages/core/client/src/collection-manager/Configuration/EditSubFieldAction.tsx b/packages/core/client/src/collection-manager/Configuration/EditSubFieldAction.tsx index 80c8e1a99..5ed637c3c 100644 --- a/packages/core/client/src/collection-manager/Configuration/EditSubFieldAction.tsx +++ b/packages/core/client/src/collection-manager/Configuration/EditSubFieldAction.tsx @@ -10,6 +10,7 @@ import { ActionContext, SchemaComponent } from '../../schema-component'; import { useUpdateAction } from '../action-hooks'; import { useCollectionManager } from '../hooks'; import { IField } from '../interfaces/types'; +import * as components from './components'; const getSchema = (schema: IField): ISchema => { if (!schema) { @@ -114,7 +115,7 @@ export const EditSubFieldAction = (props) => { > {t('Edit')} - + ); }; diff --git a/packages/core/client/src/collection-manager/Configuration/components/index.tsx b/packages/core/client/src/collection-manager/Configuration/components/index.tsx new file mode 100644 index 000000000..17c7e2c78 --- /dev/null +++ b/packages/core/client/src/collection-manager/Configuration/components/index.tsx @@ -0,0 +1,103 @@ +import { Field } from '@formily/core'; +import { observer, useField, useForm } from '@formily/react'; +import { Select } from 'antd'; +import React from 'react'; +import { useRecord } from '../../../record-provider'; +import { useCollectionManager } from '../../hooks'; + +export const SourceForeignKey = observer(() => { + const record = useRecord(); + const { getCollection } = useCollectionManager(); + const collection = record?.collectionName ? getCollection(record.collectionName) : record; + const field = useField(); + const form = useForm(); + const { getCollectionFields } = useCollectionManager(); + return ( +
+ field.type).map((field) => { + return { + label: field?.uiSchema?.title || field.name, + value: field.name, + }; + })} + /> +
+ ); +}); + + +export const TargetForeignKey = observer(() => { + const field = useField(); + const form = useForm(); + const { getCollectionFields } = useCollectionManager(); + return ( +
+ +
+ ); +}); + +export const SourceKey = observer(() => { + return ( +
+ +
+ ); +}); diff --git a/packages/core/client/src/collection-manager/interfaces/components/index.tsx b/packages/core/client/src/collection-manager/interfaces/components/index.tsx new file mode 100644 index 000000000..b9aafda8d --- /dev/null +++ b/packages/core/client/src/collection-manager/interfaces/components/index.tsx @@ -0,0 +1,50 @@ +import { Switch } from 'antd'; +import React from 'react'; + +export const TargetKey = () => { + return ( +
+ Target key +
+ ); +}; + +export const ThroughCollection = () => { + return ( +
+ Through collection +
+ ); +}; + +export const SourceKey = () => { + return ( +
+ Source key +
+ ); +}; + +export const ForeignKey = () => { + return ( +
+ Foreign key +
+ ); +}; + +export const ForeignKey1 = () => { + return ( +
+ Foreign key 1 新建 +
+ ); +}; + +export const ForeignKey2 = () => { + return ( +
+ Foreign key 2 新建 +
+ ); +}; diff --git a/packages/core/client/src/collection-manager/interfaces/index.ts b/packages/core/client/src/collection-manager/interfaces/index.ts index 91874d519..997b20e5f 100644 --- a/packages/core/client/src/collection-manager/interfaces/index.ts +++ b/packages/core/client/src/collection-manager/interfaces/index.ts @@ -10,9 +10,13 @@ export * from './icon'; export * from './id'; export * from './input'; export * from './linkTo'; +export * from './m2m'; +export * from './m2o'; export * from './markdown'; export * from './multipleSelect'; export * from './number'; +export * from './o2m'; +export * from './o2o'; export * from './password'; export * from './percent'; export * from './phone'; diff --git a/packages/core/client/src/collection-manager/interfaces/m2m.tsx b/packages/core/client/src/collection-manager/interfaces/m2m.tsx new file mode 100644 index 000000000..fc9423abf --- /dev/null +++ b/packages/core/client/src/collection-manager/interfaces/m2m.tsx @@ -0,0 +1,244 @@ +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; +import { cloneDeep } from 'lodash'; +import { defaultProps, recordPickerSelector, recordPickerViewer } from './properties'; +import { IField } from './types'; + +export const m2m: IField = { + name: 'm2m', + type: 'object', + group: 'relation', + order: 6, + title: '{{t("Many to many")}}', + isAssociation: true, + default: { + type: 'belongsToMany', + // name, + uiSchema: { + // title, + 'x-component': 'RecordPicker', + 'x-component-props': { + // mode: 'tags', + multiple: true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + }, + reverseField: { + interface: 'm2m', + type: 'belongsToMany', + // name, + uiSchema: { + // title, + 'x-component': 'RecordPicker', + 'x-component-props': { + // mode: 'tags', + multiple: true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + }, + }, + }, + schemaInitialize(schema: ISchema, { readPretty }) { + if (readPretty) { + schema['properties'] = { + viewer: cloneDeep(recordPickerViewer), + }; + } else { + schema['properties'] = { + selector: cloneDeep(recordPickerSelector), + }; + } + }, + initialize: (values: any) => { + if (values.type === 'belongsToMany') { + if (!values.through) { + values.through = `t_${uid()}`; + } + if (!values.foreignKey) { + values.foreignKey = `f_${uid()}`; + } + if (!values.otherKey) { + values.otherKey = `f_${uid()}`; + } + if (!values.sourceKey) { + values.sourceKey = 'id'; + } + if (!values.targetKey) { + values.targetKey = 'id'; + } + } + }, + properties: { + ...defaultProps, + type: { + type: 'string', + title: '{{t("Relationship type")}}', + required: true, + 'x-disabled': true, + 'x-decorator': 'FormItem', + 'x-component': 'Select', + enum: [ + { label: 'One to one', value: 'hasOne' }, + { label: 'One to many', value: 'hasMany' }, + { label: 'Many to one', value: 'belongsTo' }, + { label: 'Many to many', value: 'belongsToMany' }, + ], + }, + grid: { + type: 'void', + 'x-component': 'Grid', + properties: { + row1: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + col11: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + source: { + type: 'string', + title: '{{t("Source collection")}}', + 'x-decorator': 'FormItem', + 'x-component': 'SourceCollection', + 'x-disabled': true, + }, + }, + }, + col12: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + through: { + type: 'string', + title: '{{t("Through collection")}}', + 'x-disabled': '{{ !createOnly }}', + 'x-reactions': ['{{useAsyncDataSource(loadCollections)}}'], + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-component-props': { + allowClear: true, + placeholder: '留空时,自动生成中间表' + }, + }, + }, + }, + col13: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + target: { + type: 'string', + title: '{{t("Target collection")}}', + required: true, + 'x-reactions': ['{{useAsyncDataSource(loadCollections)}}'], + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + }, + }, + row2: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + col21: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + sourceKey: { + type: 'void', + title: '{{t("Source key")}}', + 'x-decorator': 'FormItem', + 'x-component': 'SourceKey', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + col22: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + foreignKey: { + type: 'string', + title: '{{t("Foreign key 1")}}', + 'x-decorator': 'FormItem', + 'x-component': 'ThroughForeignKey', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + col23: { + type: 'void', + 'x-component': 'Grid.Col', + properties: {}, + }, + }, + }, + row3: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + col21: { + type: 'void', + 'x-component': 'Grid.Col', + properties: {}, + }, + col22: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + otherKey: { + type: 'string', + title: '{{t("Foreign key 2")}}', + 'x-decorator': 'FormItem', + 'x-component': 'ThroughForeignKey', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + col23: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + targetKey: { + type: 'void', + title: '{{t("Target key")}}', + 'x-decorator': 'FormItem', + 'x-component': 'TargetKey', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + }, + }, + }, + }, + }, + filterable: { + nested: true, + children: [ + // { + // name: 'id', + // title: '{{t("Exists")}}', + // operators: [ + // { label: '{{t("exists")}}', value: '$exists', noValue: true }, + // { label: '{{t("not exists")}}', value: '$notExists', noValue: true }, + // ], + // schema: { + // title: '{{t("Exists")}}', + // type: 'string', + // 'x-component': 'Input', + // }, + // }, + ], + }, +}; diff --git a/packages/core/client/src/collection-manager/interfaces/m2o.tsx b/packages/core/client/src/collection-manager/interfaces/m2o.tsx new file mode 100644 index 000000000..16f42bda9 --- /dev/null +++ b/packages/core/client/src/collection-manager/interfaces/m2o.tsx @@ -0,0 +1,200 @@ +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; +import { cloneDeep } from 'lodash'; +import { recordPickerSelector, recordPickerViewer } from './properties'; +import { IField } from './types'; + +export const m2o: IField = { + name: 'm2o', + type: 'object', + group: 'relation', + order: 5, + title: '{{t("Many to one")}}', + isAssociation: true, + default: { + type: 'belongsTo', + // name, + uiSchema: { + // title, + 'x-component': 'RecordPicker', + 'x-component-props': { + // mode: 'tags', + multiple: false, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + }, + reverseField: { + interface: 'o2m', + type: 'hasMany', + // name, + uiSchema: { + // title, + 'x-component': 'RecordPicker', + 'x-component-props': { + // mode: 'tags', + multiple: true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + }, + }, + }, + schemaInitialize(schema: ISchema, { readPretty }) { + if (readPretty) { + schema['properties'] = { + viewer: cloneDeep(recordPickerViewer), + }; + } else { + schema['properties'] = { + selector: cloneDeep(recordPickerSelector), + }; + } + }, + initialize: (values: any) => { + if (values.type === 'belongsToMany') { + if (!values.through) { + values.through = `t_${uid()}`; + } + if (!values.foreignKey) { + values.foreignKey = `f_${uid()}`; + } + if (!values.otherKey) { + values.otherKey = `f_${uid()}`; + } + if (!values.sourceKey) { + values.sourceKey = 'id'; + } + if (!values.targetKey) { + values.targetKey = 'id'; + } + } + }, + properties: { + 'uiSchema.title': { + type: 'string', + title: '{{t("Field display name")}}', + required: true, + 'x-decorator': 'FormItem', + 'x-component': 'Input', + }, + name: { + type: 'string', + title: '{{t("Field name")}}', + required: true, + 'x-disabled': '{{ !createOnly }}', + 'x-decorator': 'FormItem', + 'x-component': 'Input', + description: + "{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}", + }, + type: { + type: 'string', + title: '{{t("Relationship type")}}', + required: true, + 'x-disabled': true, + 'x-decorator': 'FormItem', + 'x-component': 'Select', + enum: [ + { label: 'One to one', value: 'hasOne' }, + { label: 'One to many', value: 'hasMany' }, + { label: 'Many to one', value: 'belongsTo' }, + { label: 'Many to many', value: 'belongsToMany' }, + ], + }, + grid: { + type: 'void', + 'x-component': 'Grid', + properties: { + row1: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + col11: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + source: { + type: 'void', + title: '{{t("Source collection")}}', + 'x-decorator': 'FormItem', + 'x-component': 'SourceCollection', + 'x-disabled': true, + }, + }, + }, + col12: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + target: { + type: 'string', + title: '{{t("Target collection")}}', + required: true, + 'x-reactions': ['{{useAsyncDataSource(loadCollections)}}'], + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + }, + }, + row2: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + col21: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + foreignKey: { + type: 'string', + title: '{{t("Foreign key")}}', + 'x-decorator': 'FormItem', + 'x-component': 'SourceForeignKey', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + col22: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + targetKey: { + type: 'void', + title: '{{t("Target key")}}', + 'x-decorator': 'FormItem', + 'x-component': 'TargetKey', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + }, + }, + }, + }, + }, + filterable: { + nested: true, + children: [ + // { + // name: 'id', + // title: '{{t("Exists")}}', + // operators: [ + // { label: '{{t("exists")}}', value: '$exists', noValue: true }, + // { label: '{{t("not exists")}}', value: '$notExists', noValue: true }, + // ], + // schema: { + // title: '{{t("Exists")}}', + // type: 'string', + // 'x-component': 'Input', + // }, + // }, + ], + }, +}; diff --git a/packages/core/client/src/collection-manager/interfaces/o2m.tsx b/packages/core/client/src/collection-manager/interfaces/o2m.tsx new file mode 100644 index 000000000..0945b2c85 --- /dev/null +++ b/packages/core/client/src/collection-manager/interfaces/o2m.tsx @@ -0,0 +1,224 @@ +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; +import { cloneDeep } from 'lodash'; +import { recordPickerSelector, recordPickerViewer } from './properties'; +import { IField } from './types'; + +export const o2m: IField = { + name: 'o2m', + type: 'object', + group: 'relation', + order: 4, + title: '{{t("One to many")}}', + isAssociation: true, + default: { + type: 'hasMany', + // name, + uiSchema: { + // title, + 'x-component': 'RecordPicker', + 'x-component-props': { + // mode: 'tags', + multiple: true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + }, + reverseField: { + interface: 'm2o', + type: 'belongsTo', + // name, + uiSchema: { + // title, + 'x-component': 'RecordPicker', + 'x-component-props': { + // mode: 'tags', + multiple: true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + }, + }, + }, + schemaInitialize(schema: ISchema, { readPretty }) { + if (readPretty) { + schema['properties'] = { + viewer: cloneDeep(recordPickerViewer), + }; + } else { + schema['properties'] = { + selector: cloneDeep(recordPickerSelector), + }; + } + }, + initialize: (values: any) => { + if (values.type === 'belongsToMany') { + if (!values.through) { + values.through = `t_${uid()}`; + } + if (!values.foreignKey) { + values.foreignKey = `f_${uid()}`; + } + if (!values.otherKey) { + values.otherKey = `f_${uid()}`; + } + if (!values.sourceKey) { + values.sourceKey = 'id'; + } + if (!values.targetKey) { + values.targetKey = 'id'; + } + } + }, + properties: { + 'uiSchema.title': { + type: 'string', + title: '{{t("Field display name")}}', + required: true, + 'x-decorator': 'FormItem', + 'x-component': 'Input', + }, + name: { + type: 'string', + title: '{{t("Field name")}}', + required: true, + 'x-disabled': '{{ !createOnly }}', + 'x-decorator': 'FormItem', + 'x-component': 'Input', + description: + "{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}", + }, + type: { + type: 'string', + title: '{{t("Relationship type")}}', + required: true, + 'x-disabled': true, + 'x-decorator': 'FormItem', + 'x-component': 'Select', + enum: [ + { label: 'One to one', value: 'hasOne' }, + { label: 'One to many', value: 'hasMany' }, + { label: 'Many to one', value: 'belongsTo' }, + { label: 'Many to many', value: 'belongsToMany' }, + ], + }, + grid: { + type: 'void', + 'x-component': 'Grid', + properties: { + row1: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + col11: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + source: { + type: 'void', + title: '{{t("Source collection")}}', + 'x-decorator': 'FormItem', + 'x-component': 'SourceCollection', + }, + }, + }, + col12: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + target: { + type: 'string', + title: '{{t("Target collection")}}', + required: true, + 'x-reactions': ['{{useAsyncDataSource(loadCollections)}}'], + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + }, + }, + row2: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + col21: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + sourceKey: { + type: 'void', + title: '{{t("Source key")}}', + default: 'id', + enum: [{ label: 'ID', value: 'id' }], + 'x-decorator': 'FormItem', + 'x-component': 'SourceKey', + }, + }, + }, + col22: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + foreignKey: { + type: 'string', + title: '{{t("Foreign key")}}', + 'x-decorator': 'FormItem', + 'x-component': 'TargetForeignKey', + }, + }, + }, + }, + }, + row3: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + col21: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + }, + }, + col22: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + targetKey: { + type: 'void', + title: '{{t("Target key")}}', + 'x-decorator': 'FormItem', + 'x-component': 'TargetKey', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + }, + }, + }, + }, + }, + filterable: { + nested: true, + children: [ + // { + // name: 'id', + // title: '{{t("Exists")}}', + // operators: [ + // { label: '{{t("exists")}}', value: '$exists', noValue: true }, + // { label: '{{t("not exists")}}', value: '$notExists', noValue: true }, + // ], + // schema: { + // title: '{{t("Exists")}}', + // type: 'string', + // 'x-component': 'Input', + // }, + // }, + ], + }, +}; diff --git a/packages/core/client/src/collection-manager/interfaces/o2o.tsx b/packages/core/client/src/collection-manager/interfaces/o2o.tsx new file mode 100644 index 000000000..d7b13e50f --- /dev/null +++ b/packages/core/client/src/collection-manager/interfaces/o2o.tsx @@ -0,0 +1,199 @@ +import { ISchema } from '@formily/react'; +import { uid } from '@formily/shared'; +import { cloneDeep } from 'lodash'; +import { recordPickerSelector, recordPickerViewer } from './properties'; +import { IField } from './types'; + +export const o2o: IField = { + name: 'o2o', + type: 'object', + group: 'relation', + order: 3, + title: '{{t("One to one")}}', + isAssociation: true, + default: { + type: 'hasOne', + // name, + uiSchema: { + // title, + 'x-component': 'RecordPicker', + 'x-component-props': { + // mode: 'tags', + multiple: false, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + }, + reverseField: { + interface: 'm2o', + type: 'belongsTo', + // name, + uiSchema: { + // title, + 'x-component': 'RecordPicker', + 'x-component-props': { + // mode: 'tags', + multiple: true, + fieldNames: { + label: 'id', + value: 'id', + }, + }, + }, + }, + }, + schemaInitialize(schema: ISchema, { readPretty }) { + if (readPretty) { + schema['properties'] = { + viewer: cloneDeep(recordPickerViewer), + }; + } else { + schema['properties'] = { + selector: cloneDeep(recordPickerSelector), + }; + } + }, + initialize: (values: any) => { + if (values.type === 'belongsToMany') { + if (!values.through) { + values.through = `t_${uid()}`; + } + if (!values.foreignKey) { + values.foreignKey = `f_${uid()}`; + } + if (!values.otherKey) { + values.otherKey = `f_${uid()}`; + } + if (!values.sourceKey) { + values.sourceKey = 'id'; + } + if (!values.targetKey) { + values.targetKey = 'id'; + } + } + }, + properties: { + 'uiSchema.title': { + type: 'string', + title: '{{t("Field display name")}}', + required: true, + 'x-decorator': 'FormItem', + 'x-component': 'Input', + }, + name: { + type: 'string', + title: '{{t("Field name")}}', + required: true, + 'x-disabled': '{{ !createOnly }}', + 'x-decorator': 'FormItem', + 'x-component': 'Input', + description: + "{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}", + }, + type: { + type: 'string', + title: '{{t("Relationship type")}}', + required: true, + 'x-disabled': true, + 'x-decorator': 'FormItem', + 'x-component': 'Select', + enum: [ + { label: 'One to one', value: 'hasOne' }, + { label: 'One to many', value: 'hasMany' }, + { label: 'Many to one', value: 'belongsTo' }, + { label: 'Many to many', value: 'belongsToMany' }, + ], + }, + grid: { + type: 'void', + 'x-component': 'Grid', + properties: { + row1: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + col11: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + source: { + type: 'void', + title: '{{t("Source collection")}}', + 'x-decorator': 'FormItem', + 'x-component': 'SourceCollection', + 'x-disabled': true, + }, + }, + }, + col12: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + target: { + type: 'string', + title: '{{t("Target collection")}}', + required: true, + 'x-reactions': ['{{useAsyncDataSource(loadCollections)}}'], + 'x-decorator': 'FormItem', + 'x-component': 'Select', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + }, + }, + row2: { + type: 'void', + 'x-component': 'Grid.Row', + properties: { + col21: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + sourceKey: { + type: 'void', + title: '{{t("Source key")}}', + 'x-decorator': 'FormItem', + 'x-component': 'SourceKey', + }, + }, + }, + col22: { + type: 'void', + 'x-component': 'Grid.Col', + properties: { + foreignKey: { + type: 'string', + title: '{{t("Foreign key")}}', + 'x-decorator': 'FormItem', + 'x-component': 'TargetForeignKey', + 'x-disabled': '{{ !createOnly }}', + }, + }, + }, + }, + }, + }, + }, + }, + filterable: { + nested: true, + children: [ + // { + // name: 'id', + // title: '{{t("Exists")}}', + // operators: [ + // { label: '{{t("exists")}}', value: '$exists', noValue: true }, + // { label: '{{t("not exists")}}', value: '$notExists', noValue: true }, + // ], + // schema: { + // title: '{{t("Exists")}}', + // type: 'string', + // 'x-component': 'Input', + // }, + // }, + ], + }, +};