mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 10:46:54 +00:00
feat(client): x-designer
This commit is contained in:
parent
992befe89e
commit
2c38b63f18
@ -1,18 +1,12 @@
|
||||
import React from 'react';
|
||||
import { useDesignable } from '../..';
|
||||
import { SortableItem } from '../../common';
|
||||
import { useDesigner } from '../../hooks';
|
||||
|
||||
export const BlockItem: React.FC<any> = (props) => {
|
||||
const { remove } = useDesignable();
|
||||
const Designer = useDesigner();
|
||||
return (
|
||||
<SortableItem className={'nb-block-item'} style={{ position: 'relative' }}>
|
||||
<a
|
||||
onClick={() => {
|
||||
remove();
|
||||
}}
|
||||
>
|
||||
删除
|
||||
</a>
|
||||
<Designer />
|
||||
{props.children}
|
||||
</SortableItem>
|
||||
);
|
||||
|
@ -0,0 +1,19 @@
|
||||
import React from 'react';
|
||||
import { DragHandler } from '../../common';
|
||||
import { useDesignable } from '../../hooks';
|
||||
|
||||
export const TestDesigner = () => {
|
||||
const { remove } = useDesignable();
|
||||
return (
|
||||
<div>
|
||||
<a
|
||||
onClick={() => {
|
||||
remove();
|
||||
}}
|
||||
>
|
||||
删除
|
||||
</a>
|
||||
<DragHandler/>
|
||||
</div>
|
||||
);
|
||||
};
|
@ -1,2 +1,3 @@
|
||||
export * from './BlockItem';
|
||||
export * from './TestDesigner';
|
||||
|
||||
|
@ -2,6 +2,7 @@ export * from './useAttach';
|
||||
export * from './useCompile';
|
||||
export * from './useComponent';
|
||||
export * from './useDesignable';
|
||||
export * from './useDesigner';
|
||||
export * from './useFieldProps';
|
||||
export * from './useSchemaComponentContext';
|
||||
|
||||
|
@ -93,6 +93,18 @@ export class Designable {
|
||||
});
|
||||
}
|
||||
});
|
||||
this.on('patch', async ({ schema }) => {
|
||||
refresh();
|
||||
if (schema?.['x-uid']) {
|
||||
await api.request({
|
||||
url: `/uiSchemas:patch`,
|
||||
method: 'post',
|
||||
data: {
|
||||
...schema,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
this.on('remove', async ({ removed }) => {
|
||||
refresh();
|
||||
if (removed?.['x-uid']) {
|
||||
@ -121,14 +133,14 @@ export class Designable {
|
||||
generateUid(schema);
|
||||
}
|
||||
|
||||
on(name: 'insertAdjacent' | 'remove' | 'error', listener: any) {
|
||||
on(name: 'insertAdjacent' | 'remove' | 'error' | 'patch', listener: any) {
|
||||
if (!this.events[name]) {
|
||||
this.events[name] = [];
|
||||
}
|
||||
this.events[name].push(listener);
|
||||
}
|
||||
|
||||
emit(name: 'insertAdjacent' | 'remove' | 'error', ...args) {
|
||||
emit(name: 'insertAdjacent' | 'remove' | 'error' | 'patch', ...args) {
|
||||
if (!this.events[name]) {
|
||||
return;
|
||||
}
|
||||
@ -435,6 +447,7 @@ export function useDesignable() {
|
||||
const dn = createDesignable({ api, refresh, current: fieldSchema });
|
||||
dn.loadAPIClientEvents();
|
||||
return {
|
||||
dn,
|
||||
designable,
|
||||
reset,
|
||||
refresh,
|
||||
|
@ -0,0 +1,9 @@
|
||||
import { useFieldSchema } from '@formily/react';
|
||||
import { useComponent } from '.';
|
||||
|
||||
const Def = () => null;
|
||||
|
||||
export const useDesigner = () => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
return useComponent(fieldSchema['x-designer'], Def);
|
||||
};
|
@ -18,6 +18,7 @@ const createSchema = (collectionName) => {
|
||||
params: {},
|
||||
},
|
||||
},
|
||||
'x-designer': 'TestDesigner',
|
||||
'x-component': 'CardItem',
|
||||
properties: {
|
||||
form: {
|
||||
@ -33,8 +34,14 @@ const createSchema = (collectionName) => {
|
||||
},
|
||||
actions: {
|
||||
type: 'void',
|
||||
'x-component': 'ActionBar',
|
||||
'x-action-initializer': 'FormActionInitializer',
|
||||
'x-component': 'ActionBar',
|
||||
'x-component-props': {
|
||||
layout: 'one-column',
|
||||
style: {
|
||||
marginTop: 24,
|
||||
},
|
||||
},
|
||||
properties: {},
|
||||
},
|
||||
},
|
||||
|
@ -0,0 +1,29 @@
|
||||
import { FormOutlined } from '@ant-design/icons';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SchemaInitializer } from '../..';
|
||||
|
||||
const itemWrap = SchemaInitializer.itemWrap;
|
||||
|
||||
export const MarkdownBlock = itemWrap((props) => {
|
||||
const { insert } = props;
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<SchemaInitializer.Item
|
||||
{...props}
|
||||
icon={<FormOutlined />}
|
||||
onClick={() => {
|
||||
insert({
|
||||
type: 'void',
|
||||
'x-designer': 'Markdown.Void.Designer',
|
||||
'x-decorator': 'CardItem',
|
||||
'x-component': 'Markdown.Void',
|
||||
'x-editable': false,
|
||||
'x-component-props': {
|
||||
content: '# Markdown content',
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
@ -16,7 +16,6 @@ const createSchema = (collectionName) => {
|
||||
resource: collectionName,
|
||||
action: 'list',
|
||||
params: {
|
||||
perPage: 20,
|
||||
pageSize: 20,
|
||||
filter: {},
|
||||
// sort: ['sort'],
|
||||
@ -24,15 +23,21 @@ const createSchema = (collectionName) => {
|
||||
},
|
||||
},
|
||||
},
|
||||
'x-designer': 'TestDesigner',
|
||||
'x-component': 'CardItem',
|
||||
properties: {
|
||||
actions: {
|
||||
type: 'void',
|
||||
'x-component': 'ActionBar',
|
||||
'x-action-initializer': 'TableActionInitializer',
|
||||
'x-component': 'ActionBar',
|
||||
'x-component-props': {
|
||||
style: {
|
||||
marginBottom: 16,
|
||||
},
|
||||
},
|
||||
properties: {},
|
||||
},
|
||||
table1: {
|
||||
table: {
|
||||
type: 'void',
|
||||
'x-component': 'VoidTable',
|
||||
'x-component-props': {
|
||||
@ -47,9 +52,10 @@ const createSchema = (collectionName) => {
|
||||
actions: {
|
||||
type: 'void',
|
||||
title: 'Actions',
|
||||
'x-designer': 'TestDesigner',
|
||||
'x-decorator': 'TableColumnActionBar',
|
||||
'x-component': 'VoidTable.Column',
|
||||
'x-action-initializer': 'TableColumnActionInitializer',
|
||||
'x-action-initializer': 'TableRecordActionInitializer',
|
||||
properties: {
|
||||
actions: {
|
||||
type: 'void',
|
||||
|
@ -4,6 +4,7 @@ import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SchemaInitializer } from '../..';
|
||||
import { FormBlock } from './FormBlock';
|
||||
import { MarkdownBlock } from './MarkdownBlock';
|
||||
import { TableBlock } from './TableBlock';
|
||||
|
||||
const gridRowColWrap = (schema: ISchema) => {
|
||||
@ -45,6 +46,17 @@ export const BlockInitializer = observer((props: any) => {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'itemGroup',
|
||||
title: t('Media'),
|
||||
children: [
|
||||
{
|
||||
type: 'item',
|
||||
title: t('Markdown'),
|
||||
component: MarkdownBlock,
|
||||
},
|
||||
],
|
||||
},
|
||||
]}
|
||||
>
|
||||
{t('Add block')}
|
||||
|
@ -33,6 +33,7 @@ const InitializeAction = SchemaInitializer.itemWrap((props) => {
|
||||
}
|
||||
insert({
|
||||
type: 'void',
|
||||
'x-designer': 'TestDesigner',
|
||||
'x-component': 'Action',
|
||||
...item.schema,
|
||||
});
|
||||
|
@ -34,6 +34,7 @@ const InitializeAction = SchemaInitializer.itemWrap((props) => {
|
||||
}
|
||||
insert({
|
||||
type: 'void',
|
||||
'x-designer': 'TestDesigner',
|
||||
'x-component': 'Action',
|
||||
...item.schema,
|
||||
});
|
||||
@ -52,7 +53,6 @@ export const FormActionInitializer = observer((props: any) => {
|
||||
return (
|
||||
<SchemaInitializer.Button
|
||||
insertPosition={'beforeEnd'}
|
||||
style={{ marginLeft: 8 }}
|
||||
items={[
|
||||
{
|
||||
type: 'itemGroup',
|
||||
|
@ -2,11 +2,12 @@ import { ISchema, observer, Schema, useFieldSchema } from '@formily/react';
|
||||
import { uid } from '@formily/shared';
|
||||
import { Switch } from 'antd';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { SchemaInitializer, SchemaInitializerItemOptions } from '../..';
|
||||
import { useCollection } from '../../../collection-manager';
|
||||
import { useDesignable } from '../../../schema-component';
|
||||
|
||||
const useFormItemInitializerFields = () => {
|
||||
const useFormItems = () => {
|
||||
const { name, fields } = useCollection();
|
||||
return fields?.map((field) => {
|
||||
return {
|
||||
@ -15,6 +16,7 @@ const useFormItemInitializerFields = () => {
|
||||
component: InitializeFormItem,
|
||||
schema: {
|
||||
name: field.name,
|
||||
'x-designer': 'TestDesigner',
|
||||
'x-component': 'CollectionField',
|
||||
'x-decorator': 'FormItem',
|
||||
'x-collection-field': `${name}.${field.name}`,
|
||||
@ -100,9 +102,13 @@ const InitializeTextFormItem = itemWrap((props) => {
|
||||
onClick={() => {
|
||||
insert({
|
||||
type: 'void',
|
||||
'x-component': 'Markdown.Void',
|
||||
'x-editable': false,
|
||||
'x-decorator': 'FormItem',
|
||||
// 'x-editable': false,
|
||||
'x-designer': 'Markdown.Void.Designer',
|
||||
'x-component': 'Markdown.Void',
|
||||
'x-component-props': {
|
||||
content: '# Markdown content',
|
||||
},
|
||||
});
|
||||
}}
|
||||
/>
|
||||
@ -110,6 +116,7 @@ const InitializeTextFormItem = itemWrap((props) => {
|
||||
});
|
||||
|
||||
export const FormItemInitializer = observer((props: any) => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<SchemaInitializer.Button
|
||||
wrap={gridRowColWrap}
|
||||
@ -117,20 +124,20 @@ export const FormItemInitializer = observer((props: any) => {
|
||||
items={[
|
||||
{
|
||||
type: 'itemGroup',
|
||||
title: 'Display fields',
|
||||
children: useFormItemInitializerFields(),
|
||||
title: t('Display fields'),
|
||||
children: useFormItems(),
|
||||
},
|
||||
{
|
||||
type: 'divider',
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
title: 'Add text',
|
||||
title: t('Add text'),
|
||||
component: InitializeTextFormItem,
|
||||
},
|
||||
]}
|
||||
>
|
||||
Configure fields
|
||||
{t('Configure fields')}
|
||||
</SchemaInitializer.Button>
|
||||
);
|
||||
});
|
||||
|
@ -22,93 +22,15 @@ const gridRowColWrap = (schema: ISchema) => {
|
||||
|
||||
const itemWrap = SchemaInitializer.itemWrap;
|
||||
|
||||
const TestInitializerItem = itemWrap((props) => {
|
||||
const FormBlock = itemWrap((props) => {
|
||||
const { insert } = props;
|
||||
return (
|
||||
<SchemaInitializer.Item
|
||||
icon={<FormOutlined />}
|
||||
onClick={() => {
|
||||
insert({
|
||||
type: 'void',
|
||||
name: uid(),
|
||||
'x-decorator': 'CardItem',
|
||||
'x-component': 'Grid',
|
||||
'x-uid': uid(),
|
||||
properties: {
|
||||
row1: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Row',
|
||||
'x-uid': uid(),
|
||||
properties: {
|
||||
col11: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Col',
|
||||
properties: {
|
||||
block1: {
|
||||
type: 'void',
|
||||
title: '1',
|
||||
'x-decorator': 'BlockItem',
|
||||
'x-component': 'Block',
|
||||
},
|
||||
block2: {
|
||||
type: 'void',
|
||||
title: '2',
|
||||
'x-decorator': 'BlockItem',
|
||||
'x-component': 'Block',
|
||||
},
|
||||
},
|
||||
},
|
||||
col12: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Col',
|
||||
properties: {
|
||||
block3: {
|
||||
type: 'void',
|
||||
title: '3',
|
||||
'x-decorator': 'BlockItem',
|
||||
'x-component': 'Block',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
row2: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Row',
|
||||
'x-uid': uid(),
|
||||
properties: {
|
||||
col21: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Col',
|
||||
properties: {
|
||||
block4: {
|
||||
type: 'void',
|
||||
title: '4',
|
||||
'x-decorator': 'BlockItem',
|
||||
'x-component': 'Block',
|
||||
},
|
||||
},
|
||||
},
|
||||
col22: {
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Col',
|
||||
properties: {
|
||||
block5: {
|
||||
type: 'void',
|
||||
title: '5',
|
||||
'x-decorator': 'BlockItem',
|
||||
'x-component': 'Block',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
insert({});
|
||||
}}
|
||||
>
|
||||
Test
|
||||
</SchemaInitializer.Item>
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
@ -125,12 +47,12 @@ export const RecordBlockInitializer = observer((props: any) => {
|
||||
{
|
||||
type: 'item',
|
||||
title: 'Form',
|
||||
component: TestInitializerItem,
|
||||
component: FormBlock,
|
||||
},
|
||||
{
|
||||
type: 'item',
|
||||
title: 'Details',
|
||||
component: TestInitializerItem,
|
||||
component: FormBlock,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
@ -34,6 +34,7 @@ const InitializeAction = SchemaInitializer.itemWrap((props) => {
|
||||
}
|
||||
insert({
|
||||
type: 'void',
|
||||
'x-designer': 'TestDesigner',
|
||||
'x-component': 'Action',
|
||||
...item.schema,
|
||||
});
|
||||
@ -79,12 +80,14 @@ export const TableActionInitializer = observer((props: any) => {
|
||||
'x-component': 'Action',
|
||||
'x-component-props': {
|
||||
type: 'primary',
|
||||
openMode: 'drawer',
|
||||
},
|
||||
properties: {
|
||||
drawer: {
|
||||
type: 'void',
|
||||
title: '{{ t("Add new record") }}',
|
||||
'x-component': 'Action.Drawer',
|
||||
'x-component': 'Action.Container',
|
||||
'x-component-props': {},
|
||||
'x-decorator': 'Form',
|
||||
properties: {
|
||||
grid: {
|
||||
@ -95,7 +98,7 @@ export const TableActionInitializer = observer((props: any) => {
|
||||
},
|
||||
footer: {
|
||||
type: 'void',
|
||||
'x-component': 'Action.Drawer.Footer',
|
||||
'x-component': 'Action.Container.Footer',
|
||||
properties: {
|
||||
action1: {
|
||||
title: '{{ t("Cancel") }}',
|
||||
@ -126,6 +129,9 @@ export const TableActionInitializer = observer((props: any) => {
|
||||
schema: {
|
||||
title: '{{ t("Delete") }}',
|
||||
'x-action': 'destroy',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useBulkDestroyAction }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
|
@ -7,20 +7,23 @@ import { useCollection, useDesignable } from '../../..';
|
||||
|
||||
const useTableColumnInitializerFields = () => {
|
||||
const { name, fields } = useCollection();
|
||||
return fields
|
||||
// .filter((field) => field?.uiSchema?.title)
|
||||
.map((field) => {
|
||||
return {
|
||||
type: 'item',
|
||||
title: field?.uiSchema?.title || field.name,
|
||||
schema: {
|
||||
name: field.name,
|
||||
'x-collection-field': `${name}.${field.name}`,
|
||||
'x-component': 'CollectionField',
|
||||
},
|
||||
component: ColumnInitializerItem,
|
||||
} as SchemaInitializerItemOptions;
|
||||
});
|
||||
return (
|
||||
fields
|
||||
// .filter((field) => field?.uiSchema?.title)
|
||||
.map((field) => {
|
||||
return {
|
||||
type: 'item',
|
||||
title: field?.uiSchema?.title || field.name,
|
||||
schema: {
|
||||
name: field.name,
|
||||
'x-designer': 'TestDesigner',
|
||||
'x-collection-field': `${name}.${field.name}`,
|
||||
'x-component': 'CollectionField',
|
||||
},
|
||||
component: ColumnInitializerItem,
|
||||
} as SchemaInitializerItemOptions;
|
||||
})
|
||||
);
|
||||
};
|
||||
|
||||
const useCurrentColumnSchema = (path: string) => {
|
||||
|
@ -67,6 +67,7 @@ const InitializeAction = SchemaInitializer.itemWrap((props) => {
|
||||
}
|
||||
insert({
|
||||
type: 'void',
|
||||
'x-designer': 'TestDesigner',
|
||||
'x-component': 'Action.Link',
|
||||
...item.schema,
|
||||
});
|
||||
@ -79,7 +80,7 @@ const InitializeAction = SchemaInitializer.itemWrap((props) => {
|
||||
);
|
||||
});
|
||||
|
||||
export const TableColumnActionInitializer = observer((props: any) => {
|
||||
export const TableRecordActionInitializer = observer((props: any) => {
|
||||
const fieldSchema = useFieldSchema();
|
||||
const api = useAPIClient();
|
||||
const { refresh } = useDesignable();
|
||||
@ -181,6 +182,9 @@ export const TableColumnActionInitializer = observer((props: any) => {
|
||||
schema: {
|
||||
title: '{{ t("Delete") }}',
|
||||
'x-action': 'destroy',
|
||||
'x-component-props': {
|
||||
useAction: '{{ useDestroyAction }}',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
@ -4,6 +4,6 @@ export * from './FormActionInitializer';
|
||||
export * from './FormItemInitializer';
|
||||
export * from './RecordBlockInitializer';
|
||||
export * from './TableActionInitializer';
|
||||
export * from './TableColumnActionInitializer';
|
||||
export * from './TableColumnInitializer';
|
||||
export * from './TableRecordActionInitializer';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user