feat(collection-manager): inverse fields can be configured (#883)
* feat: inverse field * feat: improve code * feat: translations * fix: required (cherry picked from commit 306dca8e5ee1b74562d835a816b72f933465bfb6) # Conflicts: # packages/core/client/src/locale/zh_CN.ts
This commit is contained in:
parent
933c3f4463
commit
f6add23da5
@ -8,10 +8,11 @@ import React, { useState } from 'react';
|
|||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useRequest } from '../../api-client';
|
import { useRequest } from '../../api-client';
|
||||||
import { useRecord } from '../../record-provider';
|
import { useRecord } from '../../record-provider';
|
||||||
import { ActionContext, SchemaComponent, useCompile } from '../../schema-component';
|
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
|
||||||
import { useCreateAction } from '../action-hooks';
|
import { useCreateAction } from '../action-hooks';
|
||||||
import { useCollectionManager } from '../hooks';
|
import { useCollectionManager } from '../hooks';
|
||||||
import { IField } from '../interfaces/types';
|
import { IField } from '../interfaces/types';
|
||||||
|
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
|
||||||
import * as components from './components';
|
import * as components from './components';
|
||||||
import { options } from './interfaces';
|
import { options } from './interfaces';
|
||||||
|
|
||||||
@ -27,12 +28,15 @@ const getSchema = (schema: IField, record: any, compile): ISchema => {
|
|||||||
properties['defaultValue']['title'] = compile('{{ t("Default value") }}');
|
properties['defaultValue']['title'] = compile('{{ t("Default value") }}');
|
||||||
properties['defaultValue']['x-decorator'] = 'FormItem';
|
properties['defaultValue']['x-decorator'] = 'FormItem';
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialValue = {
|
const initialValue: any = {
|
||||||
name: `f_${uid()}`,
|
name: `f_${uid()}`,
|
||||||
...cloneDeep(schema.default),
|
...cloneDeep(schema.default),
|
||||||
interface: schema.name,
|
interface: schema.name,
|
||||||
};
|
};
|
||||||
|
if (initialValue.reverseField) {
|
||||||
|
initialValue.reverseField.name = `f_${uid()}`;
|
||||||
|
}
|
||||||
// initialValue.uiSchema.title = schema.title;
|
// initialValue.uiSchema.title = schema.title;
|
||||||
return {
|
return {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@ -95,44 +99,22 @@ const useCreateCollectionField = () => {
|
|||||||
const { run } = useCreateAction();
|
const { run } = useCreateAction();
|
||||||
const { refreshCM } = useCollectionManager();
|
const { refreshCM } = useCollectionManager();
|
||||||
const { title } = useRecord();
|
const { title } = useRecord();
|
||||||
|
const ctx = useActionContext();
|
||||||
|
const { refresh } = useResourceActionContext();
|
||||||
|
const { resource } = useResourceContext();
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run() {
|
||||||
await form.submit();
|
await form.submit();
|
||||||
// const options = form?.values?.uiSchema?.enum?.slice() || [];
|
const values = cloneDeep(form.values);
|
||||||
// if (options?.length) {
|
if (values.autoCreateReverseField) {
|
||||||
// form.setValuesIn(
|
} else {
|
||||||
// 'uiSchema.enum',
|
delete values.reverseField;
|
||||||
// options.map((option) => {
|
|
||||||
// return {
|
|
||||||
// value: uid(),
|
|
||||||
// ...option,
|
|
||||||
// };
|
|
||||||
// }),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// function recursiveChildren(children = [], prefix = 'children') {
|
|
||||||
// children.forEach((item, index) => {
|
|
||||||
// const itemOptions = item.uiSchema?.enum?.slice() || [];
|
|
||||||
// form.setValuesIn(
|
|
||||||
// `${prefix}[${index}].uiSchema.enum`,
|
|
||||||
// itemOptions.map((option) => {
|
|
||||||
// return {
|
|
||||||
// value: uid(),
|
|
||||||
// ...option,
|
|
||||||
// };
|
|
||||||
// }),
|
|
||||||
// );
|
|
||||||
// recursiveChildren(item.children, `${prefix}[${index}].children`);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
// recursiveChildren(form?.values?.children);
|
|
||||||
|
|
||||||
if (['obo', 'oho', 'o2o', 'o2m', 'm2o', 'm2m', 'linkTo'].includes(form?.values?.interface) && title) {
|
|
||||||
form.setValuesIn('reverseField.uiSchema.title', title);
|
|
||||||
}
|
}
|
||||||
|
delete values.autoCreateReverseField;
|
||||||
await run();
|
await resource.create({ values });
|
||||||
|
ctx.setVisible(false);
|
||||||
|
await form.reset();
|
||||||
|
refresh();
|
||||||
await refreshCM();
|
await refreshCM();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -183,7 +165,7 @@ export const AddFieldAction = () => {
|
|||||||
<SchemaComponent
|
<SchemaComponent
|
||||||
schema={schema}
|
schema={schema}
|
||||||
components={{ ...components, ArrayTable }}
|
components={{ ...components, ArrayTable }}
|
||||||
scope={{ createOnly: true, useCreateCollectionField }}
|
scope={{ createOnly: true, useCreateCollectionField, record, showReverseFieldConfig: true }}
|
||||||
/>
|
/>
|
||||||
</ActionContext.Provider>
|
</ActionContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -2,16 +2,17 @@ import { ArrayTable } from '@formily/antd';
|
|||||||
import { ISchema, useForm } from '@formily/react';
|
import { ISchema, useForm } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import cloneDeep from 'lodash/cloneDeep';
|
import cloneDeep from 'lodash/cloneDeep';
|
||||||
|
import set from 'lodash/set';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useAPIClient, useRequest } from '../../api-client';
|
import { useAPIClient, useRequest } from '../../api-client';
|
||||||
import { useRecord } from '../../record-provider';
|
import { useRecord } from '../../record-provider';
|
||||||
import { ActionContext, SchemaComponent, useCompile } from '../../schema-component';
|
import { ActionContext, SchemaComponent, useActionContext, useCompile } from '../../schema-component';
|
||||||
import { useUpdateAction } from '../action-hooks';
|
import { useUpdateAction } from '../action-hooks';
|
||||||
import { useCollectionManager } from '../hooks';
|
import { useCollectionManager } from '../hooks';
|
||||||
import { IField } from '../interfaces/types';
|
import { IField } from '../interfaces/types';
|
||||||
|
import { useResourceActionContext, useResourceContext } from '../ResourceActionProvider';
|
||||||
import * as components from './components';
|
import * as components from './components';
|
||||||
import { Typography } from 'antd';
|
|
||||||
|
|
||||||
const getSchema = (schema: IField, record: any, compile): ISchema => {
|
const getSchema = (schema: IField, record: any, compile): ISchema => {
|
||||||
if (!schema) {
|
if (!schema) {
|
||||||
@ -50,8 +51,8 @@ const getSchema = (schema: IField, record: any, compile): ISchema => {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'FieldSummary',
|
'x-component': 'FieldSummary',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
schemaKey: schema.name
|
schemaKey: schema.name,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
...properties,
|
...properties,
|
||||||
@ -86,39 +87,23 @@ const useUpdateCollectionField = () => {
|
|||||||
const form = useForm();
|
const form = useForm();
|
||||||
const { run } = useUpdateAction();
|
const { run } = useUpdateAction();
|
||||||
const { refreshCM } = useCollectionManager();
|
const { refreshCM } = useCollectionManager();
|
||||||
|
const ctx = useActionContext();
|
||||||
|
const { refresh } = useResourceActionContext();
|
||||||
|
const { resource, targetKey } = useResourceContext();
|
||||||
|
const { [targetKey]: filterByTk } = useRecord();
|
||||||
return {
|
return {
|
||||||
async run() {
|
async run() {
|
||||||
await form.submit();
|
await form.submit();
|
||||||
const options = form?.values?.uiSchema?.enum?.slice() || [];
|
const values = cloneDeep(form.values);
|
||||||
form.setValuesIn(
|
if (values.autoCreateReverseField) {
|
||||||
'uiSchema.enum',
|
} else {
|
||||||
options.map((option) => {
|
delete values.reverseField;
|
||||||
return {
|
|
||||||
value: uid(),
|
|
||||||
...option,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
|
|
||||||
function recursiveChildren(children = [], prefix = 'children') {
|
|
||||||
children.forEach((item, index) => {
|
|
||||||
const itemOptions = item.uiSchema?.enum?.slice() || [];
|
|
||||||
form.setValuesIn(
|
|
||||||
`${prefix}[${index}].uiSchema.enum`,
|
|
||||||
itemOptions.map((option) => {
|
|
||||||
return {
|
|
||||||
value: uid(),
|
|
||||||
...option,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
recursiveChildren(item.children, `${prefix}[${index}].children`);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
delete values.autoCreateReverseField;
|
||||||
recursiveChildren(form?.values?.children);
|
await resource.update({ filterByTk, values });
|
||||||
|
ctx.setVisible(false);
|
||||||
await run();
|
await form.reset();
|
||||||
|
refresh();
|
||||||
await refreshCM();
|
await refreshCM();
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -132,18 +117,32 @@ export const EditFieldAction = (props) => {
|
|||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
|
const [data, setData] = useState<any>({});
|
||||||
return (
|
return (
|
||||||
<ActionContext.Provider value={{ visible, setVisible }}>
|
<ActionContext.Provider value={{ visible, setVisible }}>
|
||||||
<a
|
<a
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const { data } = await api.resource('collections.fields', record.collectionName).get({
|
const { data } = await api.resource('collections.fields', record.collectionName).get({
|
||||||
filterByTk: record.name,
|
filterByTk: record.name,
|
||||||
appends: record.interface === 'subTable' ? ['uiSchema', 'children'] : ['uiSchema'],
|
appends: ['uiSchema', 'reverseField'],
|
||||||
});
|
});
|
||||||
const schema = getSchema({
|
setData(data?.data);
|
||||||
...getInterface(record.interface),
|
const interfaceConf = getInterface(record.interface);
|
||||||
default: data?.data,
|
const defaultValues: any = cloneDeep(data?.data) || {};
|
||||||
}, record, compile);
|
if (!defaultValues?.reverseField) {
|
||||||
|
defaultValues.autoCreateReverseField = false;
|
||||||
|
defaultValues.reverseField = interfaceConf.default?.reverseField;
|
||||||
|
set(defaultValues.reverseField, 'name', `f_${uid()}`);
|
||||||
|
set(defaultValues.reverseField, 'uiSchema.title', record.__parent.title);
|
||||||
|
}
|
||||||
|
const schema = getSchema(
|
||||||
|
{
|
||||||
|
...interfaceConf,
|
||||||
|
default: defaultValues,
|
||||||
|
},
|
||||||
|
record,
|
||||||
|
compile,
|
||||||
|
);
|
||||||
setSchema(schema);
|
setSchema(schema);
|
||||||
setVisible(true);
|
setVisible(true);
|
||||||
}}
|
}}
|
||||||
@ -153,7 +152,7 @@ export const EditFieldAction = (props) => {
|
|||||||
<SchemaComponent
|
<SchemaComponent
|
||||||
schema={schema}
|
schema={schema}
|
||||||
components={{ ...components, ArrayTable }}
|
components={{ ...components, ArrayTable }}
|
||||||
scope={{ useUpdateCollectionField }}
|
scope={{ useUpdateCollectionField, showReverseFieldConfig: !data?.reverseField }}
|
||||||
/>
|
/>
|
||||||
</ActionContext.Provider>
|
</ActionContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { defaultProps, recordPickerSelector, recordPickerViewer, relationshipType } from './properties';
|
import { defaultProps, recordPickerSelector, recordPickerViewer, relationshipType, reverseFieldProperties } from './properties';
|
||||||
import { IField } from './types';
|
import { IField } from './types';
|
||||||
|
|
||||||
export const m2m: IField = {
|
export const m2m: IField = {
|
||||||
@ -231,6 +231,7 @@ export const m2m: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
...reverseFieldProperties,
|
||||||
},
|
},
|
||||||
filterable: {
|
filterable: {
|
||||||
nested: true,
|
nested: true,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { recordPickerSelector, recordPickerViewer, relationshipType } from './properties';
|
import { recordPickerSelector, recordPickerViewer, relationshipType, reverseFieldProperties } from './properties';
|
||||||
import { IField } from './types';
|
import { IField } from './types';
|
||||||
|
|
||||||
export const m2o: IField = {
|
export const m2o: IField = {
|
||||||
@ -203,6 +203,7 @@ export const m2o: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
...reverseFieldProperties,
|
||||||
},
|
},
|
||||||
filterable: {
|
filterable: {
|
||||||
nested: true,
|
nested: true,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { recordPickerSelector, recordPickerViewer, relationshipType } from './properties';
|
import { recordPickerSelector, recordPickerViewer, relationshipType, reverseFieldProperties } from './properties';
|
||||||
import { IField } from './types';
|
import { IField } from './types';
|
||||||
|
|
||||||
export const o2m: IField = {
|
export const o2m: IField = {
|
||||||
@ -240,6 +240,7 @@ export const o2m: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
...reverseFieldProperties,
|
||||||
},
|
},
|
||||||
filterable: {
|
filterable: {
|
||||||
nested: true,
|
nested: true,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { cloneDeep } from 'lodash';
|
import { cloneDeep } from 'lodash';
|
||||||
import { recordPickerSelector, recordPickerViewer, relationshipType } from './properties';
|
import { recordPickerSelector, recordPickerViewer, relationshipType, reverseFieldProperties } from './properties';
|
||||||
import { IField } from './types';
|
import { IField } from './types';
|
||||||
|
|
||||||
const internalSchameInitialize = (schema: ISchema, { field, block, readPretty, action }) => {
|
const internalSchameInitialize = (schema: ISchema, { field, block, readPretty, action }) => {
|
||||||
@ -37,11 +37,11 @@ const internalSchameInitialize = (schema: ISchema, { field, block, readPretty, a
|
|||||||
'x-initializer': 'FormItemInitializers',
|
'x-initializer': 'FormItemInitializers',
|
||||||
properties: {},
|
properties: {},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
};
|
||||||
} else {
|
} else {
|
||||||
schema.type = 'string';
|
schema.type = 'string';
|
||||||
if (block === 'Form') {
|
if (block === 'Form') {
|
||||||
@ -57,11 +57,11 @@ const internalSchameInitialize = (schema: ISchema, { field, block, readPretty, a
|
|||||||
} else {
|
} else {
|
||||||
schema['properties'] = {
|
schema['properties'] = {
|
||||||
selector: cloneDeep(recordPickerSelector),
|
selector: cloneDeep(recordPickerSelector),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export const o2o: IField = {
|
export const o2o: IField = {
|
||||||
name: 'o2o',
|
name: 'o2o',
|
||||||
@ -207,6 +207,16 @@ export const o2o: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
'reverseField.name': {
|
||||||
|
type: 'string',
|
||||||
|
title: '{{t("Inverse field name")}}',
|
||||||
|
// required: true,
|
||||||
|
'x-hidden': '{{ !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.')}}",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
filterable: {
|
filterable: {
|
||||||
nested: true,
|
nested: true,
|
||||||
@ -372,6 +382,7 @@ export const oho: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
...reverseFieldProperties,
|
||||||
},
|
},
|
||||||
filterable: {
|
filterable: {
|
||||||
nested: true,
|
nested: true,
|
||||||
@ -537,6 +548,7 @@ export const obo: IField = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
...reverseFieldProperties,
|
||||||
},
|
},
|
||||||
filterable: {
|
filterable: {
|
||||||
nested: true,
|
nested: true,
|
||||||
|
@ -53,6 +53,89 @@ export const relationshipType: ISchema = {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const reverseFieldProperties: Record<string, ISchema> = {
|
||||||
|
reverse: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'div',
|
||||||
|
'x-hidden': '{{ !showReverseFieldConfig }}',
|
||||||
|
properties: {
|
||||||
|
autoCreateReverseField: {
|
||||||
|
type: 'boolean',
|
||||||
|
default: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Checkbox',
|
||||||
|
'x-content': '{{t("Create inverse field in the target collection")}}',
|
||||||
|
'x-reactions': [
|
||||||
|
{
|
||||||
|
target: 'reverseField.type',
|
||||||
|
when: '{{!!$self.value}}',
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
otherwise: {
|
||||||
|
state: {
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: 'reverseField.uiSchema.title',
|
||||||
|
when: '{{!!$self.value}}',
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
otherwise: {
|
||||||
|
state: {
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
target: 'reverseField.name',
|
||||||
|
when: '{{!!$self.value}}',
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
hidden: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
otherwise: {
|
||||||
|
state: {
|
||||||
|
hidden: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'reverseField.type': {
|
||||||
|
...relationshipType,
|
||||||
|
title: '{{t("Inverse relationship type")}}',
|
||||||
|
},
|
||||||
|
'reverseField.uiSchema.title': {
|
||||||
|
type: 'string',
|
||||||
|
title: '{{t("Inverse field display name")}}',
|
||||||
|
default: '{{record.title}}',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
'reverseField.name': {
|
||||||
|
type: 'string',
|
||||||
|
title: '{{t("Inverse field name")}}',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-validator': 'uid',
|
||||||
|
description:
|
||||||
|
"{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const dateTimeProps: { [key: string]: ISchema } = {
|
export const dateTimeProps: { [key: string]: ISchema } = {
|
||||||
'uiSchema.x-component-props.dateFormat': {
|
'uiSchema.x-component-props.dateFormat': {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -175,7 +175,8 @@ export default {
|
|||||||
"Time format": "时间格式",
|
"Time format": "时间格式",
|
||||||
"12 hour": "12 小时制",
|
"12 hour": "12 小时制",
|
||||||
"24 hour": "24 小时制",
|
"24 hour": "24 小时制",
|
||||||
"Relationship type": "关联类型",
|
"Relationship type": "关系类型",
|
||||||
|
"Inverse relationship type": "反向关系类型",
|
||||||
"Source collection": "源数据表",
|
"Source collection": "源数据表",
|
||||||
"Source key": "源数据表字段标识",
|
"Source key": "源数据表字段标识",
|
||||||
"Target collection": "目标数据表",
|
"Target collection": "目标数据表",
|
||||||
@ -683,7 +684,9 @@ export default {
|
|||||||
'Marketplace': '插件市场',
|
'Marketplace': '插件市场',
|
||||||
'Coming soon...': '敬请期待...',
|
'Coming soon...': '敬请期待...',
|
||||||
'Settings center': '配置中心',
|
'Settings center': '配置中心',
|
||||||
|
|
||||||
'Bookmark': '书签',
|
'Bookmark': '书签',
|
||||||
'Manage all settings': '管理所有配置',
|
'Manage all settings': '管理所有配置',
|
||||||
|
'Create inverse field in the target collection': '在目标数据表里创建反向关系字段',
|
||||||
|
'Inverse field name': '反向关系字段标识',
|
||||||
|
'Inverse field display name': '反向关系字段名称',
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,12 @@ export class CollectionManagerPlugin extends Plugin {
|
|||||||
lodash.get(newValue, 'reverseField') &&
|
lodash.get(newValue, 'reverseField') &&
|
||||||
!lodash.get(newValue, 'reverseField.key')
|
!lodash.get(newValue, 'reverseField.key')
|
||||||
) {
|
) {
|
||||||
throw new Error('cant update field without a reverseField key');
|
const field = await this.app.db
|
||||||
|
.getModel('fields')
|
||||||
|
.findByPk(model.get('reverseKey'), { transaction: options.transaction });
|
||||||
|
if (field) {
|
||||||
|
throw new Error('cant update field without a reverseField key');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user