feat: improve view action schema initializer
This commit is contained in:
parent
b4dc7f6199
commit
590ca267b2
@ -29,6 +29,7 @@ const useCollectionValues = (options) => {
|
|||||||
name: `t_${uid()}`,
|
name: `t_${uid()}`,
|
||||||
createdBy: true,
|
createdBy: true,
|
||||||
updatedBy: true,
|
updatedBy: true,
|
||||||
|
sortable: true,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
|
@ -10,6 +10,7 @@ export const checkboxGroup: IField = {
|
|||||||
default: {
|
default: {
|
||||||
interface: 'checkboxGroup',
|
interface: 'checkboxGroup',
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
defaultValue: [],
|
||||||
// name,
|
// name,
|
||||||
uiSchema: {
|
uiSchema: {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
|
@ -9,6 +9,7 @@ export const multipleSelect: IField = {
|
|||||||
title: '{{t("Multiple select")}}',
|
title: '{{t("Multiple select")}}',
|
||||||
default: {
|
default: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
defaultValue: [],
|
||||||
// name,
|
// name,
|
||||||
uiSchema: {
|
uiSchema: {
|
||||||
type: 'array',
|
type: 'array',
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
import { useField } from '@formily/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../';
|
||||||
|
|
||||||
|
export const TabsDesigner = () => {
|
||||||
|
const field = useField();
|
||||||
|
return (
|
||||||
|
<GeneralSchemaDesigner>
|
||||||
|
<SchemaSettings.Popup
|
||||||
|
schema={{
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Modal',
|
||||||
|
'x-decorator': 'Form',
|
||||||
|
'x-component-props': {
|
||||||
|
title: '标题',
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</SchemaSettings.Popup>
|
||||||
|
<SchemaSettings.Divider />
|
||||||
|
<SchemaSettings.Remove />
|
||||||
|
</GeneralSchemaDesigner>
|
||||||
|
);
|
||||||
|
};
|
@ -1,12 +1,23 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
||||||
|
import { useSchemaInitializer } from '@nocobase/client';
|
||||||
import { TabPaneProps, Tabs as AntdTabs, TabsProps } from 'antd';
|
import { TabPaneProps, Tabs as AntdTabs, TabsProps } from 'antd';
|
||||||
|
import classNames from 'classnames';
|
||||||
import React from 'react';
|
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) => {
|
export const Tabs: any = observer((props: TabsProps) => {
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { render } = useSchemaInitializer(fieldSchema['x-initializer']);
|
||||||
return (
|
return (
|
||||||
<div>
|
<DndContext>
|
||||||
<AntdTabs>
|
<AntdTabs
|
||||||
|
tabBarExtraContent={{
|
||||||
|
right: render(),
|
||||||
|
}}
|
||||||
|
>
|
||||||
{fieldSchema.mapProperties((schema, key) => {
|
{fieldSchema.mapProperties((schema, key) => {
|
||||||
return (
|
return (
|
||||||
<AntdTabs.TabPane tab={<RecursionField name={key} schema={schema} onlyRenderSelf />} key={key}>
|
<AntdTabs.TabPane tab={<RecursionField name={key} schema={schema} onlyRenderSelf />} key={key}>
|
||||||
@ -15,11 +26,67 @@ export const Tabs: any = observer((props: TabsProps) => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</AntdTabs>
|
</AntdTabs>
|
||||||
</div>
|
</DndContext>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
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) => {
|
Tabs.TabPane = observer((props: TabPaneProps) => {
|
||||||
|
const Designer = useDesigner();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
return <>{props.tab || field.title}</>;
|
console.log('Designer', Designer);
|
||||||
|
return (
|
||||||
|
<SortableItem className={classNames('nb-action-link', designerCss, props.className)}>
|
||||||
|
{props.tab || field.title}
|
||||||
|
<Designer />
|
||||||
|
</SortableItem>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Tabs.Designer = TabsDesigner;
|
||||||
|
@ -2,8 +2,9 @@
|
|||||||
* title: Tabs
|
* title: Tabs
|
||||||
*/
|
*/
|
||||||
import { ISchema } from '@formily/react';
|
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 React from 'react';
|
||||||
|
import { AntdSchemaComponentProvider } from '../../AntdSchemaComponentProvider';
|
||||||
|
|
||||||
const schema: ISchema = {
|
const schema: ISchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@ -46,8 +47,10 @@ const schema: ISchema = {
|
|||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
return (
|
return (
|
||||||
<SchemaComponentProvider components={{ Tabs }}>
|
<SchemaComponentProvider designable components={{ Tabs, Action }}>
|
||||||
|
<AntdSchemaComponentProvider>
|
||||||
<SchemaComponent schema={schema} />
|
<SchemaComponent schema={schema} />
|
||||||
|
</AntdSchemaComponentProvider>
|
||||||
</SchemaComponentProvider>
|
</SchemaComponentProvider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -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 (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
{...props}
|
||||||
|
icon={<FormOutlined />}
|
||||||
|
onClick={({ item }) => {
|
||||||
|
insert(createSchema(item.name));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -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 (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
{...props}
|
||||||
|
icon={<FormOutlined />}
|
||||||
|
onClick={({ item }) => {
|
||||||
|
insert(createSchema(item.name));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -7,6 +7,8 @@ export * from './FormBlockInitializer';
|
|||||||
export * from './GeneralInitializer';
|
export * from './GeneralInitializer';
|
||||||
export * from './LinkToCollectionFieldInitializer';
|
export * from './LinkToCollectionFieldInitializer';
|
||||||
export * from './MarkdownBlockInitializer';
|
export * from './MarkdownBlockInitializer';
|
||||||
|
export * from './RecordFormBlockInitializer';
|
||||||
|
export * from './RecordRelationBlockInitializer';
|
||||||
export * from './SubTableFieldInitializer';
|
export * from './SubTableFieldInitializer';
|
||||||
export * from './TableBlockInitializer';
|
export * from './TableBlockInitializer';
|
||||||
export * from './UserFieldInitializer';
|
export * from './UserFieldInitializer';
|
||||||
|
@ -4,5 +4,44 @@ import { gridRowColWrap } from './utils';
|
|||||||
export const RecordBlockInitializers = {
|
export const RecordBlockInitializers = {
|
||||||
wrap: gridRowColWrap,
|
wrap: gridRowColWrap,
|
||||||
title: "{{t('Add block')}}",
|
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',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
@ -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 (
|
||||||
|
<SchemaComponent
|
||||||
|
schema={{
|
||||||
|
type: 'void',
|
||||||
|
properties: {
|
||||||
|
action1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
borderColor: 'rgb(241, 139, 98)',
|
||||||
|
color: 'rgb(241, 139, 98)',
|
||||||
|
},
|
||||||
|
type: 'dashed',
|
||||||
|
},
|
||||||
|
title: '添加标签页',
|
||||||
|
properties: {
|
||||||
|
drawer1: {
|
||||||
|
'x-decorator': 'Form',
|
||||||
|
'x-component': 'Action.Modal',
|
||||||
|
type: 'void',
|
||||||
|
title: 'Drawer Title',
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
title: '标题',
|
||||||
|
required: true,
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
'x-component': 'Action.Modal.Footer',
|
||||||
|
type: 'void',
|
||||||
|
properties: {
|
||||||
|
cancel: {
|
||||||
|
title: 'Cancel',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
useAction: () => {
|
||||||
|
const ctx = useActionContext();
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
ctx.setVisible(false);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
submit: {
|
||||||
|
title: 'Submit',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
useAction: useSubmitAction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -69,19 +69,19 @@ export const TableRecordActionInitializers = (props: any) => {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Tabs',
|
'x-component': 'Tabs',
|
||||||
'x-component-props': {},
|
'x-component-props': {},
|
||||||
|
'x-initializer': 'TabPaneInitializers',
|
||||||
properties: {
|
properties: {
|
||||||
tab1: {
|
tab1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '详情',
|
title: '详情',
|
||||||
'x-component': 'Tabs.TabPane',
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designer': 'Tabs.Designer',
|
||||||
'x-component-props': {},
|
'x-component-props': {},
|
||||||
properties: {
|
properties: {
|
||||||
grid: {
|
grid: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'Form',
|
|
||||||
'x-component': 'Grid',
|
'x-component': 'Grid',
|
||||||
'x-read-pretty': true,
|
'x-initializer': 'RecordBlockInitializers',
|
||||||
'x-item-initializer': 'RecordBlockInitializer',
|
|
||||||
properties: {},
|
properties: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -10,6 +10,8 @@ import { TableActionInitializers } from './TableActionInitializers';
|
|||||||
import { TableColumnInitializers } from './TableColumnInitializers';
|
import { TableColumnInitializers } from './TableColumnInitializers';
|
||||||
import { TableFieldRecordActionInitializers } from './TableFieldRecordActionInitializers';
|
import { TableFieldRecordActionInitializers } from './TableFieldRecordActionInitializers';
|
||||||
import { TableRecordActionInitializers } from './TableRecordActionInitializers';
|
import { TableRecordActionInitializers } from './TableRecordActionInitializers';
|
||||||
|
import { TabPaneInitializers } from './TabPaneInitializers';
|
||||||
|
|
||||||
export const items = { ...Items };
|
export const items = { ...Items };
|
||||||
|
|
||||||
export const initializes = {
|
export const initializes = {
|
||||||
@ -35,4 +37,6 @@ export const initializes = {
|
|||||||
TableRecordActionInitializers,
|
TableRecordActionInitializers,
|
||||||
// 表格字段(子表格)场景的当前行记录的「操作配置」
|
// 表格字段(子表格)场景的当前行记录的「操作配置」
|
||||||
TableFieldRecordActionInitializers,
|
TableFieldRecordActionInitializers,
|
||||||
|
// 添加标签页
|
||||||
|
TabPaneInitializers,
|
||||||
};
|
};
|
||||||
|
@ -76,6 +76,10 @@ export const useTableColumnInitializerFields = () => {
|
|||||||
},
|
},
|
||||||
} as SchemaInitializerItemOptions;
|
} as SchemaInitializerItemOptions;
|
||||||
}
|
}
|
||||||
|
const componentProps = {};
|
||||||
|
if (field.interface === 'attachment') {
|
||||||
|
componentProps['size'] = 'small';
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
type: 'item',
|
type: 'item',
|
||||||
title: field?.uiSchema?.title || field.name,
|
title: field?.uiSchema?.title || field.name,
|
||||||
@ -86,6 +90,9 @@ export const useTableColumnInitializerFields = () => {
|
|||||||
name: field.name,
|
name: field.name,
|
||||||
'x-collection-field': `${name}.${field.name}`,
|
'x-collection-field': `${name}.${field.name}`,
|
||||||
'x-component': 'CollectionField',
|
'x-component': 'CollectionField',
|
||||||
|
'x-component-props': {
|
||||||
|
...componentProps,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
} as SchemaInitializerItemOptions;
|
} as SchemaInitializerItemOptions;
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user