feat: improve schema initializer

This commit is contained in:
chenos 2022-03-04 11:59:38 +08:00
parent 590ca267b2
commit ac4c8f031d
7 changed files with 174 additions and 126 deletions

View File

@ -8,13 +8,14 @@ export const ResourceActionContext = createContext<Result<any, any> & { state?:
interface ResourceActionProviderProps {
type?: 'association' | 'collection';
collection?: any;
request?: any;
uid?: string;
}
const ResourceContext = createContext<any>(null);
const InternalCollectionResourceActionProvider = (props) => {
const CollectionResourceActionProvider = (props) => {
let { collection, request, uid } = props;
const api = useAPIClient();
const service = useRequest(
@ -22,7 +23,7 @@ const InternalCollectionResourceActionProvider = (props) => {
...request,
params: {
...request?.params,
appends: collection.fields.filter(field => field.target).map((field) => field.name),
appends: collection.fields.filter((field) => field.target).map((field) => field.name),
},
},
{ uid },
@ -37,32 +38,26 @@ const InternalCollectionResourceActionProvider = (props) => {
);
};
const CollectionResourceActionProvider = (props) => {
let { collection, request, uid } = props;
const { getCollection } = useCollectionManager();
if (typeof collection === 'string') {
collection = getCollection(collection);
}
if (!collection) {
return null;
}
return <InternalCollectionResourceActionProvider {...props} collection={collection} />;
};
const AssociationResourceActionProvider = (props) => {
let { collection, association, request, uid } = props;
const { get } = useCollectionManager();
const api = useAPIClient();
const record = useRecord();
const resourceOf = record[association.sourceKey];
const service = useRequest({ resourceOf, ...request }, { uid });
const service = useRequest(
{
resourceOf,
...request,
params: {
...request?.params,
appends: [
...collection?.fields?.filter?.((field) => field.target).map((field) => field.name),
...request?.params?.appends,
],
},
},
{ uid },
);
const resource = api.resource(request.resource, resourceOf);
if (typeof collection === 'string') {
collection = get(collection);
}
if (!collection) {
return null;
}
return (
<ResourceContext.Provider value={{ type: 'association', resource, association }}>
<ResourceActionContext.Provider value={service}>
@ -73,11 +68,18 @@ const AssociationResourceActionProvider = (props) => {
};
export const ResourceActionProvider: React.FC<ResourceActionProviderProps> = (props) => {
const { request } = props;
if (request?.resource?.includes('.')) {
return <AssociationResourceActionProvider {...props} />;
let { collection, request } = props;
const { getCollection } = useCollectionManager();
if (typeof collection === 'string') {
collection = getCollection(collection);
}
return <CollectionResourceActionProvider {...props} />;
if (!collection) {
return null;
}
if (request?.resource?.includes('.')) {
return <AssociationResourceActionProvider {...props} collection={collection} />;
}
return <CollectionResourceActionProvider {...props} collection={collection} />;
};
export const useResourceActionContext = () => {

View File

@ -1,6 +1,7 @@
import { css } from '@emotion/css';
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
import { Drawer } from 'antd';
import classNames from 'classnames';
import React from 'react';
import { createPortal } from 'react-dom';
import { useActionContext } from './hooks';
@ -27,6 +28,13 @@ export const ActionDrawer: ComposedActionDrawer = observer((props) => {
destroyOnClose
visible={visible}
onClose={() => setVisible(false)}
className={classNames(others.className, css`
&.nb-action-popup {
.ant-drawer-content {
background: #f0f2f5;
}
}
`)}
footer={
footerSchema && (
<div

View File

@ -114,45 +114,28 @@ export const LinkToFieldInitializer = (props) => {
properties: {
drawer1: {
'x-component': 'Action.Drawer',
'x-component-props': {
},
type: 'void',
title: 'Drawer Title',
properties: {
details: {
tabs: {
type: 'void',
'x-collection': 'collections',
'x-decorator': 'ResourceActionProvider',
'x-decorator-props': {
collection: item.field.target,
request: {
resource: item.field.target,
action: 'get',
params: {},
},
},
'x-designer': 'Form.Designer',
'x-component': 'CardItem',
'x-component': 'Tabs',
'x-component-props': {},
'x-initializer': 'TabPaneInitializers',
properties: {
form: {
tab1: {
type: 'void',
'x-decorator': 'Form',
'x-decorator-props': {},
title: '详情',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
properties: {
actions: {
type: 'void',
'x-initializer': 'FormActionInitializers',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
style: {
marginBottom: 16,
},
},
properties: {},
},
grid: {
type: 'void',
'x-component': 'Grid',
'x-initializer': 'GridFormItemInitializers',
'x-initializer': 'RecordBlockInitializers',
properties: {},
},
},

View File

@ -3,12 +3,11 @@ import { ISchema } from '@formily/react';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { SchemaInitializer } from '../..';
import { useCollectionManager } from '../../../collection-manager';
import { useCollection } from '../../../collection-manager';
const createSchema = (collectionName) => {
const schema: ISchema = {
type: 'void',
'x-collection': 'collections',
'x-decorator': 'ResourceActionProvider',
'x-decorator-props': {
collection: collectionName,
@ -53,14 +52,14 @@ const createSchema = (collectionName) => {
export const RecordFormBlockInitializer = (props) => {
const { insert } = props;
const { collections } = useCollectionManager();
const { name } = useCollection();
const { t } = useTranslation();
return (
<SchemaInitializer.Item
{...props}
icon={<FormOutlined />}
onClick={({ item }) => {
insert(createSchema(item.name));
insert(createSchema(name));
}}
/>
);

View File

@ -4,45 +4,77 @@ import React from 'react';
import { useTranslation } from 'react-i18next';
import { SchemaInitializer } from '../..';
import { useCollectionManager } from '../../../collection-manager';
import { useRecord } from '../../../record-provider';
const createSchema = (collectionName) => {
const createSchema = (field, record) => {
const resourceOf = record[field.sourceKey || 'id'];
const schema: ISchema = {
type: 'void',
'x-collection': 'collections',
'x-decorator': 'ResourceActionProvider',
'x-decorator-props': {
collection: collectionName,
collection: field.target,
association: {
name: field.name,
targetKey: field.targetKey,
sourceKey: field.sourceKey,
},
request: {
resource: collectionName,
action: 'get',
params: {},
resource: `${field.collectionName}.${field.name}`,
// resourceOf,
action: 'list',
params: {
pageSize: 20,
filter: {},
// sort: ['sort'],
appends: [],
},
},
},
'x-designer': 'Form.Designer',
'x-designer': 'Table.Void.Designer',
'x-component': 'CardItem',
properties: {
form: {
actions: {
type: 'void',
'x-decorator': 'Form',
'x-decorator-props': {},
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-initializer': 'GridFormItemInitializers',
properties: {},
'x-initializer': 'TableActionInitializers',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 16,
},
},
properties: {},
},
table: {
type: 'void',
'x-component': 'Table.Void',
'x-component-props': {
rowKey: 'id',
rowSelection: {
type: 'checkbox',
},
useDataSource: '{{ cm.useDataSourceFromRAC }}',
},
'x-initializer': 'TableColumnInitializers',
properties: {
actions: {
type: 'void',
'x-initializer': 'FormActionInitializers',
'x-component': 'ActionBar',
'x-component-props': {
layout: 'one-column',
style: {
marginTop: 24,
title: '{{ t("Actions") }}',
'x-decorator': 'Table.Column.ActionBar',
'x-component': 'Table.Column',
'x-designer': 'Table.RowActionDesigner',
'x-initializer': 'TableRecordActionInitializers',
properties: {
actions: {
type: 'void',
'x-decorator': 'DndContext',
'x-component': 'Space',
'x-component-props': {
split: '|',
},
properties: {},
},
},
properties: {},
},
},
},
@ -55,12 +87,13 @@ export const RecordRelationBlockInitializer = (props) => {
const { insert } = props;
const { collections } = useCollectionManager();
const { t } = useTranslation();
const record = useRecord();
return (
<SchemaInitializer.Item
{...props}
icon={<FormOutlined />}
onClick={({ item }) => {
insert(createSchema(item.name));
insert(createSchema(item.field, record));
}}
/>
);

View File

@ -1,47 +1,67 @@
import { useFieldSchema } from '@formily/react';
import React from 'react';
import { useTranslation } from 'react-i18next';
import { SchemaInitializer, useCollection } from '../..';
import { useAPIClient } from '../../api-client';
import { useDesignable } from '../../schema-component';
import { gridRowColWrap } from './utils';
// 当前行记录所在面板的添加区块
export const RecordBlockInitializers = {
wrap: gridRowColWrap,
title: "{{t('Add block')}}",
items: [
{
type: 'itemGroup',
title: 'Data blocks',
children: [
{
type: 'item',
title: 'Details',
component: 'RecordFormBlockInitializer',
},
{
type: 'item',
title: 'Form',
component: 'RecordFormBlockInitializer',
},
],
},
{
type: 'itemGroup',
title: '关系数据区块',
children: [
{
type: 'item',
title: '关系数据',
component: 'RecordRelationBlockInitializer',
},
],
},
{
type: 'itemGroup',
title: 'Media',
children: [
{
type: 'item',
title: 'Markdown',
component: 'MarkdownBlockInitializer',
},
],
},
],
const useRelationFields = () => {
const { fields } = useCollection();
return fields.filter(field => field.interface === 'linkTo').map((field) => {
return {
type: 'item',
field,
title: field?.uiSchema?.title || field.name,
component: 'RecordRelationBlockInitializer',
};
}) as any;
};
// 当前行记录所在面板的添加区块
export const RecordBlockInitializers = (props: any) => {
const fieldSchema = useFieldSchema();
const api = useAPIClient();
const { refresh } = useDesignable();
const { t } = useTranslation();
return (
<SchemaInitializer.Button
wrap={gridRowColWrap}
title={t('Add block')}
items={[
{
type: 'itemGroup',
title: 'Data blocks',
children: [
{
type: 'item',
title: 'Details',
component: 'RecordFormBlockInitializer',
},
{
type: 'item',
title: 'Form',
component: 'RecordFormBlockInitializer',
},
],
},
{
type: 'itemGroup',
title: '关系数据区块',
children: useRelationFields(),
},
{
type: 'itemGroup',
title: 'Media',
children: [
{
type: 'item',
title: 'Markdown',
component: 'MarkdownBlockInitializer',
},
],
},
]}
/>
);
};

View File

@ -63,6 +63,9 @@ export const TableRecordActionInitializers = (props: any) => {
drawer: {
type: 'void',
'x-component': 'Action.Drawer',
'x-component-props': {
className: 'nb-action-popup',
},
title: '{{ t("View record") }}',
properties: {
tabs: {