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;
});