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()}`,
|
||||
createdBy: true,
|
||||
updatedBy: true,
|
||||
sortable: true,
|
||||
},
|
||||
}),
|
||||
{
|
||||
|
@ -10,6 +10,7 @@ export const checkboxGroup: IField = {
|
||||
default: {
|
||||
interface: 'checkboxGroup',
|
||||
type: 'array',
|
||||
defaultValue: [],
|
||||
// name,
|
||||
uiSchema: {
|
||||
type: 'string',
|
||||
|
@ -9,6 +9,7 @@ export const multipleSelect: IField = {
|
||||
title: '{{t("Multiple select")}}',
|
||||
default: {
|
||||
type: 'array',
|
||||
defaultValue: [],
|
||||
// name,
|
||||
uiSchema: {
|
||||
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 { 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 (
|
||||
<div>
|
||||
<AntdTabs>
|
||||
<DndContext>
|
||||
<AntdTabs
|
||||
tabBarExtraContent={{
|
||||
right: render(),
|
||||
}}
|
||||
>
|
||||
{fieldSchema.mapProperties((schema, key) => {
|
||||
return (
|
||||
<AntdTabs.TabPane tab={<RecursionField name={key} schema={schema} onlyRenderSelf />} key={key}>
|
||||
@ -15,11 +26,67 @@ export const Tabs: any = observer((props: TabsProps) => {
|
||||
);
|
||||
})}
|
||||
</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) => {
|
||||
const Designer = useDesigner();
|
||||
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
|
||||
*/
|
||||
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 (
|
||||
<SchemaComponentProvider components={{ Tabs }}>
|
||||
<SchemaComponentProvider designable components={{ Tabs, Action }}>
|
||||
<AntdSchemaComponentProvider>
|
||||
<SchemaComponent schema={schema} />
|
||||
</AntdSchemaComponentProvider>
|
||||
</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 './LinkToCollectionFieldInitializer';
|
||||
export * from './MarkdownBlockInitializer';
|
||||
export * from './RecordFormBlockInitializer';
|
||||
export * from './RecordRelationBlockInitializer';
|
||||
export * from './SubTableFieldInitializer';
|
||||
export * from './TableBlockInitializer';
|
||||
export * from './UserFieldInitializer';
|
||||
|
@ -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',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@ -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',
|
||||
'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: {},
|
||||
},
|
||||
},
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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;
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user