feat: improve schema Initializer
This commit is contained in:
parent
78e89b76ef
commit
b656f69565
@ -5,17 +5,18 @@ import {
|
|||||||
AntdSchemaComponentProvider,
|
AntdSchemaComponentProvider,
|
||||||
APIClientProvider,
|
APIClientProvider,
|
||||||
AuthLayout,
|
AuthLayout,
|
||||||
CollectionManagerProvider,
|
|
||||||
CollectionManagerShortcut,
|
CollectionManagerShortcut,
|
||||||
compose,
|
compose,
|
||||||
DesignableSwitch,
|
DesignableSwitch,
|
||||||
DocumentTitleProvider,
|
DocumentTitleProvider,
|
||||||
i18n,
|
i18n,
|
||||||
PluginManagerProvider,
|
PluginManagerProvider,
|
||||||
|
RemoteCollectionManagerProvider,
|
||||||
RouteSchemaComponent,
|
RouteSchemaComponent,
|
||||||
RouteSwitch,
|
RouteSwitch,
|
||||||
RouteSwitchProvider,
|
RouteSwitchProvider,
|
||||||
SchemaComponentProvider,
|
SchemaComponentProvider,
|
||||||
|
SchemaInitializerProvider,
|
||||||
SigninPage,
|
SigninPage,
|
||||||
SignupPage,
|
SignupPage,
|
||||||
SystemSettingsProvider,
|
SystemSettingsProvider,
|
||||||
@ -38,13 +39,32 @@ const providers = [
|
|||||||
SystemSettingsProvider,
|
SystemSettingsProvider,
|
||||||
[
|
[
|
||||||
PluginManagerProvider,
|
PluginManagerProvider,
|
||||||
{ components: { ACLShortcut, DesignableSwitch, CollectionManagerShortcut, SystemSettingsShortcut } },
|
{
|
||||||
|
components: {
|
||||||
|
ACLShortcut,
|
||||||
|
DesignableSwitch,
|
||||||
|
CollectionManagerShortcut,
|
||||||
|
SystemSettingsShortcut,
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
[SchemaComponentProvider, { components: { Link, NavLink } }],
|
[SchemaComponentProvider, { components: { Link, NavLink } }],
|
||||||
CollectionManagerProvider,
|
RemoteCollectionManagerProvider,
|
||||||
|
SchemaInitializerProvider,
|
||||||
AntdSchemaComponentProvider,
|
AntdSchemaComponentProvider,
|
||||||
[DocumentTitleProvider, { addonAfter: 'NocoBase' }],
|
[DocumentTitleProvider, { addonAfter: 'NocoBase' }],
|
||||||
[RouteSwitchProvider, { components: { AuthLayout, AdminLayout, RouteSchemaComponent, SigninPage, SignupPage } }],
|
[
|
||||||
|
RouteSwitchProvider,
|
||||||
|
{
|
||||||
|
components: {
|
||||||
|
AuthLayout,
|
||||||
|
AdminLayout,
|
||||||
|
RouteSchemaComponent,
|
||||||
|
SigninPage,
|
||||||
|
SignupPage,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
const App = compose(...providers)(() => {
|
const App = compose(...providers)(() => {
|
||||||
|
@ -2,6 +2,7 @@ import { ISchema } from '@formily/react';
|
|||||||
|
|
||||||
const collection = {
|
const collection = {
|
||||||
name: 'collections',
|
name: 'collections',
|
||||||
|
targetKey: 'name',
|
||||||
filterTargetKey: 'name',
|
filterTargetKey: 'name',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
@ -42,6 +43,7 @@ export const roleCollectionsSchema: ISchema = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'ResourceActionProvider',
|
'x-decorator': 'ResourceActionProvider',
|
||||||
'x-decorator-props': {
|
'x-decorator-props': {
|
||||||
|
collection,
|
||||||
association: {
|
association: {
|
||||||
sourceKey: 'name',
|
sourceKey: 'name',
|
||||||
targetKey: 'name',
|
targetKey: 'name',
|
||||||
@ -58,10 +60,6 @@ export const roleCollectionsSchema: ISchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'x-component': 'CollectionProvider',
|
|
||||||
'x-component-props': {
|
|
||||||
collection,
|
|
||||||
},
|
|
||||||
properties: {
|
properties: {
|
||||||
table1: {
|
table1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
@ -38,9 +38,7 @@ export const roleSchema: ISchema = {
|
|||||||
type: 'void',
|
type: 'void',
|
||||||
'x-decorator': 'ResourceActionProvider',
|
'x-decorator': 'ResourceActionProvider',
|
||||||
'x-decorator-props': {
|
'x-decorator-props': {
|
||||||
collection: {
|
collection,
|
||||||
targetKey: 'name',
|
|
||||||
},
|
|
||||||
resourceName: 'roles',
|
resourceName: 'roles',
|
||||||
request: {
|
request: {
|
||||||
resource: 'roles',
|
resource: 'roles',
|
||||||
|
@ -16,6 +16,7 @@ import {
|
|||||||
RouteSwitch,
|
RouteSwitch,
|
||||||
RouteSwitchProvider,
|
RouteSwitchProvider,
|
||||||
SchemaComponentProvider,
|
SchemaComponentProvider,
|
||||||
|
SchemaInitializerProvider,
|
||||||
SigninPage,
|
SigninPage,
|
||||||
SignupPage,
|
SignupPage,
|
||||||
SystemSettingsProvider,
|
SystemSettingsProvider,
|
||||||
@ -42,6 +43,7 @@ const providers = [
|
|||||||
[SchemaComponentProvider, { components: { Link, NavLink } }],
|
[SchemaComponentProvider, { components: { Link, NavLink } }],
|
||||||
CollectionManagerProvider,
|
CollectionManagerProvider,
|
||||||
AntdSchemaComponentProvider,
|
AntdSchemaComponentProvider,
|
||||||
|
SchemaInitializerProvider,
|
||||||
[DocumentTitleProvider, { addonAfter: 'NocoBase' }],
|
[DocumentTitleProvider, { addonAfter: 'NocoBase' }],
|
||||||
[RouteSwitchProvider, { components: { AuthLayout, AdminLayout, RouteSchemaComponent, SigninPage, SignupPage } }],
|
[RouteSwitchProvider, { components: { AuthLayout, AdminLayout, RouteSchemaComponent, SigninPage, SignupPage } }],
|
||||||
];
|
];
|
||||||
|
@ -1,15 +1,54 @@
|
|||||||
|
import { Spin } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useAPIClient, useRequest } from '../api-client';
|
||||||
import { CollectionManagerSchemaComponentProvider } from './CollectionManagerSchemaComponentProvider';
|
import { CollectionManagerSchemaComponentProvider } from './CollectionManagerSchemaComponentProvider';
|
||||||
import { CollectionManagerContext } from './context';
|
import { CollectionManagerContext } from './context';
|
||||||
|
import * as defaultInterfaces from './interfaces';
|
||||||
import { CollectionManagerOptions } from './types';
|
import { CollectionManagerOptions } from './types';
|
||||||
|
|
||||||
export const CollectionManagerProvider: React.FC<CollectionManagerOptions> = (props) => {
|
export const CollectionManagerProvider: React.FC<CollectionManagerOptions> = (props) => {
|
||||||
const { interfaces, collections } = props;
|
const { service, interfaces, collections = [], refreshCM } = props;
|
||||||
return (
|
return (
|
||||||
<CollectionManagerContext.Provider value={{ interfaces, collections }}>
|
<CollectionManagerContext.Provider
|
||||||
<CollectionManagerSchemaComponentProvider>
|
value={{
|
||||||
{props.children}
|
service,
|
||||||
</CollectionManagerSchemaComponentProvider>
|
interfaces: { ...defaultInterfaces, ...interfaces },
|
||||||
|
collections,
|
||||||
|
refreshCM: async () => {
|
||||||
|
if (refreshCM) {
|
||||||
|
await refreshCM();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<CollectionManagerSchemaComponentProvider>{props.children}</CollectionManagerSchemaComponentProvider>
|
||||||
</CollectionManagerContext.Provider>
|
</CollectionManagerContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const RemoteCollectionManagerProvider = (props: any) => {
|
||||||
|
const api = useAPIClient();
|
||||||
|
const options = {
|
||||||
|
resource: 'collections',
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
perPage: 999,
|
||||||
|
appends: ['fields', 'fields.uiSchema'],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const service = useRequest(options);
|
||||||
|
if (service.loading) {
|
||||||
|
return <Spin />;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<CollectionManagerProvider
|
||||||
|
service={service}
|
||||||
|
collections={service?.data?.data}
|
||||||
|
refreshCM={async () => {
|
||||||
|
const { data } = await api.request(options);
|
||||||
|
service.mutate(data);
|
||||||
|
}}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
@ -1,23 +1,10 @@
|
|||||||
import { DatabaseOutlined } from '@ant-design/icons';
|
import { DatabaseOutlined } from '@ant-design/icons';
|
||||||
import { ISchema, useForm } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { PluginManager } from '../plugin-manager';
|
import { PluginManager } from '../plugin-manager';
|
||||||
import { ActionContext, SchemaComponent, useActionContext } from '../schema-component';
|
import { ActionContext, SchemaComponent } from '../schema-component';
|
||||||
import { ConfigurationTable } from './Configuration';
|
import { AddFieldAction, ConfigurationTable, EditFieldAction } from './Configuration';
|
||||||
|
|
||||||
const useCloseAction = () => {
|
|
||||||
const { setVisible } = useActionContext();
|
|
||||||
const form = useForm();
|
|
||||||
return {
|
|
||||||
async run() {
|
|
||||||
setVisible(false);
|
|
||||||
form.submit((values) => {
|
|
||||||
console.log(values);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const schema: ISchema = {
|
const schema: ISchema = {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
@ -46,7 +33,7 @@ export const CollectionManagerShortcut = () => {
|
|||||||
setVisible(true);
|
setVisible(true);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<SchemaComponent scope={{ useCloseAction }} schema={schema} components={{ ConfigurationTable }} />
|
<SchemaComponent schema={schema} components={{ ConfigurationTable, AddFieldAction, EditFieldAction }} />
|
||||||
</ActionContext.Provider>
|
</ActionContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,134 @@
|
|||||||
|
import { PlusOutlined } from '@ant-design/icons';
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { Button, Dropdown, Menu } from 'antd';
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { useAPIClient } from '../../api-client';
|
||||||
|
import { useRecord } from '../../record-provider';
|
||||||
|
import { ActionContext, SchemaComponent } from '../../schema-component';
|
||||||
|
import { useCollectionManager } from '../hooks';
|
||||||
|
import { IField } from '../interfaces/types';
|
||||||
|
|
||||||
|
const getSchema = (schema: IField, useAction): ISchema => {
|
||||||
|
if (!schema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
|
'x-decorator': 'Form',
|
||||||
|
'x-decorator-props': {
|
||||||
|
initialValue: {
|
||||||
|
...schema.default,
|
||||||
|
name: `f_${uid()}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
title: 'Drawer Title',
|
||||||
|
properties: {
|
||||||
|
type: {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
// @ts-ignore
|
||||||
|
...schema.properties,
|
||||||
|
footer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer.Footer',
|
||||||
|
properties: {
|
||||||
|
action1: {
|
||||||
|
title: 'Cancel',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
useAction: '{{ useCancelAction }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
action2: {
|
||||||
|
title: 'Submit',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
useAction,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const AddFieldAction = () => {
|
||||||
|
const { getInterface } = useCollectionManager();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const [schema, setSchema] = useState({});
|
||||||
|
return (
|
||||||
|
<ActionContext.Provider value={{ visible, setVisible }}>
|
||||||
|
<Dropdown
|
||||||
|
overlay={
|
||||||
|
<Menu
|
||||||
|
onClick={(info) => {
|
||||||
|
const schema = getSchema(getInterface(info.key), '{{ useCreateActionAndRefreshCM }}');
|
||||||
|
setSchema(schema);
|
||||||
|
setVisible(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Menu.SubMenu title={'基本类型'}>
|
||||||
|
<Menu.Item key={'input'}>input</Menu.Item>
|
||||||
|
<Menu.Item key={'textarea'}>textarea</Menu.Item>
|
||||||
|
<Menu.Item key={'chinaRegion'}>China region</Menu.Item>
|
||||||
|
</Menu.SubMenu>
|
||||||
|
</Menu>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Button icon={<PlusOutlined />} type={'primary'}>
|
||||||
|
添加字段
|
||||||
|
</Button>
|
||||||
|
</Dropdown>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</ActionContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const EditFieldAction = (props) => {
|
||||||
|
const record = useRecord();
|
||||||
|
const { getInterface } = useCollectionManager();
|
||||||
|
const [visible, setVisible] = useState(false);
|
||||||
|
const [schema, setSchema] = useState({});
|
||||||
|
const api = useAPIClient();
|
||||||
|
return (
|
||||||
|
<ActionContext.Provider value={{ visible, setVisible }}>
|
||||||
|
<a
|
||||||
|
onClick={async () => {
|
||||||
|
const { data } = await api.resource('collections.fields', record.collectionName).get({
|
||||||
|
filterByTk: record.name,
|
||||||
|
appends: ['uiSchema'],
|
||||||
|
});
|
||||||
|
const schema = getSchema(
|
||||||
|
{
|
||||||
|
...getInterface(record.interface),
|
||||||
|
default: data?.data,
|
||||||
|
},
|
||||||
|
'{{ useUpdateActionAndRefreshCM }}',
|
||||||
|
);
|
||||||
|
setSchema(schema);
|
||||||
|
setVisible(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
编辑
|
||||||
|
</a>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</ActionContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
@ -5,9 +5,7 @@ import { collectionSchema } from './schemas/collections';
|
|||||||
export const ConfigurationTable = () => {
|
export const ConfigurationTable = () => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<SchemaComponent
|
<SchemaComponent schema={collectionSchema} />
|
||||||
schema={collectionSchema}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
export * from './AddFieldAction';
|
||||||
export * from './ConfigurationTable';
|
export * from './ConfigurationTable';
|
||||||
|
|
||||||
|
@ -20,6 +20,16 @@ const collection = {
|
|||||||
required: true,
|
required: true,
|
||||||
} as ISchema,
|
} as ISchema,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'interface',
|
||||||
|
interface: 'input',
|
||||||
|
uiSchema: {
|
||||||
|
title: '字段类型',
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
name: 'title',
|
name: 'title',
|
||||||
@ -54,6 +64,7 @@ export const collectionFieldSchema: ISchema = {
|
|||||||
sourceKey: 'name',
|
sourceKey: 'name',
|
||||||
targetKey: 'name',
|
targetKey: 'name',
|
||||||
},
|
},
|
||||||
|
collection,
|
||||||
request: {
|
request: {
|
||||||
resource: 'collections.fields',
|
resource: 'collections.fields',
|
||||||
action: 'list',
|
action: 'list',
|
||||||
@ -65,10 +76,10 @@ export const collectionFieldSchema: ISchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'x-component': 'CollectionProvider',
|
// 'x-component': 'CollectionProvider',
|
||||||
'x-component-props': {
|
// 'x-component-props': {
|
||||||
collection,
|
// collection,
|
||||||
},
|
// },
|
||||||
properties: {
|
properties: {
|
||||||
actions: {
|
actions: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -82,57 +93,14 @@ export const collectionFieldSchema: ISchema = {
|
|||||||
create: {
|
create: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '创建',
|
title: '创建',
|
||||||
'x-component': 'Action',
|
'x-component': 'AddFieldAction',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
},
|
},
|
||||||
properties: {
|
|
||||||
drawer: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
'x-decorator': 'Form',
|
|
||||||
title: 'Drawer Title',
|
|
||||||
properties: {
|
|
||||||
type: {
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Action.Drawer.Footer',
|
|
||||||
properties: {
|
|
||||||
action1: {
|
|
||||||
title: 'Cancel',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
useAction: '{{ useCancelAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
action2: {
|
|
||||||
title: 'Submit',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
type: 'primary',
|
|
||||||
useAction: '{{ useCreateAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
table1: {
|
table: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-uid': 'input',
|
'x-uid': 'input',
|
||||||
'x-component': 'VoidTable',
|
'x-component': 'VoidTable',
|
||||||
@ -169,6 +137,18 @@ export const collectionFieldSchema: ISchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
column3: {
|
column3: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'TableColumnDecorator',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
properties: {
|
||||||
|
interface: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
column4: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: 'Actions',
|
title: 'Actions',
|
||||||
'x-component': 'VoidTable.Column',
|
'x-component': 'VoidTable.Column',
|
||||||
@ -183,60 +163,17 @@ export const collectionFieldSchema: ISchema = {
|
|||||||
update: {
|
update: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '编辑',
|
title: '编辑',
|
||||||
'x-component': 'Action.Link',
|
'x-component': 'EditFieldAction',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
},
|
},
|
||||||
properties: {
|
|
||||||
drawer: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Action.Drawer',
|
|
||||||
'x-decorator': 'Form',
|
|
||||||
'x-decorator-props': {
|
|
||||||
useValues: '{{ useValues }}',
|
|
||||||
},
|
|
||||||
title: 'Drawer Title',
|
|
||||||
properties: {
|
|
||||||
title: {
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
},
|
|
||||||
name: {
|
|
||||||
'x-component': 'CollectionField',
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-disabled': true,
|
|
||||||
},
|
|
||||||
footer: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Action.Drawer.Footer',
|
|
||||||
properties: {
|
|
||||||
action1: {
|
|
||||||
title: 'Cancel',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
useAction: '{{ useCancelAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
action2: {
|
|
||||||
title: 'Submit',
|
|
||||||
'x-component': 'Action',
|
|
||||||
'x-component-props': {
|
|
||||||
type: 'primary',
|
|
||||||
useAction: '{{ useUpdateAction }}',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
delete: {
|
delete: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
title: '删除',
|
title: '删除',
|
||||||
'x-component': 'Action.Link',
|
'x-component': 'Action.Link',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
useAction: '{{ useDestroyAction }}',
|
useAction: '{{ useDestroyActionAndRefreshCM }}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
|
import { CollectionOptions } from '../../types';
|
||||||
import { collectionFieldSchema } from './collectionFields';
|
import { collectionFieldSchema } from './collectionFields';
|
||||||
|
|
||||||
const collection = {
|
const collection: CollectionOptions = {
|
||||||
name: 'collections',
|
name: 'collections',
|
||||||
filterTargetKey: 'name',
|
filterTargetKey: 'name',
|
||||||
|
targetKey: 'name',
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
type: 'integer',
|
type: 'integer',
|
||||||
@ -14,7 +16,7 @@ const collection = {
|
|||||||
type: 'number',
|
type: 'number',
|
||||||
'x-component': 'Input',
|
'x-component': 'Input',
|
||||||
required: true,
|
required: true,
|
||||||
} as ISchema,
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@ -25,7 +27,7 @@ const collection = {
|
|||||||
type: 'string',
|
type: 'string',
|
||||||
'x-component': 'Input',
|
'x-component': 'Input',
|
||||||
description: '使用英文',
|
description: '使用英文',
|
||||||
} as ISchema,
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: 'hasMany',
|
type: 'hasMany',
|
||||||
@ -47,9 +49,7 @@ export const collectionSchema: ISchema = {
|
|||||||
'x-collection': 'collections',
|
'x-collection': 'collections',
|
||||||
'x-decorator': 'ResourceActionProvider',
|
'x-decorator': 'ResourceActionProvider',
|
||||||
'x-decorator-props': {
|
'x-decorator-props': {
|
||||||
collection: {
|
collection,
|
||||||
targetKey: 'name',
|
|
||||||
},
|
|
||||||
request: {
|
request: {
|
||||||
resource: 'collections',
|
resource: 'collections',
|
||||||
action: 'list',
|
action: 'list',
|
||||||
@ -61,10 +61,10 @@ export const collectionSchema: ISchema = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'x-component': 'CollectionProvider',
|
// 'x-component': 'CollectionProvider',
|
||||||
'x-component-props': {
|
// 'x-component-props': {
|
||||||
collection,
|
// collection,
|
||||||
},
|
// },
|
||||||
properties: {
|
properties: {
|
||||||
actions: {
|
actions: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
@ -113,7 +113,7 @@ export const collectionSchema: ISchema = {
|
|||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
useAction: '{{ useCreateAction }}',
|
useAction: '{{ useCreateActionAndRefreshCM }}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -201,7 +201,7 @@ export const collectionSchema: ISchema = {
|
|||||||
'x-component': 'Action.Drawer',
|
'x-component': 'Action.Drawer',
|
||||||
'x-decorator': 'Form',
|
'x-decorator': 'Form',
|
||||||
'x-decorator-props': {
|
'x-decorator-props': {
|
||||||
useValues: '{{ useValues }}',
|
useValues: '{{ useValuesFromRecord }}',
|
||||||
},
|
},
|
||||||
title: 'Drawer Title',
|
title: 'Drawer Title',
|
||||||
properties: {
|
properties: {
|
||||||
@ -230,7 +230,7 @@ export const collectionSchema: ISchema = {
|
|||||||
'x-component': 'Action',
|
'x-component': 'Action',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
type: 'primary',
|
type: 'primary',
|
||||||
useAction: '{{ useUpdateAction }}',
|
useAction: '{{ useUpdateActionAndRefreshCM }}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -244,7 +244,7 @@ export const collectionSchema: ISchema = {
|
|||||||
title: '删除',
|
title: '删除',
|
||||||
'x-component': 'Action.Link',
|
'x-component': 'Action.Link',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
useAction: '{{ useDestroyAction }}',
|
useAction: '{{ useDestroyActionAndRefreshCM }}',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Result } from 'ahooks/lib/useRequest/src/types';
|
import { Result } from 'ahooks/lib/useRequest/src/types';
|
||||||
import React, { createContext, useContext, useEffect } from 'react';
|
import React, { createContext, useContext, useEffect } from 'react';
|
||||||
import { useRecord } from '..';
|
import { CollectionProvider, useRecord } from '..';
|
||||||
import { useAPIClient, useRequest } from '../api-client';
|
import { useAPIClient, useRequest } from '../api-client';
|
||||||
|
|
||||||
export const ResourceActionContext = createContext<Result<any, any>>(null);
|
export const ResourceActionContext = createContext<Result<any, any>>(null);
|
||||||
@ -18,18 +18,20 @@ const CollectionResourceActionProvider = (props) => {
|
|||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
const service = useRequest(request, {
|
const service = useRequest(request, {
|
||||||
uid,
|
uid,
|
||||||
refreshDeps: [request],
|
// refreshDeps: [request],
|
||||||
});
|
});
|
||||||
const resource = api.resource(request.resource);
|
const resource = api.resource(request.resource);
|
||||||
return (
|
return (
|
||||||
<ResourceContext.Provider value={{ type: 'collection', resource, collection }}>
|
<ResourceContext.Provider value={{ type: 'collection', resource, collection }}>
|
||||||
<ResourceActionContext.Provider value={service}>{props.children}</ResourceActionContext.Provider>
|
<ResourceActionContext.Provider value={service}>
|
||||||
|
<CollectionProvider collection={collection}>{props.children}</CollectionProvider>
|
||||||
|
</ResourceActionContext.Provider>
|
||||||
</ResourceContext.Provider>
|
</ResourceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const AssociationResourceActionProvider = (props) => {
|
const AssociationResourceActionProvider = (props) => {
|
||||||
const { association, request, uid } = props;
|
const { collection, association, request, uid } = props;
|
||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
const resourceOf = record[association.sourceKey];
|
const resourceOf = record[association.sourceKey];
|
||||||
@ -37,13 +39,15 @@ const AssociationResourceActionProvider = (props) => {
|
|||||||
{ resourceOf, ...request },
|
{ resourceOf, ...request },
|
||||||
{
|
{
|
||||||
uid,
|
uid,
|
||||||
refreshDeps: [request, resourceOf],
|
// refreshDeps: [request, resourceOf],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const resource = api.resource(request.resource, resourceOf);
|
const resource = api.resource(request.resource, resourceOf);
|
||||||
return (
|
return (
|
||||||
<ResourceContext.Provider value={{ type: 'association', resource, association }}>
|
<ResourceContext.Provider value={{ type: 'association', resource, association }}>
|
||||||
<ResourceActionContext.Provider value={service}>{props.children}</ResourceActionContext.Provider>
|
<ResourceActionContext.Provider value={service}>
|
||||||
|
<CollectionProvider collection={collection}>{props.children}</CollectionProvider>
|
||||||
|
</ResourceActionContext.Provider>
|
||||||
</ResourceContext.Provider>
|
</ResourceContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { useForm } from '@formily/react';
|
import { useForm } from '@formily/react';
|
||||||
|
import { useCollectionManager } from '.';
|
||||||
import { useRequest } from '../api-client';
|
import { useRequest } from '../api-client';
|
||||||
import { useRecord } from '../record-provider';
|
import { useRecord } from '../record-provider';
|
||||||
import { useActionContext } from '../schema-component';
|
import { useActionContext } from '../schema-component';
|
||||||
@ -60,10 +61,43 @@ export const useDestroyAction = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useValues = (options) => {
|
export const useValuesFromRecord = (options) => {
|
||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
return useRequest(() => Promise.resolve({ data: record }), {
|
return useRequest(() => Promise.resolve({ data: record }), {
|
||||||
...options,
|
...options,
|
||||||
refreshDeps: [record],
|
refreshDeps: [record],
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const useCreateActionAndRefreshCM = () => {
|
||||||
|
const { run } = useCreateAction();
|
||||||
|
const { refreshCM } = useCollectionManager();
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
await run();
|
||||||
|
await refreshCM();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useUpdateActionAndRefreshCM = () => {
|
||||||
|
const { run } = useUpdateAction();
|
||||||
|
const { refreshCM } = useCollectionManager();
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
await run();
|
||||||
|
await refreshCM();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useDestroyActionAndRefreshCM = () => {
|
||||||
|
const { run } = useDestroyAction();
|
||||||
|
const { refreshCM } = useCollectionManager();
|
||||||
|
return {
|
||||||
|
async run() {
|
||||||
|
await run();
|
||||||
|
await refreshCM();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -11,7 +11,6 @@ export const useCollectionField = () => {
|
|||||||
const ctx = useContext(CollectionFieldContext);
|
const ctx = useContext(CollectionFieldContext);
|
||||||
const resourceName = `${ctx?.collectinName || collection?.name}.${ctx.name}`;
|
const resourceName = `${ctx?.collectinName || collection?.name}.${ctx.name}`;
|
||||||
const resource = api?.resource(resourceName, record[ctx.sourceKey]);
|
const resource = api?.resource(resourceName, record[ctx.sourceKey]);
|
||||||
console.log({ resourceName });
|
|
||||||
return {
|
return {
|
||||||
...ctx,
|
...ctx,
|
||||||
resource,
|
resource,
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
|
import { clone } from '@formily/shared';
|
||||||
import { useContext } from 'react';
|
import { useContext } from 'react';
|
||||||
import { CollectionManagerContext } from '../context';
|
import { CollectionManagerContext } from '../context';
|
||||||
|
|
||||||
export const useCollectionManager = () => {
|
export const useCollectionManager = () => {
|
||||||
const { collections } = useContext(CollectionManagerContext);
|
const { refreshCM, service, interfaces, collections } = useContext(CollectionManagerContext);
|
||||||
return {
|
return {
|
||||||
|
service,
|
||||||
|
interfaces,
|
||||||
|
collections,
|
||||||
|
refreshCM: () => refreshCM?.(),
|
||||||
get(name: string) {
|
get(name: string) {
|
||||||
return collections?.find((collection) => collection.name === name);
|
return collections?.find((collection) => collection.name === name);
|
||||||
},
|
},
|
||||||
|
getInterface(name) {
|
||||||
|
return interfaces[name] ? clone(interfaces[name]) : null;
|
||||||
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,73 @@
|
|||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import { IField } from './types';
|
||||||
|
|
||||||
|
export const chinaRegion: IField = {
|
||||||
|
name: 'chinaRegion',
|
||||||
|
type: 'object',
|
||||||
|
group: 'choices',
|
||||||
|
order: 7,
|
||||||
|
title: '{{t("China region")}}',
|
||||||
|
isAssociation: true,
|
||||||
|
default: {
|
||||||
|
interface: 'chinaRegion',
|
||||||
|
type: 'belongsToMany',
|
||||||
|
target: 'chinaRegions',
|
||||||
|
targetKey: 'code',
|
||||||
|
// name,
|
||||||
|
uiSchema: {
|
||||||
|
type: 'array',
|
||||||
|
// title,
|
||||||
|
'x-component': 'Cascader',
|
||||||
|
'x-component-props': {
|
||||||
|
changeOnSelectLast: false,
|
||||||
|
labelInValue: true,
|
||||||
|
maxLevel: 3,
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'code',
|
||||||
|
children: 'children',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
initialize: (values: any) => {
|
||||||
|
if (!values.through) {
|
||||||
|
values.through = `t_${uid()}`;
|
||||||
|
}
|
||||||
|
if (!values.foreignKey) {
|
||||||
|
values.foreignKey = `f_${uid()}`;
|
||||||
|
}
|
||||||
|
if (!values.otherKey) {
|
||||||
|
values.otherKey = `f_${uid()}`;
|
||||||
|
}
|
||||||
|
if (!values.sourceKey) {
|
||||||
|
values.sourceKey = 'id';
|
||||||
|
}
|
||||||
|
if (!values.targetKey) {
|
||||||
|
values.targetKey = 'id';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
'uiSchema.x-component-props.maxLevel': {
|
||||||
|
type: 'number',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
title: '{{t("Select level")}}',
|
||||||
|
default: 3,
|
||||||
|
enum: [
|
||||||
|
{ value: 1, label: '{{t("Province")}}' },
|
||||||
|
{ value: 2, label: '{{t("City")}}' },
|
||||||
|
{ value: 3, label: '{{t("Area")}}' },
|
||||||
|
{ value: 4, label: '{{t("Street")}}' },
|
||||||
|
{ value: 5, label: '{{t("Village")}}' },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'uiSchema.x-component-props.changeOnSelectLast': {
|
||||||
|
type: 'boolean',
|
||||||
|
'x-component': 'Checkbox',
|
||||||
|
'x-content': '{{t("Must select to the last level")}}',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
operators: [{ label: '{{t("is")}}', value: 'code.in' }],
|
||||||
|
};
|
@ -0,0 +1,4 @@
|
|||||||
|
export * from './chinaRegion';
|
||||||
|
export * from './input';
|
||||||
|
export * from './textarea';
|
||||||
|
|
28
packages/client/src/collection-manager/interfaces/input.ts
Normal file
28
packages/client/src/collection-manager/interfaces/input.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { IField } from './types';
|
||||||
|
|
||||||
|
export const input: IField = {
|
||||||
|
name: 'string',
|
||||||
|
type: 'object',
|
||||||
|
group: 'basic',
|
||||||
|
order: 1,
|
||||||
|
title: '{{t("Single line text")}}',
|
||||||
|
sortable: true,
|
||||||
|
default: {
|
||||||
|
interface: 'input',
|
||||||
|
type: 'string',
|
||||||
|
uiSchema: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
},
|
||||||
|
operators: [
|
||||||
|
{ label: '{{t("contains")}}', value: '$includes', selected: true },
|
||||||
|
{ label: '{{t("does not contain")}}', value: '$notIncludes' },
|
||||||
|
{ label: '{{t("is")}}', value: 'eq' },
|
||||||
|
{ label: '{{t("is not")}}', value: 'ne' },
|
||||||
|
{ label: '{{t("is empty")}}', value: '$null', noValue: true },
|
||||||
|
{ label: '{{t("is not empty")}}', value: '$notNull', noValue: true },
|
||||||
|
],
|
||||||
|
};
|
@ -0,0 +1,198 @@
|
|||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
|
||||||
|
export const type: ISchema = {
|
||||||
|
type: 'string',
|
||||||
|
title: '{{t("Storage type")}}',
|
||||||
|
required: true,
|
||||||
|
'x-disabled': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select',
|
||||||
|
enum: [
|
||||||
|
{ label: 'Boolean', value: 'boolean' },
|
||||||
|
{ label: 'String', value: 'string' },
|
||||||
|
{ label: 'Text', value: 'text' },
|
||||||
|
{ label: 'Integer', value: 'integer' },
|
||||||
|
{ label: 'Float', value: 'float' },
|
||||||
|
{ label: 'Decimal', value: 'decimal' },
|
||||||
|
{ label: 'Date', value: 'date' },
|
||||||
|
{ label: 'DateOnly', value: 'dateonly' },
|
||||||
|
{ label: 'Time', value: 'time' },
|
||||||
|
{ label: 'Virtual', value: 'virtual' },
|
||||||
|
{ label: 'JSON', value: 'json' },
|
||||||
|
{ label: 'Password', value: 'password' },
|
||||||
|
{ label: 'HasOne', value: 'hasOne' },
|
||||||
|
{ label: 'HasMany', value: 'hasMany' },
|
||||||
|
{ label: 'BelongsTo', value: 'belongsTo' },
|
||||||
|
{ label: 'BelongsToMany', value: 'belongsToMany' },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const dateTimeProps: { [key: string]: ISchema } = {
|
||||||
|
'uiSchema.x-component-props.dateFormat': {
|
||||||
|
type: 'string',
|
||||||
|
title: '{{t("Date format")}}',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
default: 'YYYY-MM-DD',
|
||||||
|
enum: [
|
||||||
|
{
|
||||||
|
label: '{{t("Year/Month/Day")}}',
|
||||||
|
value: 'YYYY/MM/DD',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '{{t("Year-Month-Day")}}',
|
||||||
|
value: 'YYYY-MM-DD',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '{{t("Day/Month/Year")}}',
|
||||||
|
value: 'DD/MM/YYYY',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'uiSchema.x-component-props.showTime': {
|
||||||
|
type: 'boolean',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Checkbox',
|
||||||
|
'x-content': '{{t("Show time")}}',
|
||||||
|
'x-reactions': [
|
||||||
|
`{{(field) => {
|
||||||
|
field.query('..[].timeFormat').take(f => {
|
||||||
|
f.display = field.value ? 'visible' : 'none';
|
||||||
|
});
|
||||||
|
}}}`,
|
||||||
|
],
|
||||||
|
},
|
||||||
|
'uiSchema.x-component-props.timeFormat': {
|
||||||
|
type: 'string',
|
||||||
|
title: '{{t("Time format")}}',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
default: 'HH:mm:ss',
|
||||||
|
enum: [
|
||||||
|
{
|
||||||
|
label: '{{t("12 hour")}}',
|
||||||
|
value: 'hh:mm:ss a',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '{{t("24 hour")}}',
|
||||||
|
value: 'HH:mm:ss',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const dataSource: ISchema = {
|
||||||
|
type: 'array',
|
||||||
|
title: '{{t("Options")}}',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayTable',
|
||||||
|
'x-component-props': {
|
||||||
|
pagination: false,
|
||||||
|
// scroll: { x: '100%' },
|
||||||
|
},
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
column1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': { width: 50, title: '', align: 'center' },
|
||||||
|
properties: {
|
||||||
|
sort: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.SortHandle',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
column2: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': { title: '{{t("Option value")}}' },
|
||||||
|
'x-hidden': true,
|
||||||
|
properties: {
|
||||||
|
value: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
column3: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': { title: '{{t("Option label")}}' },
|
||||||
|
properties: {
|
||||||
|
label: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
column4: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': { title: '{{t("Color")}}' },
|
||||||
|
properties: {
|
||||||
|
color: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ColorSelect',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
column5: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Column',
|
||||||
|
'x-component-props': {
|
||||||
|
title: '',
|
||||||
|
dataIndex: 'operations',
|
||||||
|
fixed: 'right',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
item: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'FormItem',
|
||||||
|
properties: {
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Remove',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
add: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ArrayTable.Addition',
|
||||||
|
'x-component-props': {
|
||||||
|
randomValue: true,
|
||||||
|
},
|
||||||
|
title: "{{t('Add option')}}",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultProps = {
|
||||||
|
'uiSchema.title': {
|
||||||
|
type: 'string',
|
||||||
|
title: '{{t("Field display name")}}',
|
||||||
|
required: true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
title: '{{t("Field name")}}',
|
||||||
|
required: true,
|
||||||
|
// 'x-disabled': true,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
description:
|
||||||
|
"{{t('Randomly generated and can be modified. Support letters, numbers and underscores, must start with an letter.')}}",
|
||||||
|
},
|
||||||
|
type,
|
||||||
|
};
|
@ -0,0 +1,19 @@
|
|||||||
|
import { IField } from './types';
|
||||||
|
|
||||||
|
export const textarea: IField = {
|
||||||
|
name: 'textarea',
|
||||||
|
type: 'object',
|
||||||
|
group: 'basic',
|
||||||
|
order: 2,
|
||||||
|
title: '{{t("Long text")}}',
|
||||||
|
default: {
|
||||||
|
interface: 'textarea',
|
||||||
|
type: 'text',
|
||||||
|
// name,
|
||||||
|
uiSchema: {
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input.TextArea',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
};
|
12
packages/client/src/collection-manager/interfaces/types.ts
Normal file
12
packages/client/src/collection-manager/interfaces/types.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
|
||||||
|
interface IDefault {
|
||||||
|
type: string;
|
||||||
|
uiSchema?: ISchema;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IField extends ISchema {
|
||||||
|
default?: IDefault;
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
@ -1,14 +1,24 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
|
|
||||||
export interface CollectionManagerOptions {
|
export interface CollectionManagerOptions {
|
||||||
|
service?: any;
|
||||||
interfaces?: any;
|
interfaces?: any;
|
||||||
collections?: any[];
|
collections?: any[];
|
||||||
|
refreshCM?: () => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FieldOptions {
|
||||||
|
type: string;
|
||||||
|
interface?: string;
|
||||||
|
uiSchema?: ISchema;
|
||||||
|
[key: string]: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CollectionOptions {
|
export interface CollectionOptions {
|
||||||
name?: string;
|
name?: string;
|
||||||
filterTargetKey?: string;
|
filterTargetKey?: string;
|
||||||
fields?: any[];
|
targetKey?: string;
|
||||||
|
fields?: FieldOptions[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICollectionProviderProps {
|
export interface ICollectionProviderProps {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
import { observer, useField, useFieldSchema } from '@formily/react';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { ActionContext } from './context';
|
import { ActionContext } from './context';
|
||||||
@ -23,7 +23,7 @@ export const ActionLink: ComposedAction = observer((props: any) => {
|
|||||||
>
|
>
|
||||||
{field.title}
|
{field.title}
|
||||||
</Link>
|
</Link>
|
||||||
<RecursionField basePath={field.address} schema={schema} onlyRenderProperties />
|
{props.children}
|
||||||
</ActionContext.Provider>
|
</ActionContext.Provider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
import { observer, useField, useFieldSchema } from '@formily/react';
|
||||||
import { Button } from 'antd';
|
import { Button } from 'antd';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import ActionContainer from './Action.Container';
|
import ActionContainer from './Action.Container';
|
||||||
@ -28,7 +28,7 @@ export const Action: ComposedAction = observer((props: any) => {
|
|||||||
>
|
>
|
||||||
{field.title}
|
{field.title}
|
||||||
</Button>
|
</Button>
|
||||||
<RecursionField basePath={field.address} schema={schema} onlyRenderProperties />
|
{props.children}
|
||||||
</ActionContext.Provider>
|
</ActionContext.Provider>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -1,58 +0,0 @@
|
|||||||
import { observer } from '@formily/react';
|
|
||||||
import React from 'react';
|
|
||||||
import { SchemaInitializer } from '../../../schema-initializer';
|
|
||||||
|
|
||||||
const useTableColumnInitializerFields = () => {
|
|
||||||
const fields = [
|
|
||||||
{
|
|
||||||
title: 'Field1',
|
|
||||||
name: 'field1',
|
|
||||||
component: ArrayTableColumnInitializer,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
title: 'Field2',
|
|
||||||
name: 'field2',
|
|
||||||
component: ArrayTableColumnInitializer,
|
|
||||||
},
|
|
||||||
].filter((field) => field.component);
|
|
||||||
return fields;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const TableColumnInitializeButton = observer((props: any) => {
|
|
||||||
return (
|
|
||||||
<SchemaInitializer.Button
|
|
||||||
insertPosition={'beforeEnd'}
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
type: 'item',
|
|
||||||
title: 'Display fields',
|
|
||||||
children: useTableColumnInitializerFields(),
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
Configure columns
|
|
||||||
</SchemaInitializer.Button>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
export const ArrayTableColumnInitializer = SchemaInitializer.itemWrap((props) => {
|
|
||||||
const { insert } = props;
|
|
||||||
return (
|
|
||||||
<SchemaInitializer.Item
|
|
||||||
onClick={() => {
|
|
||||||
insert({
|
|
||||||
type: 'void',
|
|
||||||
title: 'Name',
|
|
||||||
'x-component': 'ArrayTable.Column',
|
|
||||||
properties: {
|
|
||||||
name: {
|
|
||||||
type: 'string',
|
|
||||||
'x-component': 'Input',
|
|
||||||
'x-read-pretty': true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
@ -0,0 +1,41 @@
|
|||||||
|
import { observer, useFieldSchema } from '@formily/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { createDesignable, useDesignable } from '../..';
|
||||||
|
import { useAPIClient } from '../../../api-client';
|
||||||
|
|
||||||
|
export const TableActionDesignable = observer((props) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const api = useAPIClient();
|
||||||
|
const { refresh } = useDesignable();
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<span
|
||||||
|
onClick={() => {
|
||||||
|
const spaceSchema = fieldSchema.reduceProperties((buf, schema) => {
|
||||||
|
if (schema['x-component'] === 'Space') {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}, null);
|
||||||
|
const dn = createDesignable({
|
||||||
|
current: spaceSchema,
|
||||||
|
refresh,
|
||||||
|
api,
|
||||||
|
});
|
||||||
|
dn.loadAPIClientEvents();
|
||||||
|
dn.insertBeforeEnd({
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Delete") }}',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': {
|
||||||
|
useAction: '{{ useDestroyAction }}',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</span>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,4 @@
|
|||||||
|
import React from 'react';
|
||||||
|
export const TableActionDesignableBar = () => {
|
||||||
|
return <div>Edit</div>;
|
||||||
|
};
|
@ -0,0 +1,14 @@
|
|||||||
|
import { observer, useFieldSchema } from '@formily/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { useComponent } from '../..';
|
||||||
|
|
||||||
|
export const TableColumnActionBar = observer((props) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const ActionInitializer = useComponent(fieldSchema['x-action-initializer']);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{ActionInitializer && <ActionInitializer />}
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
@ -1,4 +1,5 @@
|
|||||||
export * from './ArrayTable';
|
export * from './ArrayTable';
|
||||||
export * from './Initializer';
|
export * from './TableColumnActionBar';
|
||||||
export * from './TableColumnDecorator';
|
export * from './TableColumnDecorator';
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,18 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useDesignable } from '../..';
|
||||||
import { SortableItem } from '../../common';
|
import { SortableItem } from '../../common';
|
||||||
|
|
||||||
export const BlockItem: React.FC<any> = (props) => {
|
export const BlockItem: React.FC<any> = (props) => {
|
||||||
|
const { remove } = useDesignable();
|
||||||
return (
|
return (
|
||||||
<SortableItem className={'nb-block-item'} style={{ position: 'relative' }}>
|
<SortableItem className={'nb-block-item'} style={{ position: 'relative' }}>
|
||||||
|
<a
|
||||||
|
onClick={() => {
|
||||||
|
remove();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
删除
|
||||||
|
</a>
|
||||||
{props.children}
|
{props.children}
|
||||||
</SortableItem>
|
</SortableItem>
|
||||||
);
|
);
|
||||||
|
@ -6,8 +6,6 @@ import cls from 'classnames';
|
|||||||
import React, { createContext, useContext, useState } from 'react';
|
import React, { createContext, useContext, useState } from 'react';
|
||||||
import { useComponent } from '../..';
|
import { useComponent } from '../..';
|
||||||
import { DndContext } from '../../common/dnd-context';
|
import { DndContext } from '../../common/dnd-context';
|
||||||
import { AddGridBlockItem } from './AddBlockItem';
|
|
||||||
import { AddGridFormItem } from './AddFormItem';
|
|
||||||
|
|
||||||
const GridRowContext = createContext(null);
|
const GridRowContext = createContext(null);
|
||||||
const GridColContext = createContext(null);
|
const GridColContext = createContext(null);
|
||||||
@ -209,6 +207,3 @@ Grid.Col = observer((props: any) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
Grid.AddFormItem = AddGridFormItem;
|
|
||||||
Grid.AddBlockItem = AddGridBlockItem;
|
|
||||||
|
@ -1,6 +1,15 @@
|
|||||||
import { ISchema } from '@formily/react';
|
import { ISchema } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { Form, FormItem, Grid, Input, Markdown, SchemaComponent, SchemaComponentProvider } from '@nocobase/client';
|
import {
|
||||||
|
Form,
|
||||||
|
FormItem,
|
||||||
|
Grid,
|
||||||
|
Input,
|
||||||
|
Markdown,
|
||||||
|
SchemaComponent,
|
||||||
|
SchemaComponentProvider,
|
||||||
|
SchemaInitializerProvider
|
||||||
|
} from '@nocobase/client';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
const schema: ISchema = {
|
const schema: ISchema = {
|
||||||
@ -8,7 +17,7 @@ const schema: ISchema = {
|
|||||||
name: 'grid1',
|
name: 'grid1',
|
||||||
'x-decorator': 'Form',
|
'x-decorator': 'Form',
|
||||||
'x-component': 'Grid',
|
'x-component': 'Grid',
|
||||||
'x-item-initializer': 'Grid.AddFormItem',
|
'x-item-initializer': 'AddFormItem',
|
||||||
'x-uid': uid(),
|
'x-uid': uid(),
|
||||||
properties: {
|
properties: {
|
||||||
row1: {
|
row1: {
|
||||||
@ -56,7 +65,9 @@ const schema: ISchema = {
|
|||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<SchemaComponentProvider components={{ Markdown, Form, Grid, Input, FormItem }}>
|
<SchemaComponentProvider components={{ Markdown, Form, Grid, Input, FormItem }}>
|
||||||
<SchemaComponent schema={schema} />
|
<SchemaInitializerProvider>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</SchemaInitializerProvider>
|
||||||
</SchemaComponentProvider>
|
</SchemaComponentProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import {
|
|||||||
Markdown,
|
Markdown,
|
||||||
SchemaComponent,
|
SchemaComponent,
|
||||||
SchemaComponentProvider,
|
SchemaComponentProvider,
|
||||||
|
SchemaInitializerProvider,
|
||||||
VoidTable
|
VoidTable
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -29,7 +30,7 @@ const schema: ISchema = {
|
|||||||
grid: {
|
grid: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid',
|
'x-component': 'Grid',
|
||||||
'x-item-initializer': 'Grid.AddBlockItem',
|
'x-item-initializer': 'AddBlockItem',
|
||||||
'x-uid': uid(),
|
'x-uid': uid(),
|
||||||
properties: {},
|
properties: {},
|
||||||
},
|
},
|
||||||
@ -39,7 +40,9 @@ const schema: ISchema = {
|
|||||||
export default function App() {
|
export default function App() {
|
||||||
return (
|
return (
|
||||||
<SchemaComponentProvider components={{ BlockItem, Block, Grid, CardItem, Markdown, Form, VoidTable }}>
|
<SchemaComponentProvider components={{ BlockItem, Block, Grid, CardItem, Markdown, Form, VoidTable }}>
|
||||||
<SchemaComponent schema={schema} />
|
<SchemaInitializerProvider>
|
||||||
|
<SchemaComponent schema={schema} />
|
||||||
|
</SchemaInitializerProvider>
|
||||||
</SchemaComponentProvider>
|
</SchemaComponentProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -475,7 +475,7 @@ export function useDesignable() {
|
|||||||
update(key);
|
update(key);
|
||||||
refresh();
|
refresh();
|
||||||
},
|
},
|
||||||
remove(schema: any, options?: RemoveOptions) {
|
remove(schema?: any, options?: RemoveOptions) {
|
||||||
dn.remove(schema, options);
|
dn.remove(schema, options);
|
||||||
},
|
},
|
||||||
insertAdjacent(position: Position, schema: ISchema, options?: InsertAdjacentOptions) {
|
insertAdjacent(position: Position, schema: ISchema, options?: InsertAdjacentOptions) {
|
||||||
|
@ -0,0 +1,260 @@
|
|||||||
|
import { TableOutlined } from '@ant-design/icons';
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import { clone } from '@formily/shared';
|
||||||
|
import React from 'react';
|
||||||
|
import { SchemaInitializer } from '../../';
|
||||||
|
import { CollectionOptions, useCollectionManager } from '../../../collection-manager';
|
||||||
|
|
||||||
|
const collection: CollectionOptions = {
|
||||||
|
name: 'collections',
|
||||||
|
filterTargetKey: 'name',
|
||||||
|
targetKey: 'name',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'integer',
|
||||||
|
name: 'title',
|
||||||
|
interface: 'input',
|
||||||
|
uiSchema: {
|
||||||
|
title: '数据表名称',
|
||||||
|
type: 'number',
|
||||||
|
'x-component': 'Input',
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'name',
|
||||||
|
interface: 'input',
|
||||||
|
uiSchema: {
|
||||||
|
title: '数据表标识',
|
||||||
|
type: 'string',
|
||||||
|
'x-component': 'Input',
|
||||||
|
description: '使用英文',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'hasMany',
|
||||||
|
name: 'fields',
|
||||||
|
target: 'fields',
|
||||||
|
collectionName: 'collections',
|
||||||
|
sourceKey: 'name',
|
||||||
|
targetKey: 'name',
|
||||||
|
uiSchema: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const collectionSchema: ISchema = {
|
||||||
|
type: 'void',
|
||||||
|
'x-collection': 'collections',
|
||||||
|
'x-component': 'CardItem',
|
||||||
|
'x-decorator': 'ResourceActionProvider',
|
||||||
|
'x-decorator-props': {
|
||||||
|
collection,
|
||||||
|
request: {
|
||||||
|
resource: 'collections',
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
pageSize: 5,
|
||||||
|
filter: {},
|
||||||
|
sort: ['sort'],
|
||||||
|
appends: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-action-initializer': 'AddActionButton',
|
||||||
|
properties: {
|
||||||
|
delete: {
|
||||||
|
type: 'void',
|
||||||
|
title: '删除',
|
||||||
|
'x-component': 'Action',
|
||||||
|
},
|
||||||
|
create: {
|
||||||
|
type: 'void',
|
||||||
|
title: '创建',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
|
'x-decorator': 'Form',
|
||||||
|
title: 'Drawer Title',
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer.Footer',
|
||||||
|
properties: {
|
||||||
|
action1: {
|
||||||
|
title: 'Cancel',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
useAction: '{{ useCancelAction }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
action2: {
|
||||||
|
title: 'Submit',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
useAction: '{{ useCreateAction }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
table1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'VoidTable',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
rowSelection: {
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
useDataSource: '{{ useDataSourceFromRAC }}',
|
||||||
|
},
|
||||||
|
'x-column-initializer': 'AddTableColumn',
|
||||||
|
properties: {
|
||||||
|
column3: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Actions',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Space',
|
||||||
|
'x-component-props': {
|
||||||
|
split: '|',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
view: {
|
||||||
|
type: 'void',
|
||||||
|
title: '配置字段',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
|
title: 'Drawer Title',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
update: {
|
||||||
|
type: 'void',
|
||||||
|
title: '编辑',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
|
'x-decorator': 'Form',
|
||||||
|
'x-decorator-props': {
|
||||||
|
useValues: '{{ useValues }}',
|
||||||
|
},
|
||||||
|
title: 'Drawer Title',
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
},
|
||||||
|
name: {
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-disabled': true,
|
||||||
|
},
|
||||||
|
footer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer.Footer',
|
||||||
|
properties: {
|
||||||
|
action1: {
|
||||||
|
title: 'Cancel',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
useAction: '{{ useCancelAction }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
action2: {
|
||||||
|
title: 'Submit',
|
||||||
|
'x-component': 'Action',
|
||||||
|
'x-component-props': {
|
||||||
|
type: 'primary',
|
||||||
|
useAction: '{{ useUpdateAction }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
delete: {
|
||||||
|
type: 'void',
|
||||||
|
title: '删除',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': {
|
||||||
|
useAction: '{{ useDestroyAction }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemWrap = SchemaInitializer.itemWrap;
|
||||||
|
|
||||||
|
export const FormBlockInitializerItem = itemWrap((props) => {
|
||||||
|
const { insert } = props;
|
||||||
|
const { collections } = useCollectionManager();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
icon={<TableOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
insert(clone(collectionSchema));
|
||||||
|
}}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: 'select a data source',
|
||||||
|
children: collections?.map((item) => {
|
||||||
|
return {
|
||||||
|
type: 'item',
|
||||||
|
name: item.name,
|
||||||
|
title: item.title,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
Form
|
||||||
|
</SchemaInitializer.Item>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,135 @@
|
|||||||
|
import { TableOutlined } from '@ant-design/icons';
|
||||||
|
import { ISchema } from '@formily/react';
|
||||||
|
import { clone } from '@formily/shared';
|
||||||
|
import React from 'react';
|
||||||
|
import { SchemaInitializer } from '../..';
|
||||||
|
import { CollectionOptions, useCollectionManager } from '../../../collection-manager';
|
||||||
|
|
||||||
|
const collection: CollectionOptions = {
|
||||||
|
name: 'collections',
|
||||||
|
filterTargetKey: 'name',
|
||||||
|
targetKey: 'name',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
type: 'integer',
|
||||||
|
name: 'title',
|
||||||
|
interface: 'input',
|
||||||
|
uiSchema: {
|
||||||
|
title: '数据表名称',
|
||||||
|
type: 'number',
|
||||||
|
required: true,
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'string',
|
||||||
|
name: 'name',
|
||||||
|
interface: 'input',
|
||||||
|
uiSchema: {
|
||||||
|
title: '数据表标识',
|
||||||
|
type: 'string',
|
||||||
|
description: '使用英文',
|
||||||
|
'x-component': 'Input',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'hasMany',
|
||||||
|
name: 'fields',
|
||||||
|
target: 'fields',
|
||||||
|
collectionName: 'collections',
|
||||||
|
sourceKey: 'name',
|
||||||
|
targetKey: 'name',
|
||||||
|
uiSchema: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const collectionSchema: ISchema = {
|
||||||
|
type: 'void',
|
||||||
|
'x-collection': 'collections',
|
||||||
|
'x-component': 'CardItem',
|
||||||
|
'x-decorator': 'ResourceActionProvider',
|
||||||
|
'x-decorator-props': {
|
||||||
|
collection,
|
||||||
|
request: {
|
||||||
|
resource: 'collections',
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
pageSize: 5,
|
||||||
|
filter: {},
|
||||||
|
sort: ['sort'],
|
||||||
|
appends: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-action-initializer': 'TableActionInitializer',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
table1: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'VoidTable',
|
||||||
|
'x-component-props': {
|
||||||
|
rowKey: 'id',
|
||||||
|
rowSelection: {
|
||||||
|
type: 'checkbox',
|
||||||
|
},
|
||||||
|
useDataSource: '{{ useDataSourceFromRAC }}',
|
||||||
|
},
|
||||||
|
'x-column-initializer': 'TableColumnInitializer',
|
||||||
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
title: 'Actions',
|
||||||
|
'x-decorator': 'TableColumnActionBar',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
'x-action-initializer': 'TableColumnActionInitializer',
|
||||||
|
properties: {
|
||||||
|
actions: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Space',
|
||||||
|
'x-component-props': {
|
||||||
|
split: '|',
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemWrap = SchemaInitializer.itemWrap;
|
||||||
|
|
||||||
|
export const TableBlockInitializerItem = itemWrap((props) => {
|
||||||
|
const { insert } = props;
|
||||||
|
const { collections } = useCollectionManager();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
icon={<TableOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
insert(clone(collectionSchema));
|
||||||
|
}}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: 'select a data source',
|
||||||
|
children: collections?.map((item) => {
|
||||||
|
return {
|
||||||
|
type: 'item',
|
||||||
|
name: item.name,
|
||||||
|
title: item.title,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
Table
|
||||||
|
</SchemaInitializer.Item>
|
||||||
|
);
|
||||||
|
});
|
@ -1,8 +1,10 @@
|
|||||||
import { FormOutlined, TableOutlined } from '@ant-design/icons';
|
import { FormOutlined } from '@ant-design/icons';
|
||||||
import { ISchema, observer } from '@formily/react';
|
import { ISchema, observer } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SchemaInitializer } from '../../../schema-initializer';
|
import { SchemaInitializer } from '../..';
|
||||||
|
import { FormBlockInitializerItem } from './FormBlockInitializerItem';
|
||||||
|
import { TableBlockInitializerItem } from './TableBlockInitializerItem';
|
||||||
|
|
||||||
const gridRowColWrap = (schema: ISchema) => {
|
const gridRowColWrap = (schema: ISchema) => {
|
||||||
return {
|
return {
|
||||||
@ -22,87 +24,6 @@ const gridRowColWrap = (schema: ISchema) => {
|
|||||||
|
|
||||||
const itemWrap = SchemaInitializer.itemWrap;
|
const itemWrap = SchemaInitializer.itemWrap;
|
||||||
|
|
||||||
const TableBlockInitializerItem = itemWrap((props) => {
|
|
||||||
const { insert } = props;
|
|
||||||
return (
|
|
||||||
<SchemaInitializer.Item
|
|
||||||
icon={<TableOutlined />}
|
|
||||||
onClick={() => {
|
|
||||||
insert({
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'VoidTable',
|
|
||||||
'x-decorator': 'CardItem',
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
type: 'itemGroup',
|
|
||||||
title: 'select a data source',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: 'item',
|
|
||||||
name: 'users',
|
|
||||||
title: 'Users',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'item',
|
|
||||||
name: 'posts',
|
|
||||||
title: 'Posts',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
Table
|
|
||||||
</SchemaInitializer.Item>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const FormBlockInitializerItem = itemWrap((props) => {
|
|
||||||
const { insert } = props;
|
|
||||||
return (
|
|
||||||
<SchemaInitializer.Item
|
|
||||||
icon={<FormOutlined />}
|
|
||||||
onClick={() => {
|
|
||||||
insert({
|
|
||||||
type: 'void',
|
|
||||||
'x-uid': uid(),
|
|
||||||
'x-component': 'Form',
|
|
||||||
'x-decorator': 'CardItem',
|
|
||||||
properties: {
|
|
||||||
[uid()]: {
|
|
||||||
type: 'void',
|
|
||||||
'x-component': 'Grid',
|
|
||||||
'x-item-initializer': 'Grid.AddFormItem',
|
|
||||||
'x-uid': uid(),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
items={[
|
|
||||||
{
|
|
||||||
type: 'itemGroup',
|
|
||||||
title: 'select a data source',
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
type: 'item',
|
|
||||||
name: 'users',
|
|
||||||
title: 'Users',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'item',
|
|
||||||
name: 'posts',
|
|
||||||
title: 'Posts',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
Form
|
|
||||||
</SchemaInitializer.Item>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const TestInitializerItem = itemWrap((props) => {
|
const TestInitializerItem = itemWrap((props) => {
|
||||||
const { insert } = props;
|
const { insert } = props;
|
||||||
return (
|
return (
|
||||||
@ -193,7 +114,7 @@ const TestInitializerItem = itemWrap((props) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const AddGridBlockItem = observer((props: any) => {
|
export const BlockInitializer = observer((props: any) => {
|
||||||
return (
|
return (
|
||||||
<SchemaInitializer.Button
|
<SchemaInitializer.Button
|
||||||
wrap={gridRowColWrap}
|
wrap={gridRowColWrap}
|
||||||
@ -213,11 +134,6 @@ export const AddGridBlockItem = observer((props: any) => {
|
|||||||
title: 'Form',
|
title: 'Form',
|
||||||
component: FormBlockInitializerItem,
|
component: FormBlockInitializerItem,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
type: 'item',
|
|
||||||
title: 'Test',
|
|
||||||
component: TestInitializerItem,
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
]}
|
]}
|
@ -0,0 +1,84 @@
|
|||||||
|
import { observer, useFieldSchema } from '@formily/react';
|
||||||
|
import { Switch } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import { SchemaInitializer } from '../..';
|
||||||
|
import { useDesignable } from '../../../schema-component';
|
||||||
|
|
||||||
|
const useCurrentActionSchema = (action: string) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { remove } = useDesignable();
|
||||||
|
const schema = fieldSchema.reduceProperties((buf, s) => {
|
||||||
|
if (s['x-action'] === action) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
schema,
|
||||||
|
exists: !!schema,
|
||||||
|
remove() {
|
||||||
|
schema && remove(schema);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const InitializeAction = SchemaInitializer.itemWrap((props) => {
|
||||||
|
const { item, insert } = props;
|
||||||
|
const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
onClick={() => {
|
||||||
|
if (exists) {
|
||||||
|
return remove();
|
||||||
|
}
|
||||||
|
insert({
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action',
|
||||||
|
...item.schema,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
|
{item.title} <Switch size={'small'} checked={exists} />
|
||||||
|
</div>
|
||||||
|
</SchemaInitializer.Item>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const DetailsActionInitializer = observer((props: any) => {
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Button
|
||||||
|
insertPosition={'beforeEnd'}
|
||||||
|
style={{ marginLeft: 8 }}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: 'Enable actions',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: 'Create',
|
||||||
|
component: InitializeAction,
|
||||||
|
schema: {
|
||||||
|
title: 'Create',
|
||||||
|
'x-action': 'posts:create',
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: 'Update',
|
||||||
|
component: InitializeAction,
|
||||||
|
schema: {
|
||||||
|
title: 'Update',
|
||||||
|
'x-action': 'posts:update',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
Configure actions
|
||||||
|
</SchemaInitializer.Button>
|
||||||
|
);
|
||||||
|
});
|
@ -2,8 +2,8 @@ import { ISchema, observer, Schema, useFieldSchema } from '@formily/react';
|
|||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import { Switch } from 'antd';
|
import { Switch } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { SchemaInitializer, SchemaInitializerItemOptions } from '../../../schema-initializer';
|
import { SchemaInitializer, SchemaInitializerItemOptions } from '../..';
|
||||||
import { useDesignable } from '../../hooks';
|
import { useDesignable } from '../../../schema-component';
|
||||||
|
|
||||||
const useFormItemInitializerFields = () => {
|
const useFormItemInitializerFields = () => {
|
||||||
return [
|
return [
|
||||||
@ -122,7 +122,7 @@ const InitializeTextFormItem = itemWrap((props) => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
export const AddGridFormItem = observer((props: any) => {
|
export const FormItemInitializer = observer((props: any) => {
|
||||||
return (
|
return (
|
||||||
<SchemaInitializer.Button
|
<SchemaInitializer.Button
|
||||||
wrap={gridRowColWrap}
|
wrap={gridRowColWrap}
|
@ -0,0 +1,142 @@
|
|||||||
|
import { FormOutlined } from '@ant-design/icons';
|
||||||
|
import { ISchema, observer } from '@formily/react';
|
||||||
|
import { uid } from '@formily/shared';
|
||||||
|
import React from 'react';
|
||||||
|
import { SchemaInitializer } from '../..';
|
||||||
|
|
||||||
|
const gridRowColWrap = (schema: ISchema) => {
|
||||||
|
return {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
properties: {
|
||||||
|
[uid()]: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
properties: {
|
||||||
|
[schema.name || uid()]: schema,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const itemWrap = SchemaInitializer.itemWrap;
|
||||||
|
|
||||||
|
const TestInitializerItem = 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',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Test
|
||||||
|
</SchemaInitializer.Item>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const RecordBlockInitializer = observer((props: any) => {
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Button
|
||||||
|
wrap={gridRowColWrap}
|
||||||
|
insertPosition={'beforeEnd'}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: 'Data blocks',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: 'Form',
|
||||||
|
component: TestInitializerItem,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: 'Details',
|
||||||
|
component: TestInitializerItem,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
Add block
|
||||||
|
</SchemaInitializer.Button>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,96 @@
|
|||||||
|
import { observer, useFieldSchema } from '@formily/react';
|
||||||
|
import { Switch } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { SchemaInitializer } from '../..';
|
||||||
|
import { useDesignable } from '../../../schema-component';
|
||||||
|
|
||||||
|
const useCurrentActionSchema = (action: string) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { remove } = useDesignable();
|
||||||
|
const schema = fieldSchema.reduceProperties((buf, s) => {
|
||||||
|
if (s['x-action'] === action) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
schema,
|
||||||
|
exists: !!schema,
|
||||||
|
remove() {
|
||||||
|
schema && remove(schema);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const InitializeAction = SchemaInitializer.itemWrap((props) => {
|
||||||
|
const { item, insert } = props;
|
||||||
|
const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
onClick={() => {
|
||||||
|
if (exists) {
|
||||||
|
return remove();
|
||||||
|
}
|
||||||
|
insert({
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action',
|
||||||
|
...item.schema,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
|
{item.title}
|
||||||
|
<Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
|
||||||
|
</div>
|
||||||
|
</SchemaInitializer.Item>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const TableActionInitializer = observer((props: any) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Button
|
||||||
|
insertPosition={'beforeEnd'}
|
||||||
|
style={{ marginLeft: 8 }}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: t('Enable actions'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: t('Filter'),
|
||||||
|
component: InitializeAction,
|
||||||
|
schema: {
|
||||||
|
title: '{{ t("Filter") }}',
|
||||||
|
'x-action': 'filter',
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: t('Add new'),
|
||||||
|
component: InitializeAction,
|
||||||
|
schema: {
|
||||||
|
title: '{{ t("Add new") }}',
|
||||||
|
'x-action': 'create',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: t('Delete'),
|
||||||
|
component: InitializeAction,
|
||||||
|
schema: {
|
||||||
|
title: '{{ t("Delete") }}',
|
||||||
|
'x-action': 'destroy',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{t('Configure actions')}
|
||||||
|
</SchemaInitializer.Button>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,145 @@
|
|||||||
|
import { observer, Schema, useFieldSchema } from '@formily/react';
|
||||||
|
import { Switch } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { SchemaInitializer } from '../..';
|
||||||
|
import { useAPIClient } from '../../../api-client';
|
||||||
|
import { createDesignable, useDesignable } from '../../../schema-component';
|
||||||
|
|
||||||
|
const useCurrentActionSchema = (action: string) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { remove } = useDesignable();
|
||||||
|
const findActionSchema = (schema: Schema) => {
|
||||||
|
return schema.reduceProperties((buf, s) => {
|
||||||
|
if (s['x-action'] === action) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
const c = findActionSchema(s);
|
||||||
|
if (c) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const schema = findActionSchema(fieldSchema);
|
||||||
|
return {
|
||||||
|
schema,
|
||||||
|
exists: !!schema,
|
||||||
|
remove() {
|
||||||
|
schema && remove(schema);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const InitializeAction = SchemaInitializer.itemWrap((props) => {
|
||||||
|
const { item, insert } = props;
|
||||||
|
const { exists, remove } = useCurrentActionSchema(item.schema['x-action']);
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
onClick={() => {
|
||||||
|
console.log('InitializeAction', insert);
|
||||||
|
if (exists) {
|
||||||
|
return remove();
|
||||||
|
}
|
||||||
|
insert({
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
...item.schema,
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
|
{item.title} <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
|
||||||
|
</div>
|
||||||
|
</SchemaInitializer.Item>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
export const TableColumnActionInitializer = observer((props: any) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const api = useAPIClient();
|
||||||
|
const { refresh } = useDesignable();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Button
|
||||||
|
insertPosition={'beforeEnd'}
|
||||||
|
insert={(schema) => {
|
||||||
|
const spaceSchema = fieldSchema.reduceProperties((buf, schema) => {
|
||||||
|
if (schema['x-component'] === 'Space') {
|
||||||
|
return schema;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}, null);
|
||||||
|
if (!spaceSchema) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const dn = createDesignable({
|
||||||
|
api,
|
||||||
|
refresh,
|
||||||
|
current: spaceSchema,
|
||||||
|
});
|
||||||
|
dn.loadAPIClientEvents();
|
||||||
|
dn.insertBeforeEnd(schema);
|
||||||
|
}}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: t('Enable actions'),
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: t('View'),
|
||||||
|
component: InitializeAction,
|
||||||
|
schema: {
|
||||||
|
title: '{{ t("View") }}',
|
||||||
|
type: 'void',
|
||||||
|
'x-action': 'view',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
|
title: '{{ t("View record") }}',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: t('Edit'),
|
||||||
|
component: InitializeAction,
|
||||||
|
schema: {
|
||||||
|
title: '{{ t("Edit") }}',
|
||||||
|
type: 'void',
|
||||||
|
'x-action': 'update',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Action.Drawer',
|
||||||
|
title: '{{ t("Edit record") }}',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: t('Delete'),
|
||||||
|
component: InitializeAction,
|
||||||
|
schema: {
|
||||||
|
title: '{{ t("Delete") }}',
|
||||||
|
'x-action': 'destroy',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
Configure
|
||||||
|
</SchemaInitializer.Button>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,99 @@
|
|||||||
|
import { observer, Schema, useFieldSchema } from '@formily/react';
|
||||||
|
import { Switch } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { SchemaInitializer, SchemaInitializerItemOptions } from '../..';
|
||||||
|
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,
|
||||||
|
schema: {
|
||||||
|
name: field.name,
|
||||||
|
'x-collection-field': `${name}.${field.name}`,
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
},
|
||||||
|
component: ColumnInitializerItem,
|
||||||
|
} as SchemaInitializerItemOptions;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const useCurrentColumnSchema = (path: string) => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { remove } = useDesignable();
|
||||||
|
const findFieldSchema = (schema: Schema) => {
|
||||||
|
return schema.reduceProperties((buf, s) => {
|
||||||
|
if (s['x-collection-field'] === path) {
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
const child = findFieldSchema(s);
|
||||||
|
if (child) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
const schema = findFieldSchema(fieldSchema);
|
||||||
|
return {
|
||||||
|
schema,
|
||||||
|
exists: !!schema,
|
||||||
|
remove() {
|
||||||
|
schema && remove(schema.parent);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const ColumnInitializerItem = SchemaInitializer.itemWrap((props) => {
|
||||||
|
const { item, insert } = props;
|
||||||
|
const { exists, remove } = useCurrentColumnSchema(item.schema['x-collection-field']);
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Item
|
||||||
|
onClick={() => {
|
||||||
|
if (exists) {
|
||||||
|
return remove();
|
||||||
|
}
|
||||||
|
insert({
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'TableColumnDecorator',
|
||||||
|
'x-component': 'VoidTable.Column',
|
||||||
|
properties: {
|
||||||
|
[item.schema.name]: {
|
||||||
|
'x-read-pretty': true,
|
||||||
|
...item.schema,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
|
||||||
|
{item.title} <Switch style={{ marginLeft: 20 }} size={'small'} checked={exists} />
|
||||||
|
</div>
|
||||||
|
</SchemaInitializer.Item>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表格列配置器
|
||||||
|
*/
|
||||||
|
export const TableColumnInitializer = observer((props: any) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
return (
|
||||||
|
<SchemaInitializer.Button
|
||||||
|
insertPosition={'beforeEnd'}
|
||||||
|
items={[
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: t('Display fields'),
|
||||||
|
children: useTableColumnInitializerFields(),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{t('Configure columns')}
|
||||||
|
</SchemaInitializer.Button>
|
||||||
|
);
|
||||||
|
});
|
@ -0,0 +1,8 @@
|
|||||||
|
export * from './BlockInitializer';
|
||||||
|
export * from './DetailsActionInitializer';
|
||||||
|
export * from './FormItemInitializer';
|
||||||
|
export * from './RecordBlockInitializer';
|
||||||
|
export * from './TableActionInitializer';
|
||||||
|
export * from './TableColumnActionInitializer';
|
||||||
|
export * from './TableColumnInitializer';
|
||||||
|
|
@ -16,10 +16,16 @@ export const SchemaInitializerItemContext = createContext(null);
|
|||||||
export const SchemaInitializer = () => null;
|
export const SchemaInitializer = () => null;
|
||||||
|
|
||||||
SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
|
SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
|
||||||
const { wrap = defaultWrap, items = [], insertPosition, dropdown, ...others } = props;
|
const { insert, wrap = defaultWrap, items = [], insertPosition, dropdown, ...others } = props;
|
||||||
const { insertAdjacent, findComponent } = useDesignable();
|
let { insertAdjacent, findComponent } = useDesignable();
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
|
const insertSchema = (schema) => {
|
||||||
|
if (props.insert) {
|
||||||
|
props.insert(wrap(schema));
|
||||||
|
} else {
|
||||||
|
insertAdjacent(insertPosition, wrap(schema));
|
||||||
|
}
|
||||||
|
};
|
||||||
const menu = (
|
const menu = (
|
||||||
<Menu>
|
<Menu>
|
||||||
{items?.map((item, indexA) => {
|
{items?.map((item, indexA) => {
|
||||||
@ -36,18 +42,10 @@ SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
|
|||||||
index: indexA,
|
index: indexA,
|
||||||
item,
|
item,
|
||||||
info: item,
|
info: item,
|
||||||
insert: (schema) => {
|
insert: insertSchema,
|
||||||
insertAdjacent(insertPosition, wrap(schema));
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Component
|
<Component {...item} item={item} insert={insertSchema} />
|
||||||
{...item}
|
|
||||||
item={item}
|
|
||||||
insert={(schema) => {
|
|
||||||
insertAdjacent(insertPosition, wrap(schema));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</SchemaInitializerItemContext.Provider>
|
</SchemaInitializerItemContext.Provider>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -68,18 +66,10 @@ SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
|
|||||||
index: indexB,
|
index: indexB,
|
||||||
item: child,
|
item: child,
|
||||||
info: child,
|
info: child,
|
||||||
insert: (schema) => {
|
insert: insertSchema,
|
||||||
insertAdjacent(insertPosition, wrap(schema));
|
|
||||||
},
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Component
|
<Component {...child} item={child} insert={insertSchema} />
|
||||||
{...child}
|
|
||||||
item={child}
|
|
||||||
insert={(schema) => {
|
|
||||||
insertAdjacent(insertPosition, wrap(schema));
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</SchemaInitializerItemContext.Provider>
|
</SchemaInitializerItemContext.Provider>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -91,6 +81,8 @@ SchemaInitializer.Button = observer((props: SchemaInitializerButtonProps) => {
|
|||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
console.log('others', others);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dropdown
|
<Dropdown
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { SchemaComponentOptions } from '../schema-component';
|
||||||
|
import * as initializers from './Initializers';
|
||||||
|
|
||||||
|
export const SchemaInitializerProvider: React.FC = (props) => {
|
||||||
|
return <SchemaComponentOptions components={initializers}>{props.children}</SchemaComponentOptions>;
|
||||||
|
};
|
@ -1,3 +1,4 @@
|
|||||||
export * from './SchemaInitializer';
|
export * from './SchemaInitializer';
|
||||||
|
export * from './SchemaInitializerProvider';
|
||||||
export * from './types';
|
export * from './types';
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ import { ISchema } from '@formily/react';
|
|||||||
import { ButtonProps, DropDownProps, MenuItemProps } from 'antd';
|
import { ButtonProps, DropDownProps, MenuItemProps } from 'antd';
|
||||||
|
|
||||||
export interface SchemaInitializerButtonProps extends ButtonProps {
|
export interface SchemaInitializerButtonProps extends ButtonProps {
|
||||||
|
insert?: (s: ISchema) => void;
|
||||||
wrap?: (s: ISchema) => ISchema;
|
wrap?: (s: ISchema) => ISchema;
|
||||||
insertPosition?: 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd';
|
insertPosition?: 'beforeBegin' | 'afterBegin' | 'beforeEnd' | 'afterEnd';
|
||||||
items?: SchemaInitializerItemOptions[];
|
items?: SchemaInitializerItemOptions[];
|
||||||
|
@ -54,12 +54,12 @@ export class UiRoutesStoragePlugin extends Plugin {
|
|||||||
grid1: {
|
grid1: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
'x-component': 'Grid',
|
'x-component': 'Grid',
|
||||||
'x-item-initializer': 'Grid.AddBlockItem',
|
'x-item-initializer': 'BlockInitializer',
|
||||||
properties: {},
|
properties: {},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
item8: {
|
item8: {
|
||||||
type: 'void',
|
type: 'void',
|
||||||
|
Loading…
Reference in New Issue
Block a user