feat: update collections & fields (#500)

* feat: update collections & fields

* fix: restore phone

* fix: add phone type

* fix: just hide subTable in menu
This commit is contained in:
金昶 2022-06-11 22:25:03 +08:00 committed by GitHub
parent a92a78cc9e
commit 3496126102
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 91 additions and 32 deletions

View File

@ -2,7 +2,7 @@ import { PlusOutlined } from '@ant-design/icons';
import { ArrayTable } from '@formily/antd'; 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 { Button, Dropdown, Menu } from 'antd'; import { Button, Dropdown, Menu, Typography } from 'antd';
import { cloneDeep } from 'lodash'; import { cloneDeep } from 'lodash';
import React, { useState } from 'react'; import React, { useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -15,7 +15,7 @@ import { IField } from '../interfaces/types';
import * as components from './components'; import * as components from './components';
import { options } from './interfaces'; import { options } from './interfaces';
const getSchema = (schema: IField): ISchema => { const getSchema = (schema: IField, record: any, compile): ISchema => {
if (!schema) { if (!schema) {
return; return;
} }
@ -44,8 +44,15 @@ const getSchema = (schema: IField): ISchema => {
); );
}, },
}, },
title: '{{ t("Add field") }}', title: `${record.title} - ${compile('{{ t("Add field") }}')}`,
properties: { properties: {
summary: {
type: 'void',
'x-component': 'FieldSummary',
'x-component-props': {
schemaKey: schema.name
}
},
// @ts-ignore // @ts-ignore
...properties, ...properties,
footer: { footer: {
@ -128,6 +135,7 @@ export const AddFieldAction = () => {
const [schema, setSchema] = useState({}); const [schema, setSchema] = useState({});
const compile = useCompile(); const compile = useCompile();
const { t } = useTranslation(); const { t } = useTranslation();
const record = useRecord();
return ( return (
<ActionContext.Provider value={{ visible, setVisible }}> <ActionContext.Provider value={{ visible, setVisible }}>
<Dropdown <Dropdown
@ -138,7 +146,7 @@ export const AddFieldAction = () => {
overflow: 'auto', overflow: 'auto',
}} }}
onClick={(info) => { onClick={(info) => {
const schema = getSchema(getInterface(info.key)); const schema = getSchema(getInterface(info.key), record, compile);
setSchema(schema); setSchema(schema);
setVisible(true); setVisible(true);
}} }}

View File

@ -6,13 +6,14 @@ 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 } from '../../schema-component'; import { ActionContext, SchemaComponent, 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 * as components from './components'; import * as components from './components';
import { Typography } from 'antd';
const getSchema = (schema: IField): ISchema => { const getSchema = (schema: IField, record: any, compile): ISchema => {
if (!schema) { if (!schema) {
return; return;
} }
@ -36,8 +37,15 @@ const getSchema = (schema: IField): ISchema => {
); );
}, },
}, },
title: '{{ t("Edit field") }}', title: `${record.__parent?.title} - ${compile('{{ t("Edit field") }}')}`,
properties: { properties: {
summary: {
type: 'void',
'x-component': 'FieldSummary',
'x-component-props': {
schemaKey: schema.name
}
},
// @ts-ignore // @ts-ignore
...properties, ...properties,
footer: { footer: {
@ -116,6 +124,7 @@ export const EditFieldAction = (props) => {
const [schema, setSchema] = useState({}); const [schema, setSchema] = useState({});
const api = useAPIClient(); const api = useAPIClient();
const { t } = useTranslation(); const { t } = useTranslation();
const compile = useCompile();
return ( return (
<ActionContext.Provider value={{ visible, setVisible }}> <ActionContext.Provider value={{ visible, setVisible }}>
<a <a
@ -127,7 +136,7 @@ export const EditFieldAction = (props) => {
const schema = getSchema({ const schema = getSchema({
...getInterface(record.interface), ...getInterface(record.interface),
default: data?.data, default: data?.data,
}); }, record, compile);
setSchema(schema); setSchema(schema);
setVisible(true); setVisible(true);
}} }}

View File

@ -17,7 +17,7 @@ export function registerGroupLabel(key: string, label: string) {
groupLabels[key] = label; groupLabels[key] = label;
} }
Object.keys(types).forEach((type) => { Object.keys(types).filter((type) => !['subTable'].includes(type)).forEach((type) => {
const schema = types[type]; const schema = types[type];
registerField(schema.group || 'others', type, { order: 0, ...schema }); registerField(schema.group || 'others', type, { order: 0, ...schema });
}); });
@ -27,6 +27,7 @@ registerGroupLabel('choices', '{{t("Choices")}}');
registerGroupLabel('media', '{{t("Media")}}'); registerGroupLabel('media', '{{t("Media")}}');
registerGroupLabel('datetime', '{{t("Date & Time")}}'); registerGroupLabel('datetime', '{{t("Date & Time")}}');
registerGroupLabel('relation', '{{t("Relation")}}'); registerGroupLabel('relation', '{{t("Relation")}}');
registerGroupLabel('advance', '{{t("Advance type")}}');
registerGroupLabel('systemInfo', '{{t("System info")}}'); registerGroupLabel('systemInfo', '{{t("System info")}}');
registerGroupLabel('others', '{{t("Others")}}'); registerGroupLabel('others', '{{t("Others")}}');

View File

@ -85,6 +85,10 @@ export const collectionFieldSchema: ISchema = {
// collection, // collection,
// }, // },
properties: { properties: {
summary: {
type: 'void',
'x-component': 'FieldSummary',
},
actions: { actions: {
type: 'void', type: 'void',
'x-component': 'ActionBar', 'x-component': 'ActionBar',

View File

@ -1,4 +1,7 @@
import { ISchema } from '@formily/react'; import { ISchema } from '@formily/react';
import { useTranslation } from 'react-i18next';
import { useRecord } from '../../../record-provider';
import { useCompile } from '../../../schema-component';
import { CollectionOptions } from '../../types'; import { CollectionOptions } from '../../types';
import { collectionFieldSchema } from './collectionFields'; import { collectionFieldSchema } from './collectionFields';
@ -197,7 +200,12 @@ export const collectionSchema: ISchema = {
drawer: { drawer: {
type: 'void', type: 'void',
'x-component': 'Action.Drawer', 'x-component': 'Action.Drawer',
title: '{{ t("Configure fields") }}', 'x-reactions': (field) => {
const i = field.path.segments[1];
const table = field.form.getValuesIn(`table.${i}`);
const compile = useCompile();
field.title = `${compile(table.title)} - ${compile('{{ t("Configure fields") }}')}`;
},
properties: { properties: {
collectionFieldSchema, collectionFieldSchema,
}, },

View File

@ -4,9 +4,10 @@ import { IField } from './types';
export const formula: IField = { export const formula: IField = {
name: 'formula', name: 'formula',
type: 'object', type: 'object',
group: 'basic', group: 'advance',
order: 9, order: 1,
title: '{{t("Formula")}}', title: '{{t("Formula")}}',
description: '{{t("Formula description")}}',
sortable: true, sortable: true,
default: { default: {
type: 'formula', type: 'formula',

View File

@ -10,6 +10,7 @@ export const linkTo: IField = {
group: 'relation', group: 'relation',
order: 1, order: 1,
title: '{{t("Link to")}}', title: '{{t("Link to")}}',
description: '{{t("Link to description")}}',
isAssociation: true, isAssociation: true,
default: { default: {
type: 'belongsToMany', type: 'belongsToMany',

View File

@ -10,6 +10,7 @@ export const m2m: IField = {
group: 'relation', group: 'relation',
order: 6, order: 6,
title: '{{t("Many to many")}}', title: '{{t("Many to many")}}',
description: '{{t("Many to many description")}}',
isAssociation: true, isAssociation: true,
default: { default: {
type: 'belongsToMany', type: 'belongsToMany',

View File

@ -9,6 +9,7 @@ export const m2o: IField = {
group: 'relation', group: 'relation',
order: 5, order: 5,
title: '{{t("Many to one")}}', title: '{{t("Many to one")}}',
description: '{{t("Many to one description")}}',
isAssociation: true, isAssociation: true,
default: { default: {
type: 'belongsTo', type: 'belongsTo',

View File

@ -7,6 +7,7 @@ export const o2m: IField = {
group: 'relation', group: 'relation',
order: 4, order: 4,
title: '{{t("One to many")}}', title: '{{t("One to many")}}',
description: '{{t("One to many description")}}',
isAssociation: true, isAssociation: true,
default: { default: {
type: 'hasMany', type: 'hasMany',

View File

@ -9,6 +9,7 @@ export const o2o: IField = {
group: 'relation', group: 'relation',
order: 3, order: 3,
title: '{{t("One to one")}}', title: '{{t("One to one")}}',
description: '{{t("One to one description")}}',
isAssociation: true, isAssociation: true,
default: { default: {
type: 'hasOne', type: 'hasOne',

View File

@ -15,7 +15,10 @@ export const phone: IField = {
type: 'string', type: 'string',
// title, // title,
'x-component': 'Input', 'x-component': 'Input',
'x-validator': 'phone', 'x-component-props': {
type: 'tel'
},
// 'x-validator': 'phone',
}, },
}, },
properties: { properties: {

View File

@ -123,6 +123,7 @@ export default {
"Percent": "Percent", "Percent": "Percent",
"Password": "Password", "Password": "Password",
"Formula": "Formula", "Formula": "Formula",
"Formula description": "Compute a value in each record based on other fields in the same record.",
"Choices": "Choices", "Choices": "Choices",
"Checkbox": "Checkbox", "Checkbox": "Checkbox",
"Single select": "Single select", "Single select": "Single select",
@ -135,6 +136,7 @@ export default {
"Datetime": "Datetime", "Datetime": "Datetime",
"Relation": "Relation", "Relation": "Relation",
"Link to": "Link to", "Link to": "Link to",
"Link to description": "Used to create collection relationships quickly and compatible with most common scenarios. Suitable for non-developer use. When present as a field, it is a drop-down selection used to select records from the target collection. Once created, it will simultaneously generate the associated fields of the current collection in the target collection.",
"Sub-table": "Sub-table", "Sub-table": "Sub-table",
"System info": "System info", "System info": "System info",
"Created at": "Created at", "Created at": "Created at",
@ -164,6 +166,10 @@ export default {
"One to many": "One to many", "One to many": "One to many",
"Many to one": "Many to one", "Many to one": "Many to one",
"Many to many": "Many to many", "Many to many": "Many to many",
"One to one description": "Used to create one-to-one relationships. For example, a user has a profile.",
"One to many description": "Used to create a one-to-many relationship. For example, a country will have many cities and a city can only be in one country. When present as a field, it is a sub-table that displays the records of the associated collection. When created, a Many-to-one field is automatically generated in the associated collection.",
"Many to one description": "Used to create many-to-one relationships. For example, a city can belong to only one country and a country can have many cities. When present as a field, it is a drop-down selection used to select record from the associated collection. Once created, a One-to-many field is automatically generated in the associated collection.",
"Many to many description": "Used to create many-to-many relationships. For example, a student will have many teachers and a teacher will have many students. When present as a field, it is a drop-down selection used to select records from the associated collection.",
"Foreign key 1": "Foreign key 1", "Foreign key 1": "Foreign key 1",
"Foreign key 2": "Foreign key 2", "Foreign key 2": "Foreign key 2",
"Add filter": "Add filter", "Add filter": "Add filter",
@ -451,6 +457,7 @@ export default {
"By field": "By field", "By field": "By field",
"By custom date": "By custom date", "By custom date": "By custom date",
"Advance": "Advance", "Advance": "Advance",
"Advance type": "Advance type",
"End": "End", "End": "End",
"Trigger context": "Trigger context", "Trigger context": "Trigger context",
"Node result": "Node result", "Node result": "Node result",

View File

@ -126,6 +126,7 @@ export default {
"Percent": "百分比", "Percent": "百分比",
"Password": "密码", "Password": "密码",
"Formula": "公式", "Formula": "公式",
"Formula description": "基于同一条记录中的其他字段计算出一个值。",
"Choices": "选择类型", "Choices": "选择类型",
"Checkbox": "勾选", "Checkbox": "勾选",
"Single select": "下拉菜单(单选)", "Single select": "下拉菜单(单选)",
@ -138,6 +139,7 @@ export default {
"Datetime": "日期", "Datetime": "日期",
"Relation": "关系类型", "Relation": "关系类型",
"Link to": "关联", "Link to": "关联",
"Link to description": "用于快速创建表关系,可兼容大多数普通场景。适合非开发人员使用。作为字段存在时,它是一个下拉选择用于选择目标数据表的数据。创建后,将同时在目标数据表中生成当前数据表的关联字段。",
"Sub-table": "子表格", "Sub-table": "子表格",
"System info": "系统信息", "System info": "系统信息",
"Created at": "创建日期", "Created at": "创建日期",
@ -169,7 +171,10 @@ export default {
"Many to many": "多对多", "Many to many": "多对多",
"Foreign key 1": "外键1", "Foreign key 1": "外键1",
"Foreign key 2": "外键2", "Foreign key 2": "外键2",
"One to one description": "用于创建一对一关系,比如一个用户会有一套个人资料。",
"One to many description": "用于创建一对多关系,比如一个国家会有多个城市。作为字段存在时,它是一个子表格用于显示目标数据表的数据。创建后,会在目标数据表里自动生成一个 Many to one 字段。",
"Many to one description": "用于创建多对一关系,比如一个城市只能属于一个国家,一个国家可以有多个城市。作为字段存在时,它是一个下拉选择用于选择目标数据表的数据。创建后,会在目标数据表里自动生成一个 One to many 字段。",
"Many to many description": "用于创建多对多关系,比如一个学生会有多个老师,一个老师也会有多个学生。作为字段存在时,它是一个下拉选择用于选择目标数据表的数据。",
"Add filter": "添加筛选条件", "Add filter": "添加筛选条件",
"Add filter group": "添加筛选分组", "Add filter group": "添加筛选分组",
"is": "等于", "is": "等于",
@ -489,6 +494,7 @@ export default {
'By custom date': '自定义时间', 'By custom date': '自定义时间',
'Advance': '高级模式', 'Advance': '高级模式',
'Advance type': '高级类型',
'End': '结束', 'End': '结束',

View File

@ -0,0 +1,21 @@
import { observer, RecursionField, useFieldSchema } from '@formily/react';
import { Space, Typography } from 'antd';
import React from 'react';
import { useCollectionManager } from '../../../collection-manager/hooks';
import { useCompile } from '../../hooks';
export const FieldSummary = observer((props: any) => {
const { schemaKey } = props;
const { getInterface } = useCollectionManager();
const compile = useCompile();
const schema = getInterface(schemaKey);
if (!schema) return (null);
return (
<div style={{marginBottom: '22px'}}>
<Typography.Title level={3} style={{ margin: '0 0 10px 0' }}>{compile(schema.title)}</Typography.Title>
{ schema.description ? (<Typography.Text type="secondary">{compile(schema.description)}</Typography.Text>) : (null)}
</div>
)
});

View File

@ -0,0 +1 @@
export * from './FieldSummary';

View File

@ -35,4 +35,5 @@ export * from './tabs';
export * from './time-picker'; export * from './time-picker';
export * from './tree-select'; export * from './tree-select';
export * from './upload'; export * from './upload';
export * from './field-summary';
import './index.less'; import './index.less';

View File

@ -5234,14 +5234,7 @@
resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc"
integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==
"@types/react-dom@^16.9.8": "@types/react-dom@^16.9.8", "@types/react-dom@^17.0.0":
version "16.9.16"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-16.9.16.tgz#c591f2ed1c6f32e9759dfa6eb4abfd8041f29e39"
integrity sha512-Oqc0RY4fggGA3ltEgyPLc3IV9T73IGoWjkONbsyJ3ZBn+UPPCYpU2ec0i3cEbJuEdZtkqcCF2l1zf2pBdgUGSg==
dependencies:
"@types/react" "^16"
"@types/react-dom@^17.0.0":
version "17.0.11" version "17.0.11"
resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz#e1eadc3c5e86bdb5f7684e00274ae228e7bcc466" resolved "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz#e1eadc3c5e86bdb5f7684e00274ae228e7bcc466"
integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q== integrity sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==
@ -5301,7 +5294,7 @@
"@types/history" "*" "@types/history" "*"
"@types/react" "*" "@types/react" "*"
"@types/react@*", "@types/react@>=16.9.11", "@types/react@^17.0.0": "@types/react@*", "@types/react@>=16.9.11", "@types/react@^16.9.43", "@types/react@^17.0.0":
version "17.0.34" version "17.0.34"
resolved "https://registry.npmjs.org/@types/react/-/react-17.0.34.tgz#797b66d359b692e3f19991b6b07e4b0c706c0102" resolved "https://registry.npmjs.org/@types/react/-/react-17.0.34.tgz#797b66d359b692e3f19991b6b07e4b0c706c0102"
integrity sha512-46FEGrMjc2+8XhHXILr+3+/sTe3OfzSPU9YGKILLrUYbQ1CLQC9Daqo1KzENGXAWwrFwiY0l4ZbF20gRvgpWTg== integrity sha512-46FEGrMjc2+8XhHXILr+3+/sTe3OfzSPU9YGKILLrUYbQ1CLQC9Daqo1KzENGXAWwrFwiY0l4ZbF20gRvgpWTg==
@ -5310,15 +5303,6 @@
"@types/scheduler" "*" "@types/scheduler" "*"
csstype "^3.0.2" csstype "^3.0.2"
"@types/react@^16", "@types/react@^16.9.43":
version "16.14.26"
resolved "https://registry.yarnpkg.com/@types/react/-/react-16.14.26.tgz#82540a240ba7207ebe87d9579051bc19c9ef7605"
integrity sha512-c/5CYyciOO4XdFcNhZW1O2woVx86k4T+DO2RorHZL7EhitkNQgSD/SgpdZJAUJa/qjVgOmTM44gHkAdZSXeQuQ==
dependencies:
"@types/prop-types" "*"
"@types/scheduler" "*"
csstype "^3.0.2"
"@types/resolve@1.17.1": "@types/resolve@1.17.1":
version "1.17.1" version "1.17.1"
resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6" resolved "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz#3afd6ad8967c77e4376c598a82ddd58f46ec45d6"