From 590ca267b27b093b67aa140c4e94fd2b97c8eeb6 Mon Sep 17 00:00:00 2001 From: chenos Date: Thu, 3 Mar 2022 23:02:55 +0800 Subject: [PATCH] feat: improve view action schema initializer --- .../Configuration/ConfigurationTable.tsx | 1 + .../interfaces/checkboxGroup.ts | 1 + .../interfaces/multipleSelect.ts | 1 + .../antd/tabs/Tabs.Designer.tsx | 25 +++++ .../src/schema-component/antd/tabs/Tabs.tsx | 75 ++++++++++++- .../antd/tabs/demos/demo1.tsx | 9 +- .../Items/RecordFormBlockInitializer.tsx | 67 ++++++++++++ .../Items/RecordRelationBlockInitializer.tsx | 67 ++++++++++++ .../Initializers/Items/index.ts | 2 + .../Initializers/RecordBlockInitializers.tsx | 41 ++++++- .../Initializers/TabPaneInitializers.tsx | 101 ++++++++++++++++++ .../TableRecordActionInitializers.tsx | 6 +- .../schema-initializer/Initializers/index.tsx | 4 + .../schema-initializer/Initializers/utils.ts | 7 ++ 14 files changed, 396 insertions(+), 11 deletions(-) create mode 100644 packages/client/src/schema-component/antd/tabs/Tabs.Designer.tsx create mode 100644 packages/client/src/schema-initializer/Initializers/Items/RecordFormBlockInitializer.tsx create mode 100644 packages/client/src/schema-initializer/Initializers/Items/RecordRelationBlockInitializer.tsx create mode 100644 packages/client/src/schema-initializer/Initializers/TabPaneInitializers.tsx diff --git a/packages/client/src/collection-manager/Configuration/ConfigurationTable.tsx b/packages/client/src/collection-manager/Configuration/ConfigurationTable.tsx index fea430cc1..96fa6b9f7 100644 --- a/packages/client/src/collection-manager/Configuration/ConfigurationTable.tsx +++ b/packages/client/src/collection-manager/Configuration/ConfigurationTable.tsx @@ -29,6 +29,7 @@ const useCollectionValues = (options) => { name: `t_${uid()}`, createdBy: true, updatedBy: true, + sortable: true, }, }), { diff --git a/packages/client/src/collection-manager/interfaces/checkboxGroup.ts b/packages/client/src/collection-manager/interfaces/checkboxGroup.ts index e910fed63..2df5602f8 100644 --- a/packages/client/src/collection-manager/interfaces/checkboxGroup.ts +++ b/packages/client/src/collection-manager/interfaces/checkboxGroup.ts @@ -10,6 +10,7 @@ export const checkboxGroup: IField = { default: { interface: 'checkboxGroup', type: 'array', + defaultValue: [], // name, uiSchema: { type: 'string', diff --git a/packages/client/src/collection-manager/interfaces/multipleSelect.ts b/packages/client/src/collection-manager/interfaces/multipleSelect.ts index 03ac13d90..c3c940852 100644 --- a/packages/client/src/collection-manager/interfaces/multipleSelect.ts +++ b/packages/client/src/collection-manager/interfaces/multipleSelect.ts @@ -9,6 +9,7 @@ export const multipleSelect: IField = { title: '{{t("Multiple select")}}', default: { type: 'array', + defaultValue: [], // name, uiSchema: { type: 'array', diff --git a/packages/client/src/schema-component/antd/tabs/Tabs.Designer.tsx b/packages/client/src/schema-component/antd/tabs/Tabs.Designer.tsx new file mode 100644 index 000000000..65d741247 --- /dev/null +++ b/packages/client/src/schema-component/antd/tabs/Tabs.Designer.tsx @@ -0,0 +1,25 @@ +import { useField } from '@formily/react'; +import React from 'react'; +import { GeneralSchemaDesigner, SchemaSettings } from '../../../'; + +export const TabsDesigner = () => { + const field = useField(); + return ( + + + 编辑 + + + + + ); +}; diff --git a/packages/client/src/schema-component/antd/tabs/Tabs.tsx b/packages/client/src/schema-component/antd/tabs/Tabs.tsx index 7a3aa0f96..914d3ec81 100644 --- a/packages/client/src/schema-component/antd/tabs/Tabs.tsx +++ b/packages/client/src/schema-component/antd/tabs/Tabs.tsx @@ -1,12 +1,23 @@ +import { css } from '@emotion/css'; import { observer, RecursionField, useField, useFieldSchema } from '@formily/react'; +import { useSchemaInitializer } from '@nocobase/client'; import { TabPaneProps, Tabs as AntdTabs, TabsProps } from 'antd'; +import classNames from 'classnames'; import React from 'react'; +import { DndContext, SortableItem } from '../../common'; +import { useDesigner } from '../../hooks/useDesigner'; +import { TabsDesigner } from './Tabs.Designer'; export const Tabs: any = observer((props: TabsProps) => { const fieldSchema = useFieldSchema(); + const { render } = useSchemaInitializer(fieldSchema['x-initializer']); return ( -
- + + {fieldSchema.mapProperties((schema, key) => { return ( } key={key}> @@ -15,11 +26,67 @@ export const Tabs: any = observer((props: TabsProps) => { ); })} -
+ ); }); +const designerCss = css` + position: relative; + &:hover { + > .general-schema-designer { + display: block; + } + } + &.nb-action-link { + > .general-schema-designer { + top: -10px; + bottom: -10px; + left: -10px; + right: -10px; + } + } + > .general-schema-designer { + position: absolute; + z-index: 999; + top: 0; + bottom: 0; + left: 0; + right: 0; + display: none; + background: rgba(241, 139, 98, 0.06); + border: 0; + top: 0; + bottom: 0; + left: 0; + right: 0; + pointer-events: none; + > .general-schema-designer-icons { + position: absolute; + right: 2px; + top: 2px; + line-height: 16px; + pointer-events: all; + .ant-space-item { + background-color: #f18b62; + color: #fff; + line-height: 16px; + width: 16px; + padding-left: 1px; + } + } + } +`; + Tabs.TabPane = observer((props: TabPaneProps) => { + const Designer = useDesigner(); const field = useField(); - return <>{props.tab || field.title}; + console.log('Designer', Designer); + return ( + + {props.tab || field.title} + + + ); }); + +Tabs.Designer = TabsDesigner; diff --git a/packages/client/src/schema-component/antd/tabs/demos/demo1.tsx b/packages/client/src/schema-component/antd/tabs/demos/demo1.tsx index a91c59303..4452822e2 100644 --- a/packages/client/src/schema-component/antd/tabs/demos/demo1.tsx +++ b/packages/client/src/schema-component/antd/tabs/demos/demo1.tsx @@ -2,8 +2,9 @@ * title: Tabs */ import { ISchema } from '@formily/react'; -import { SchemaComponent, SchemaComponentProvider, Tabs } from '@nocobase/client'; +import { Action, SchemaComponent, SchemaComponentProvider, Tabs } from '@nocobase/client'; import React from 'react'; +import { AntdSchemaComponentProvider } from '../../AntdSchemaComponentProvider'; const schema: ISchema = { type: 'object', @@ -46,8 +47,10 @@ const schema: ISchema = { export default () => { return ( - - + + + + ); }; diff --git a/packages/client/src/schema-initializer/Initializers/Items/RecordFormBlockInitializer.tsx b/packages/client/src/schema-initializer/Initializers/Items/RecordFormBlockInitializer.tsx new file mode 100644 index 000000000..efa608f14 --- /dev/null +++ b/packages/client/src/schema-initializer/Initializers/Items/RecordFormBlockInitializer.tsx @@ -0,0 +1,67 @@ +import { FormOutlined } from '@ant-design/icons'; +import { ISchema } from '@formily/react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { SchemaInitializer } from '../..'; +import { useCollectionManager } from '../../../collection-manager'; + +const createSchema = (collectionName) => { + const schema: ISchema = { + type: 'void', + 'x-collection': 'collections', + 'x-decorator': 'ResourceActionProvider', + 'x-decorator-props': { + collection: collectionName, + request: { + resource: collectionName, + action: 'get', + params: {}, + }, + }, + 'x-designer': 'Form.Designer', + 'x-component': 'CardItem', + properties: { + form: { + type: 'void', + 'x-decorator': 'Form', + 'x-decorator-props': {}, + properties: { + grid: { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'GridFormItemInitializers', + properties: {}, + }, + actions: { + type: 'void', + 'x-initializer': 'FormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + properties: {}, + }, + }, + }, + }, + }; + return schema; +}; + +export const RecordFormBlockInitializer = (props) => { + const { insert } = props; + const { collections } = useCollectionManager(); + const { t } = useTranslation(); + return ( + } + onClick={({ item }) => { + insert(createSchema(item.name)); + }} + /> + ); +}; diff --git a/packages/client/src/schema-initializer/Initializers/Items/RecordRelationBlockInitializer.tsx b/packages/client/src/schema-initializer/Initializers/Items/RecordRelationBlockInitializer.tsx new file mode 100644 index 000000000..9b2aa069f --- /dev/null +++ b/packages/client/src/schema-initializer/Initializers/Items/RecordRelationBlockInitializer.tsx @@ -0,0 +1,67 @@ +import { FormOutlined } from '@ant-design/icons'; +import { ISchema } from '@formily/react'; +import React from 'react'; +import { useTranslation } from 'react-i18next'; +import { SchemaInitializer } from '../..'; +import { useCollectionManager } from '../../../collection-manager'; + +const createSchema = (collectionName) => { + const schema: ISchema = { + type: 'void', + 'x-collection': 'collections', + 'x-decorator': 'ResourceActionProvider', + 'x-decorator-props': { + collection: collectionName, + request: { + resource: collectionName, + action: 'get', + params: {}, + }, + }, + 'x-designer': 'Form.Designer', + 'x-component': 'CardItem', + properties: { + form: { + type: 'void', + 'x-decorator': 'Form', + 'x-decorator-props': {}, + properties: { + grid: { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'GridFormItemInitializers', + properties: {}, + }, + actions: { + type: 'void', + 'x-initializer': 'FormActionInitializers', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + properties: {}, + }, + }, + }, + }, + }; + return schema; +}; + +export const RecordRelationBlockInitializer = (props) => { + const { insert } = props; + const { collections } = useCollectionManager(); + const { t } = useTranslation(); + return ( + } + onClick={({ item }) => { + insert(createSchema(item.name)); + }} + /> + ); +}; diff --git a/packages/client/src/schema-initializer/Initializers/Items/index.ts b/packages/client/src/schema-initializer/Initializers/Items/index.ts index 22ef4190b..0d7b4b4d4 100644 --- a/packages/client/src/schema-initializer/Initializers/Items/index.ts +++ b/packages/client/src/schema-initializer/Initializers/Items/index.ts @@ -7,6 +7,8 @@ export * from './FormBlockInitializer'; export * from './GeneralInitializer'; export * from './LinkToCollectionFieldInitializer'; export * from './MarkdownBlockInitializer'; +export * from './RecordFormBlockInitializer'; +export * from './RecordRelationBlockInitializer'; export * from './SubTableFieldInitializer'; export * from './TableBlockInitializer'; export * from './UserFieldInitializer'; diff --git a/packages/client/src/schema-initializer/Initializers/RecordBlockInitializers.tsx b/packages/client/src/schema-initializer/Initializers/RecordBlockInitializers.tsx index 3b06c3bb0..dc63d4324 100644 --- a/packages/client/src/schema-initializer/Initializers/RecordBlockInitializers.tsx +++ b/packages/client/src/schema-initializer/Initializers/RecordBlockInitializers.tsx @@ -4,5 +4,44 @@ import { gridRowColWrap } from './utils'; export const RecordBlockInitializers = { wrap: gridRowColWrap, title: "{{t('Add block')}}", - items: [], + items: [ + { + type: 'itemGroup', + title: 'Data blocks', + children: [ + { + type: 'item', + title: 'Details', + component: 'RecordFormBlockInitializer', + }, + { + type: 'item', + title: 'Form', + component: 'RecordFormBlockInitializer', + }, + ], + }, + { + type: 'itemGroup', + title: '关系数据区块', + children: [ + { + type: 'item', + title: '关系数据', + component: 'RecordRelationBlockInitializer', + }, + ], + }, + { + type: 'itemGroup', + title: 'Media', + children: [ + { + type: 'item', + title: 'Markdown', + component: 'MarkdownBlockInitializer', + }, + ], + }, + ], }; diff --git a/packages/client/src/schema-initializer/Initializers/TabPaneInitializers.tsx b/packages/client/src/schema-initializer/Initializers/TabPaneInitializers.tsx new file mode 100644 index 000000000..0928f317b --- /dev/null +++ b/packages/client/src/schema-initializer/Initializers/TabPaneInitializers.tsx @@ -0,0 +1,101 @@ +import { useForm } from '@formily/react'; +import React from 'react'; +import { SchemaComponent, useActionContext, useDesignable } from '../..'; + +export const TabPaneInitializers = () => { + const { designable, insertBeforeEnd } = useDesignable(); + if (!designable) { + return null; + } + const useSubmitAction = () => { + const form = useForm(); + const ctx = useActionContext(); + return { + async run() { + form.submit(); + const { title } = form.values; + insertBeforeEnd({ + type: 'void', + title, + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + properties: {}, + }, + }, + }); + ctx.setVisible(false); + }, + }; + }; + return ( + { + const ctx = useActionContext(); + return { + async run() { + ctx.setVisible(false); + }, + }; + }, + }, + }, + submit: { + title: 'Submit', + 'x-component': 'Action', + 'x-component-props': { + type: 'primary', + useAction: useSubmitAction, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }} + /> + ); +}; diff --git a/packages/client/src/schema-initializer/Initializers/TableRecordActionInitializers.tsx b/packages/client/src/schema-initializer/Initializers/TableRecordActionInitializers.tsx index 0062414bb..d1faf9780 100644 --- a/packages/client/src/schema-initializer/Initializers/TableRecordActionInitializers.tsx +++ b/packages/client/src/schema-initializer/Initializers/TableRecordActionInitializers.tsx @@ -69,19 +69,19 @@ export const TableRecordActionInitializers = (props: any) => { type: 'void', 'x-component': 'Tabs', 'x-component-props': {}, + 'x-initializer': 'TabPaneInitializers', properties: { tab1: { type: 'void', title: '详情', 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', 'x-component-props': {}, properties: { grid: { type: 'void', - 'x-decorator': 'Form', 'x-component': 'Grid', - 'x-read-pretty': true, - 'x-item-initializer': 'RecordBlockInitializer', + 'x-initializer': 'RecordBlockInitializers', properties: {}, }, }, diff --git a/packages/client/src/schema-initializer/Initializers/index.tsx b/packages/client/src/schema-initializer/Initializers/index.tsx index 4086b95c7..3c1a26714 100644 --- a/packages/client/src/schema-initializer/Initializers/index.tsx +++ b/packages/client/src/schema-initializer/Initializers/index.tsx @@ -10,6 +10,8 @@ import { TableActionInitializers } from './TableActionInitializers'; import { TableColumnInitializers } from './TableColumnInitializers'; import { TableFieldRecordActionInitializers } from './TableFieldRecordActionInitializers'; import { TableRecordActionInitializers } from './TableRecordActionInitializers'; +import { TabPaneInitializers } from './TabPaneInitializers'; + export const items = { ...Items }; export const initializes = { @@ -35,4 +37,6 @@ export const initializes = { TableRecordActionInitializers, // 表格字段(子表格)场景的当前行记录的「操作配置」 TableFieldRecordActionInitializers, + // 添加标签页 + TabPaneInitializers, }; diff --git a/packages/client/src/schema-initializer/Initializers/utils.ts b/packages/client/src/schema-initializer/Initializers/utils.ts index 88485a26c..6fa246441 100644 --- a/packages/client/src/schema-initializer/Initializers/utils.ts +++ b/packages/client/src/schema-initializer/Initializers/utils.ts @@ -76,6 +76,10 @@ export const useTableColumnInitializerFields = () => { }, } as SchemaInitializerItemOptions; } + const componentProps = {}; + if (field.interface === 'attachment') { + componentProps['size'] = 'small'; + } return { type: 'item', title: field?.uiSchema?.title || field.name, @@ -86,6 +90,9 @@ export const useTableColumnInitializerFields = () => { name: field.name, 'x-collection-field': `${name}.${field.name}`, 'x-component': 'CollectionField', + 'x-component-props': { + ...componentProps, + }, }, } as SchemaInitializerItemOptions; });