feat: support List and Grid Card block (#1753)
* feat: support details block * feat: rename to list * fix: imports * feat: improve list block * feat: support title hidden * fix: showTitle default value * feat: support table column actions * feat: support appendsOnDemand * feat: reuse same schema items * feat: shouldn't display pagination when pages only one * feat: block order * feat: support card list * fix: appends on demand * fix: remove unused code * fix: params * fix: improve default pageSize * feat: improve performance * feat: add title designer * feat: improve huge performance * fix: better key * feat: improve schema perf * feat: improve initializer * fix: improve grid perf * fix: avoid haven't properties * feat: support automatic run service when params changed * fix: revert params * fix: grid col width * refactor: improve CardList performance * fix: initializer related * feat: i18n supports * fix: improve get schema * fix: create new form * fix: revert code * feat: css improve * fix: i18n copy * refactor: the CardList rename to GridCard * feat: remove AssociationFilter item * fix: edit and view data is incorrect * feat: remove bulk actions * feat: improve action bar * feat: supports configuration of columns with different screen sizes * fix: incorrect place to save the template * feat: keep height in all card * fix: remove console * fix: rename * refactor: improve GridCard implementation * feat: support import/export actions * fix: remove padding when actions is empty * fix: remove incorrect import * fix: remove unused props * fix: action place * feat: improve column count * refactor: remove appendsOnDemand, and use useAssociationNames instated it * fix: incorrect component --------- Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
parent
26469f7aaf
commit
3a77e4376a
@ -137,7 +137,7 @@ const getIgnoreScope = (options: any = {}) => {
|
|||||||
|
|
||||||
const useAllowedActions = () => {
|
const useAllowedActions = () => {
|
||||||
const result = useBlockRequestContext() || { service: useResourceActionContext() };
|
const result = useBlockRequestContext() || { service: useResourceActionContext() };
|
||||||
return result?.service?.data?.meta?.allowedActions;
|
return result?.allowedActions ?? result?.service?.data?.meta?.allowedActions;
|
||||||
};
|
};
|
||||||
|
|
||||||
const useResourceName = () => {
|
const useResourceName = () => {
|
||||||
|
@ -2,9 +2,10 @@ import { css } from '@emotion/css';
|
|||||||
import { Field } from '@formily/core';
|
import { Field } from '@formily/core';
|
||||||
import { RecursionField, useField, useFieldSchema } from '@formily/react';
|
import { RecursionField, useField, useFieldSchema } from '@formily/react';
|
||||||
import { useRequest } from 'ahooks';
|
import { useRequest } from 'ahooks';
|
||||||
|
import merge from 'deepmerge';
|
||||||
import { Col, Row } from 'antd';
|
import { Col, Row } from 'antd';
|
||||||
import template from 'lodash/template';
|
import template from 'lodash/template';
|
||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext, useEffect, useRef, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
ACLCollectionProvider,
|
ACLCollectionProvider,
|
||||||
@ -19,6 +20,7 @@ import { CollectionProvider, useCollection, useCollectionManager } from '../coll
|
|||||||
import { FilterBlockRecord } from '../filter-provider/FilterProvider';
|
import { FilterBlockRecord } from '../filter-provider/FilterProvider';
|
||||||
import { useRecordIndex } from '../record-provider';
|
import { useRecordIndex } from '../record-provider';
|
||||||
import { SharedFilterProvider } from './SharedFilterProvider';
|
import { SharedFilterProvider } from './SharedFilterProvider';
|
||||||
|
import _ from 'lodash';
|
||||||
|
|
||||||
export const BlockResourceContext = createContext(null);
|
export const BlockResourceContext = createContext(null);
|
||||||
export const BlockAssociationContext = createContext(null);
|
export const BlockAssociationContext = createContext(null);
|
||||||
@ -92,18 +94,20 @@ export const useResourceAction = (props, opts = {}) => {
|
|||||||
/**
|
/**
|
||||||
* fieldName: 来自 TableFieldProvider
|
* fieldName: 来自 TableFieldProvider
|
||||||
*/
|
*/
|
||||||
const { resource, action, fieldName: tableFieldName } = props;
|
const { resource, action, fieldName: tableFieldName, runWhenParamsChanged = false } = props;
|
||||||
const { fields } = useCollection();
|
const { fields } = useCollection();
|
||||||
const appends = fields?.filter((field) => field.target).map((field) => field.name);
|
|
||||||
const params = useActionParams(props);
|
const params = useActionParams(props);
|
||||||
const api = useAPIClient();
|
const api = useAPIClient();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { snapshot } = useActionContext();
|
const { snapshot } = useActionContext();
|
||||||
const record = useRecord();
|
const record = useRecord();
|
||||||
|
|
||||||
if (!Object.keys(params).includes('appends') && appends?.length) {
|
if (!Reflect.has(params, 'appends')) {
|
||||||
|
const appends = fields?.filter((field) => field.target).map((field) => field.name);
|
||||||
|
if (appends?.length) {
|
||||||
params['appends'] = appends;
|
params['appends'] = appends;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
const result = useRequest(
|
const result = useRequest(
|
||||||
snapshot
|
snapshot
|
||||||
? async () => ({
|
? async () => ({
|
||||||
@ -113,10 +117,7 @@ export const useResourceAction = (props, opts = {}) => {
|
|||||||
if (!action) {
|
if (!action) {
|
||||||
return Promise.resolve({});
|
return Promise.resolve({});
|
||||||
}
|
}
|
||||||
const actionParams = { ...opts };
|
const actionParams = { ...params, ...opts };
|
||||||
if (params.appends) {
|
|
||||||
actionParams.appends = params.appends;
|
|
||||||
}
|
|
||||||
return resource[action](actionParams).then((res) => res.data);
|
return resource[action](actionParams).then((res) => res.data);
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -128,9 +129,22 @@ export const useResourceAction = (props, opts = {}) => {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
defaultParams: [params],
|
defaultParams: [params],
|
||||||
refreshDeps: [JSON.stringify(params.appends)],
|
refreshDeps: [runWhenParamsChanged ? JSON.stringify(params.appends) : null],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// automatic run service when params has changed
|
||||||
|
const firstRun = useRef(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (!runWhenParamsChanged) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (firstRun.current) {
|
||||||
|
result?.run({ ...result?.params?.[0], ...params });
|
||||||
|
}
|
||||||
|
firstRun.current = true;
|
||||||
|
}, [JSON.stringify(params), runWhenParamsChanged]);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -148,15 +162,29 @@ export const MaybeCollectionProvider = (props) => {
|
|||||||
const BlockRequestProvider = (props) => {
|
const BlockRequestProvider = (props) => {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const resource = useBlockResource();
|
const resource = useBlockResource();
|
||||||
|
const [allowedActions, setAllowedActions] = useState({});
|
||||||
|
|
||||||
const service = useResourceAction(
|
const service = useResourceAction(
|
||||||
{ ...props, resource },
|
{ ...props, resource },
|
||||||
{
|
{
|
||||||
...props.requestOptions,
|
...props.requestOptions,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Infinite scroll support
|
||||||
|
const serviceAllowedActions = (service?.data as any)?.meta?.allowedActions;
|
||||||
|
useEffect(() => {
|
||||||
|
if (!serviceAllowedActions) return;
|
||||||
|
setAllowedActions((last) => {
|
||||||
|
return merge(last, serviceAllowedActions ?? {});
|
||||||
|
});
|
||||||
|
}, [serviceAllowedActions]);
|
||||||
|
|
||||||
const __parent = useContext(BlockRequestContext);
|
const __parent = useContext(BlockRequestContext);
|
||||||
return (
|
return (
|
||||||
<BlockRequestContext.Provider value={{ block: props.block, props, field, service, resource, __parent }}>
|
<BlockRequestContext.Provider
|
||||||
|
value={{ allowedActions, block: props.block, props, field, service, resource, __parent }}
|
||||||
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
</BlockRequestContext.Provider>
|
</BlockRequestContext.Provider>
|
||||||
);
|
);
|
||||||
|
@ -1091,7 +1091,7 @@ export const useAssociationNames = (collection) => {
|
|||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const associationValues = [];
|
const associationValues = [];
|
||||||
const formSchema = fieldSchema.reduceProperties((buf, schema) => {
|
const formSchema = fieldSchema.reduceProperties((buf, schema) => {
|
||||||
if (['FormV2', 'Details'].includes(schema['x-component'])) {
|
if (['FormV2', 'Details', 'List', 'GridCard'].includes(schema['x-component'])) {
|
||||||
return schema;
|
return schema;
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
|
@ -69,7 +69,7 @@ const InternalField: React.FC = (props: Props) => {
|
|||||||
if (!uiSchema) {
|
if (!uiSchema) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return React.createElement(Component, props, props.children);
|
return <Component {...props} />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const InternalFallbackField = () => {
|
export const InternalFallbackField = () => {
|
||||||
|
@ -24,6 +24,7 @@ export * from './schema-component';
|
|||||||
export * from './schema-initializer';
|
export * from './schema-initializer';
|
||||||
export * from './schema-settings';
|
export * from './schema-settings';
|
||||||
export * from './schema-templates';
|
export * from './schema-templates';
|
||||||
|
export * from './schema-items';
|
||||||
export * from './settings-form';
|
export * from './settings-form';
|
||||||
export * from './system-settings';
|
export * from './system-settings';
|
||||||
export * from './user';
|
export * from './user';
|
||||||
|
@ -104,6 +104,17 @@ export default {
|
|||||||
"Table": "Table",
|
"Table": "Table",
|
||||||
"Table OID(Inheritance)":"Table OID(Inheritance)",
|
"Table OID(Inheritance)":"Table OID(Inheritance)",
|
||||||
"Form": "Form",
|
"Form": "Form",
|
||||||
|
"List": "List",
|
||||||
|
"Grid Card": "Grid Card",
|
||||||
|
"pixels": "pixels",
|
||||||
|
"Screen size": "Screen size",
|
||||||
|
"Display title": "Display title",
|
||||||
|
'Set the count of columns displayed in a row': "Set the count of columns displayed in a row",
|
||||||
|
'Column': 'Column',
|
||||||
|
'Phone device': 'Phone device',
|
||||||
|
'Tablet device': 'Tablet device',
|
||||||
|
'Desktop device': 'Desktop device',
|
||||||
|
'Large screen device': 'Large screen device',
|
||||||
"Collapse": "Collapse",
|
"Collapse": "Collapse",
|
||||||
"Select data source": "Select data source",
|
"Select data source": "Select data source",
|
||||||
"Calendar": "Calendar",
|
"Calendar": "Calendar",
|
||||||
|
@ -120,6 +120,17 @@ export default {
|
|||||||
"Filter blocks": "筛选区块",
|
"Filter blocks": "筛选区块",
|
||||||
"Table": "表格",
|
"Table": "表格",
|
||||||
"Form": "表单",
|
"Form": "表单",
|
||||||
|
"List": "列表",
|
||||||
|
"Grid Card": "网格卡片",
|
||||||
|
"Screen size": "屏幕尺寸",
|
||||||
|
"pixels": "像素",
|
||||||
|
"Display title": "显示标题",
|
||||||
|
'Set the count of columns displayed in a row': "设置一行展示的列数",
|
||||||
|
'Column': '列',
|
||||||
|
'Phone device': '手机设备',
|
||||||
|
'Tablet device': '平板设备',
|
||||||
|
'Desktop device': '电脑设备',
|
||||||
|
'Large screen device': '大屏幕设备',
|
||||||
"Table OID(Inheritance)":"数据表 OID(继承)",
|
"Table OID(Inheritance)":"数据表 OID(继承)",
|
||||||
"Collapse": "折叠面板",
|
"Collapse": "折叠面板",
|
||||||
"Select data source": "选择数据源",
|
"Select data source": "选择数据源",
|
||||||
@ -217,7 +228,6 @@ export default {
|
|||||||
"Edit collection": "编辑数据表",
|
"Edit collection": "编辑数据表",
|
||||||
"Configure fields": "配置字段",
|
"Configure fields": "配置字段",
|
||||||
"Configure columns": "配置字段",
|
"Configure columns": "配置字段",
|
||||||
"Please select the records you want to delete": "请选择要删除的记录",
|
|
||||||
"Edit field": "编辑字段",
|
"Edit field": "编辑字段",
|
||||||
"Override": "重写",
|
"Override": "重写",
|
||||||
"Override field": "重写字段",
|
"Override field": "重写字段",
|
||||||
|
@ -12,6 +12,10 @@ export const RecordProvider: React.FC<{ record: any; parent?: any }> = (props) =
|
|||||||
return <RecordContext.Provider value={value}>{children}</RecordContext.Provider>;
|
return <RecordContext.Provider value={value}>{children}</RecordContext.Provider>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const RecordSimpleProvider: React.FC<{ value: Record<string, any>; children: React.ReactNode }> = (props) => {
|
||||||
|
return <RecordContext.Provider {...props} />;
|
||||||
|
};
|
||||||
|
|
||||||
export const RecordIndexProvider: React.FC<{ index: any }> = (props) => {
|
export const RecordIndexProvider: React.FC<{ index: any }> = (props) => {
|
||||||
const { index, children } = props;
|
const { index, children } = props;
|
||||||
return <RecordIndexContext.Provider value={index}>{children}</RecordIndexContext.Provider>;
|
return <RecordIndexContext.Provider value={index}>{children}</RecordIndexContext.Provider>;
|
||||||
|
@ -1,30 +1,34 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { observer, RecursionField, useFieldSchema } from '@formily/react';
|
import { observer, RecursionField, useFieldSchema } from '@formily/react';
|
||||||
import { Space } from 'antd';
|
import { Space } from 'antd';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useSchemaInitializer } from '../../../schema-initializer';
|
import { useSchemaInitializer } from '../../../schema-initializer';
|
||||||
import { DndContext } from '../../common';
|
import { DndContext } from '../../common';
|
||||||
import { useDesignable } from '../../hooks';
|
import { useDesignable, useProps } from '../../hooks';
|
||||||
|
|
||||||
export const ActionBar = observer((props: any) => {
|
export const ActionBar = observer((props: any) => {
|
||||||
const { layout = 'tow-columns', style, ...others } = props;
|
const { layout = 'tow-columns', style, spaceProps, ...others } = useProps(props);
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { render } = useSchemaInitializer(fieldSchema['x-initializer']);
|
const { InitializerComponent } = useSchemaInitializer(fieldSchema['x-initializer']);
|
||||||
const { designable } = useDesignable();
|
const { designable } = useDesignable();
|
||||||
if (layout === 'one-column') {
|
if (layout === 'one-column') {
|
||||||
return (
|
return (
|
||||||
<DndContext>
|
<DndContext>
|
||||||
<div style={{ display: 'flex', ...style }} {...others}>
|
<div
|
||||||
|
style={{ display: 'flex', alignItems: 'center', ...style }}
|
||||||
|
{...others}
|
||||||
|
className={cx(others.className, 'nb-action-bar')}
|
||||||
|
>
|
||||||
{props.children && (
|
{props.children && (
|
||||||
<div style={{ marginRight: 8 }}>
|
<div style={{ marginRight: 8 }}>
|
||||||
<Space>
|
<Space {...spaceProps}>
|
||||||
{fieldSchema.mapProperties((schema, key) => {
|
{fieldSchema.mapProperties((schema, key) => {
|
||||||
return <RecursionField key={key} name={key} schema={schema} />;
|
return <RecursionField key={key} name={key} schema={schema} />;
|
||||||
})}
|
})}
|
||||||
</Space>
|
</Space>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{render()}
|
<InitializerComponent />
|
||||||
</div>
|
</div>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
);
|
);
|
||||||
@ -45,6 +49,7 @@ export const ActionBar = observer((props: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{...others}
|
{...others}
|
||||||
|
className={cx(others.className, 'nb-action-bar')}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={css`
|
className={css`
|
||||||
@ -55,7 +60,7 @@ export const ActionBar = observer((props: any) => {
|
|||||||
style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%' }}
|
style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%' }}
|
||||||
>
|
>
|
||||||
<DndContext>
|
<DndContext>
|
||||||
<Space>
|
<Space {...spaceProps}>
|
||||||
{fieldSchema.mapProperties((schema, key) => {
|
{fieldSchema.mapProperties((schema, key) => {
|
||||||
if (schema['x-align'] !== 'left') {
|
if (schema['x-align'] !== 'left') {
|
||||||
return null;
|
return null;
|
||||||
@ -63,7 +68,7 @@ export const ActionBar = observer((props: any) => {
|
|||||||
return <RecursionField key={key} name={key} schema={schema} />;
|
return <RecursionField key={key} name={key} schema={schema} />;
|
||||||
})}
|
})}
|
||||||
</Space>
|
</Space>
|
||||||
<Space>
|
<Space {...spaceProps}>
|
||||||
{fieldSchema.mapProperties((schema, key) => {
|
{fieldSchema.mapProperties((schema, key) => {
|
||||||
if (schema['x-align'] === 'left') {
|
if (schema['x-align'] === 'left') {
|
||||||
return null;
|
return null;
|
||||||
@ -73,7 +78,7 @@ export const ActionBar = observer((props: any) => {
|
|||||||
</Space>
|
</Space>
|
||||||
</DndContext>
|
</DndContext>
|
||||||
</div>
|
</div>
|
||||||
{render()}
|
<InitializerComponent />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -23,6 +23,7 @@ import { defaultFieldNames } from '../select';
|
|||||||
import { FilterDynamicComponent } from '../table-v2/FilterDynamicComponent';
|
import { FilterDynamicComponent } from '../table-v2/FilterDynamicComponent';
|
||||||
import { ReadPretty } from './ReadPretty';
|
import { ReadPretty } from './ReadPretty';
|
||||||
import useServiceOptions from './useServiceOptions';
|
import useServiceOptions from './useServiceOptions';
|
||||||
|
import { GeneralSchemaItems } from '../../../schema-items';
|
||||||
|
|
||||||
export type AssociationSelectProps<P = any> = RemoteSelectProps<P> & {
|
export type AssociationSelectProps<P = any> = RemoteSelectProps<P> & {
|
||||||
action?: string;
|
action?: string;
|
||||||
@ -161,124 +162,7 @@ AssociationSelect.Designer = function Designer() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<GeneralSchemaDesigner>
|
<GeneralSchemaDesigner>
|
||||||
{collectionField && (
|
<GeneralSchemaItems />
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-field-title"
|
|
||||||
title={t('Edit field title')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit field title'),
|
|
||||||
properties: {
|
|
||||||
title: {
|
|
||||||
title: t('Field title'),
|
|
||||||
default: field?.title,
|
|
||||||
description: `${t('Original field title: ')}${collectionField?.uiSchema?.title}`,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ title }) => {
|
|
||||||
if (title) {
|
|
||||||
field.title = title;
|
|
||||||
fieldSchema.title = title;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
title: fieldSchema.title,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!field.readPretty && (
|
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-description"
|
|
||||||
title={t('Edit description')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit description'),
|
|
||||||
properties: {
|
|
||||||
description: {
|
|
||||||
// title: t('Description'),
|
|
||||||
default: field?.description,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input.TextArea',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ description }) => {
|
|
||||||
field.description = description;
|
|
||||||
fieldSchema.description = description;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
description: fieldSchema.description,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{field.readPretty && (
|
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-tooltip"
|
|
||||||
title={t('Edit tooltip')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit description'),
|
|
||||||
properties: {
|
|
||||||
tooltip: {
|
|
||||||
default: fieldSchema?.['x-decorator-props']?.tooltip,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input.TextArea',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ tooltip }) => {
|
|
||||||
field.decoratorProps.tooltip = tooltip;
|
|
||||||
fieldSchema['x-decorator-props'] = fieldSchema['x-decorator-props'] || {};
|
|
||||||
fieldSchema['x-decorator-props']['tooltip'] = tooltip;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
'x-decorator-props': fieldSchema['x-decorator-props'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!field.readPretty && (
|
|
||||||
<SchemaSettings.SwitchItem
|
|
||||||
key="required"
|
|
||||||
title={t('Required')}
|
|
||||||
checked={fieldSchema.required as boolean}
|
|
||||||
onChange={(required) => {
|
|
||||||
const schema = {
|
|
||||||
['x-uid']: fieldSchema['x-uid'],
|
|
||||||
};
|
|
||||||
field.required = required;
|
|
||||||
fieldSchema['required'] = required;
|
|
||||||
schema['required'] = required;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema,
|
|
||||||
});
|
|
||||||
refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{form && !form?.readPretty && validateSchema && (
|
{form && !form?.readPretty && validateSchema && (
|
||||||
<SchemaSettings.ModalItem
|
<SchemaSettings.ModalItem
|
||||||
title={t('Set validation rules')}
|
title={t('Set validation rules')}
|
||||||
@ -795,105 +679,7 @@ AssociationSelect.FilterDesigner = function FilterDesigner() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<GeneralSchemaDesigner>
|
<GeneralSchemaDesigner>
|
||||||
{collectionField && (
|
<GeneralSchemaItems required={false} />
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-field-title"
|
|
||||||
title={t('Edit field title')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit field title'),
|
|
||||||
properties: {
|
|
||||||
title: {
|
|
||||||
title: t('Field title'),
|
|
||||||
default: field?.title,
|
|
||||||
description: `${t('Original field title: ')}${collectionField?.uiSchema?.title}`,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ title }) => {
|
|
||||||
if (title) {
|
|
||||||
field.title = title;
|
|
||||||
fieldSchema.title = title;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
title: fieldSchema.title,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!field.readPretty && (
|
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-description"
|
|
||||||
title={t('Edit description')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit description'),
|
|
||||||
properties: {
|
|
||||||
description: {
|
|
||||||
// title: t('Description'),
|
|
||||||
default: field?.description,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input.TextArea',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ description }) => {
|
|
||||||
field.description = description;
|
|
||||||
fieldSchema.description = description;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
description: fieldSchema.description,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{field.readPretty && (
|
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-tooltip"
|
|
||||||
title={t('Edit tooltip')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit description'),
|
|
||||||
properties: {
|
|
||||||
tooltip: {
|
|
||||||
default: fieldSchema?.['x-decorator-props']?.tooltip,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input.TextArea',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ tooltip }) => {
|
|
||||||
field.decoratorProps.tooltip = tooltip;
|
|
||||||
fieldSchema['x-decorator-props'] = fieldSchema['x-decorator-props'] || {};
|
|
||||||
fieldSchema['x-decorator-props']['tooltip'] = tooltip;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
'x-decorator-props': fieldSchema['x-decorator-props'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{form && !form?.readPretty && validateSchema && (
|
{form && !form?.readPretty && validateSchema && (
|
||||||
<SchemaSettings.ModalItem
|
<SchemaSettings.ModalItem
|
||||||
title={t('Set validation rules')}
|
title={t('Set validation rules')}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { css } from '@emotion/css';
|
import { css, cx } from '@emotion/css';
|
||||||
import { ArrayCollapse, ArrayItems, FormLayout, FormItem as Item } from '@formily/antd';
|
import { ArrayCollapse, ArrayItems, FormLayout, FormItem as Item } from '@formily/antd';
|
||||||
import { Field } from '@formily/core';
|
import { Field } from '@formily/core';
|
||||||
import { ISchema, Schema, observer, useField, useFieldSchema } from '@formily/react';
|
import { ISchema, Schema, observer, useField, useFieldSchema } from '@formily/react';
|
||||||
@ -18,6 +18,7 @@ import {
|
|||||||
useSortFields,
|
useSortFields,
|
||||||
} from '../../../collection-manager';
|
} from '../../../collection-manager';
|
||||||
import { isTitleField } from '../../../collection-manager/Configuration/CollectionFields';
|
import { isTitleField } from '../../../collection-manager/Configuration/CollectionFields';
|
||||||
|
import { GeneralSchemaItems } from '../../../schema-items/GeneralSchemaItems';
|
||||||
import { GeneralSchemaDesigner, SchemaSettings, isPatternDisabled, isShowDefaultValue } from '../../../schema-settings';
|
import { GeneralSchemaDesigner, SchemaSettings, isPatternDisabled, isShowDefaultValue } from '../../../schema-settings';
|
||||||
import { VariableInput } from '../../../schema-settings/VariableInput/VariableInput';
|
import { VariableInput } from '../../../schema-settings/VariableInput/VariableInput';
|
||||||
import { useIsShowMultipleSwitch } from '../../../schema-settings/hooks/useIsShowMultipleSwitch';
|
import { useIsShowMultipleSwitch } from '../../../schema-settings/hooks/useIsShowMultipleSwitch';
|
||||||
@ -70,15 +71,25 @@ export const FormItem: any = observer((props: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
const { showTitle = true } = props;
|
||||||
return (
|
return (
|
||||||
<ACLCollectionFieldProvider>
|
<ACLCollectionFieldProvider>
|
||||||
<BlockItem className={'nb-form-item'}>
|
<BlockItem className={'nb-form-item'}>
|
||||||
<Item
|
<Item
|
||||||
className={`${css`
|
className={cx(
|
||||||
|
css`
|
||||||
& .ant-space {
|
& .ant-space {
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
}
|
}
|
||||||
`}`}
|
`,
|
||||||
|
{
|
||||||
|
[css`
|
||||||
|
& .ant-formily-item-label {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
`]: showTitle === false,
|
||||||
|
},
|
||||||
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
extra={
|
extra={
|
||||||
typeof field.description === 'string' ? (
|
typeof field.description === 'string' ? (
|
||||||
@ -162,124 +173,7 @@ FormItem.Designer = function Designer() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<GeneralSchemaDesigner>
|
<GeneralSchemaDesigner>
|
||||||
{collectionField && (
|
<GeneralSchemaItems />
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-field-title"
|
|
||||||
title={t('Edit field title')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit field title'),
|
|
||||||
properties: {
|
|
||||||
title: {
|
|
||||||
title: t('Field title'),
|
|
||||||
default: field?.title,
|
|
||||||
description: `${t('Original field title: ')}${collectionField?.uiSchema?.title}`,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ title }) => {
|
|
||||||
if (title) {
|
|
||||||
field.title = title;
|
|
||||||
fieldSchema.title = title;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
title: fieldSchema.title,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!field.readPretty && (
|
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-description"
|
|
||||||
title={t('Edit description')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit description'),
|
|
||||||
properties: {
|
|
||||||
description: {
|
|
||||||
// title: t('Description'),
|
|
||||||
default: field?.description,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input.TextArea',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ description }) => {
|
|
||||||
field.description = description;
|
|
||||||
fieldSchema.description = description;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
description: fieldSchema.description,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{field.readPretty && (
|
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-tooltip"
|
|
||||||
title={t('Edit tooltip')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit description'),
|
|
||||||
properties: {
|
|
||||||
tooltip: {
|
|
||||||
default: fieldSchema?.['x-decorator-props']?.tooltip,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input.TextArea',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ tooltip }) => {
|
|
||||||
field.decoratorProps.tooltip = tooltip;
|
|
||||||
fieldSchema['x-decorator-props'] = fieldSchema['x-decorator-props'] || {};
|
|
||||||
fieldSchema['x-decorator-props']['tooltip'] = tooltip;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
'x-decorator-props': fieldSchema['x-decorator-props'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!field.readPretty && fieldSchema['x-component'] !== 'FormField' && (
|
|
||||||
<SchemaSettings.SwitchItem
|
|
||||||
key="required"
|
|
||||||
title={t('Required')}
|
|
||||||
checked={fieldSchema.required as boolean}
|
|
||||||
onChange={(required) => {
|
|
||||||
const schema = {
|
|
||||||
['x-uid']: fieldSchema['x-uid'],
|
|
||||||
};
|
|
||||||
field.required = required;
|
|
||||||
fieldSchema['required'] = required;
|
|
||||||
schema['required'] = required;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema,
|
|
||||||
});
|
|
||||||
refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!form?.readPretty && isFileField ? (
|
{!form?.readPretty && isFileField ? (
|
||||||
<SchemaSettings.SwitchItem
|
<SchemaSettings.SwitchItem
|
||||||
key="quick-upload"
|
key="quick-upload"
|
||||||
|
@ -0,0 +1,80 @@
|
|||||||
|
import { createForm } from '@formily/core';
|
||||||
|
import { FormContext, useField, useForm } from '@formily/react';
|
||||||
|
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { BlockProvider, useBlockRequestContext } from '../../../block-provider';
|
||||||
|
import { FormLayout } from '@formily/antd';
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { useAssociationNames } from '../../../block-provider/hooks';
|
||||||
|
|
||||||
|
export const GridCardBlockContext = createContext<any>({});
|
||||||
|
|
||||||
|
const InternalGridCardBlockProvider = (props) => {
|
||||||
|
const { resource, service } = useBlockRequestContext();
|
||||||
|
const field = useField();
|
||||||
|
const form = useMemo(() => {
|
||||||
|
return createForm({
|
||||||
|
readPretty: true,
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!service?.loading) {
|
||||||
|
form.setValuesIn(field.address.concat('list').toString(), service?.data?.data);
|
||||||
|
}
|
||||||
|
}, [service?.data?.data, service?.loading]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<GridCardBlockContext.Provider
|
||||||
|
value={{
|
||||||
|
service,
|
||||||
|
resource,
|
||||||
|
columnCount: props.columnCount,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormContext.Provider value={form}>
|
||||||
|
<FormLayout layout={'vertical'}>
|
||||||
|
<div
|
||||||
|
className={css`
|
||||||
|
& > .nb-block-item {
|
||||||
|
margin-bottom: var(--nb-spacing);
|
||||||
|
& > .nb-action-bar:has(:first-child:not(:empty)) {
|
||||||
|
padding: var(--nb-spacing);
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
.ant-list-pagination {
|
||||||
|
padding: var(--nb-spacing);
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</div>
|
||||||
|
</FormLayout>
|
||||||
|
</FormContext.Provider>
|
||||||
|
</GridCardBlockContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GridCardBlockProvider = (props) => {
|
||||||
|
const params = { ...props.params };
|
||||||
|
const { collection } = props;
|
||||||
|
const { appends } = useAssociationNames(collection);
|
||||||
|
if (!Object.keys(params).includes('appends')) {
|
||||||
|
params['appends'] = appends;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BlockProvider {...props} params={params}>
|
||||||
|
<InternalGridCardBlockProvider {...props} />
|
||||||
|
</BlockProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGridCardBlockContext = () => {
|
||||||
|
return useContext(GridCardBlockContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGridCardItemProps = () => {
|
||||||
|
return {};
|
||||||
|
};
|
@ -0,0 +1,245 @@
|
|||||||
|
import { useFieldSchema, useField, ISchema } from '@formily/react';
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { ArrayItems } from '@formily/antd';
|
||||||
|
import { Slider } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useCollection, useCollectionFilterOptions, useSortFields } from '../../../collection-manager';
|
||||||
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||||
|
import { useSchemaTemplate } from '../../../schema-templates';
|
||||||
|
import { useDesignable } from '../../hooks';
|
||||||
|
import { removeNullCondition } from '../filter';
|
||||||
|
import { FilterDynamicComponent } from '../table-v2/FilterDynamicComponent';
|
||||||
|
import { SchemaComponentOptions } from '../../core';
|
||||||
|
import { defaultColumnCount, gridSizes, pageSizeOptions, screenSizeMaps, screenSizeTitleMaps } from './options';
|
||||||
|
Slider;
|
||||||
|
|
||||||
|
const columnCountMarks = [1, 2, 3, 4, 6, 8, 12, 24].reduce((obj, cur) => {
|
||||||
|
obj[cur] = cur;
|
||||||
|
return obj;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
export const GridCardDesigner = () => {
|
||||||
|
const { name, title } = useCollection();
|
||||||
|
const template = useSchemaTemplate();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const field = useField();
|
||||||
|
const dataSource = useCollectionFilterOptions(name);
|
||||||
|
const { dn } = useDesignable();
|
||||||
|
const sortFields = useSortFields(name);
|
||||||
|
const defaultFilter = fieldSchema?.['x-decorator-props']?.params?.filter || {};
|
||||||
|
const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || [];
|
||||||
|
const defaultResource = fieldSchema?.['x-decorator-props']?.resource;
|
||||||
|
const columnCount = field.decoratorProps.columnCount || defaultColumnCount;
|
||||||
|
|
||||||
|
const columnCountSchema = useMemo(() => {
|
||||||
|
return {
|
||||||
|
'x-component': 'Slider',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component-props': {
|
||||||
|
min: 1,
|
||||||
|
max: 24,
|
||||||
|
marks: columnCountMarks,
|
||||||
|
tooltip: {
|
||||||
|
formatter: (value) => `${value}${t('Column')}`,
|
||||||
|
},
|
||||||
|
step: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
|
const columnCountProperties = useMemo(() => {
|
||||||
|
return gridSizes.reduce((o, k) => {
|
||||||
|
o[k] = {
|
||||||
|
...columnCountSchema,
|
||||||
|
title: t(screenSizeTitleMaps[k]),
|
||||||
|
description: `${t('Screen size')} ${screenSizeMaps[k]} ${t('pixels')}`,
|
||||||
|
};
|
||||||
|
return o;
|
||||||
|
}, {});
|
||||||
|
}, [columnCountSchema, t]);
|
||||||
|
|
||||||
|
const sort = defaultSort?.map((item: string) => {
|
||||||
|
return item.startsWith('-')
|
||||||
|
? {
|
||||||
|
field: item.substring(1),
|
||||||
|
direction: 'desc',
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
field: item,
|
||||||
|
direction: 'asc',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<GeneralSchemaDesigner template={template} title={title || name}>
|
||||||
|
<SchemaComponentOptions components={{ Slider }}>
|
||||||
|
<SchemaSettings.BlockTitleItem />
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
title={t('Set the count of columns displayed in a row')}
|
||||||
|
initialValues={columnCount}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Set the count of columns displayed in a row'),
|
||||||
|
properties: columnCountProperties,
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={(columnCount) => {
|
||||||
|
_.set(fieldSchema, 'x-decorator-props.columnCount', columnCount);
|
||||||
|
field.decoratorProps.columnCount = columnCount;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
title={t('Set the data scope')}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Set the data scope'),
|
||||||
|
properties: {
|
||||||
|
filter: {
|
||||||
|
default: defaultFilter,
|
||||||
|
// title: '数据范围',
|
||||||
|
enum: dataSource,
|
||||||
|
'x-component': 'Filter',
|
||||||
|
'x-component-props': {
|
||||||
|
dynamicComponent: (props) => FilterDynamicComponent({ ...props }),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ filter }) => {
|
||||||
|
filter = removeNullCondition(filter);
|
||||||
|
_.set(fieldSchema, 'x-decorator-props.params.filter', filter);
|
||||||
|
field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params };
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
title={t('Set default sorting rules')}
|
||||||
|
components={{ ArrayItems }}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Set default sorting rules'),
|
||||||
|
properties: {
|
||||||
|
sort: {
|
||||||
|
type: 'array',
|
||||||
|
default: sort,
|
||||||
|
'x-component': 'ArrayItems',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
space: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Space',
|
||||||
|
properties: {
|
||||||
|
sort: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayItems.SortHandle',
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: 'string',
|
||||||
|
enum: sortFields,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
width: 260,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
direction: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-component-props': {
|
||||||
|
optionType: 'button',
|
||||||
|
},
|
||||||
|
enum: [
|
||||||
|
{
|
||||||
|
label: t('ASC'),
|
||||||
|
value: 'asc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('DESC'),
|
||||||
|
value: 'desc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayItems.Remove',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
add: {
|
||||||
|
type: 'void',
|
||||||
|
title: t('Add sort field'),
|
||||||
|
'x-component': 'ArrayItems.Addition',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ sort }) => {
|
||||||
|
const sortArr = sort.map((item) => {
|
||||||
|
return item.direction === 'desc' ? `-${item.field}` : item.field;
|
||||||
|
});
|
||||||
|
|
||||||
|
_.set(fieldSchema, 'x-decorator-props.params.sort', sortArr);
|
||||||
|
field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params };
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SchemaSettings.SelectItem
|
||||||
|
title={t('Records per page')}
|
||||||
|
value={field.decoratorProps?.params?.pageSize || 20}
|
||||||
|
options={pageSizeOptions.map((v) => ({ value: v }))}
|
||||||
|
onChange={(pageSize) => {
|
||||||
|
_.set(fieldSchema, 'x-decorator-props.params.pageSize', pageSize);
|
||||||
|
field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 };
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SchemaSettings.Template componentName={'GridCard'} collectionName={name} resourceName={defaultResource} />
|
||||||
|
<SchemaSettings.Divider />
|
||||||
|
<SchemaSettings.Remove
|
||||||
|
removeParentsIfNoChildren
|
||||||
|
breakRemoveOn={{
|
||||||
|
'x-component': 'Grid',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
</GeneralSchemaDesigner>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,33 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Card } from 'antd';
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { useField } from '@formily/react';
|
||||||
|
import { ObjectField } from '@formily/core';
|
||||||
|
import { RecordSimpleProvider } from '../../../record-provider';
|
||||||
|
|
||||||
|
const itemCss = css`
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 8px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const GridCardItem = (props) => {
|
||||||
|
const field = useField<ObjectField>();
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
className={css`
|
||||||
|
&,
|
||||||
|
& .ant-card-body {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<div className={itemCss}>
|
||||||
|
<RecordSimpleProvider value={field.value}>{props.children}</RecordSimpleProvider>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,150 @@
|
|||||||
|
import React, { useCallback, useState } from 'react';
|
||||||
|
import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
||||||
|
import { css, cx } from '@emotion/css';
|
||||||
|
import { List as AntdList, PaginationProps, Col } from 'antd';
|
||||||
|
import { useGridCardActionBarProps } from './hooks';
|
||||||
|
import { SortableItem } from '../../common';
|
||||||
|
import { SchemaComponentOptions } from '../../core';
|
||||||
|
import { useDesigner } from '../../hooks';
|
||||||
|
import { GridCardItem } from './GridCard.Item';
|
||||||
|
import { useGridCardBlockContext, useGridCardItemProps, GridCardBlockProvider } from './GridCard.Decorator';
|
||||||
|
import { GridCardDesigner } from './GridCard.Designer';
|
||||||
|
import { ArrayField } from '@formily/core';
|
||||||
|
import { defaultColumnCount, pageSizeOptions } from './options';
|
||||||
|
|
||||||
|
const rowGutter = {
|
||||||
|
md: 16,
|
||||||
|
sm: 8,
|
||||||
|
xs: 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const designerCss = css`
|
||||||
|
width: 100%;
|
||||||
|
&:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .general-schema-designer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: rgba(241, 139, 98, 0.06);
|
||||||
|
border: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: #f18b62;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const InternalGridCard = (props) => {
|
||||||
|
const { service, columnCount = defaultColumnCount } = useGridCardBlockContext();
|
||||||
|
const { run, params } = service;
|
||||||
|
const meta = service?.data?.meta;
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const field = useField<ArrayField>();
|
||||||
|
const Designer = useDesigner();
|
||||||
|
const [schemaMap] = useState(new Map());
|
||||||
|
const getSchema = useCallback(
|
||||||
|
(key) => {
|
||||||
|
if (!schemaMap.has(key)) {
|
||||||
|
schemaMap.set(
|
||||||
|
key,
|
||||||
|
new Schema({
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
[key]: fieldSchema.properties['item'],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return schemaMap.get(key);
|
||||||
|
},
|
||||||
|
[fieldSchema.properties, schemaMap],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onPaginationChange: PaginationProps['onChange'] = useCallback(
|
||||||
|
(page, pageSize) => {
|
||||||
|
run({
|
||||||
|
...params?.[0],
|
||||||
|
page: page,
|
||||||
|
pageSize: pageSize,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[run, params],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SchemaComponentOptions
|
||||||
|
scope={{
|
||||||
|
useGridCardItemProps,
|
||||||
|
useGridCardActionBarProps,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SortableItem className={cx('nb-card-list', designerCss)}>
|
||||||
|
<AntdList
|
||||||
|
pagination={
|
||||||
|
!meta || meta.count <= meta.pageSize
|
||||||
|
? false
|
||||||
|
: {
|
||||||
|
onChange: onPaginationChange,
|
||||||
|
total: meta?.count || 0,
|
||||||
|
pageSize: meta?.pageSize || 10,
|
||||||
|
current: meta?.page || 1,
|
||||||
|
pageSizeOptions,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dataSource={field.value}
|
||||||
|
grid={{
|
||||||
|
...columnCount,
|
||||||
|
sm: columnCount.xs,
|
||||||
|
xl: columnCount.lg,
|
||||||
|
gutter: [rowGutter, rowGutter],
|
||||||
|
}}
|
||||||
|
renderItem={(item, index) => {
|
||||||
|
return (
|
||||||
|
<Col style={{ height: '100%' }}>
|
||||||
|
<RecursionField
|
||||||
|
key={index}
|
||||||
|
basePath={field.address}
|
||||||
|
name={index}
|
||||||
|
onlyRenderProperties
|
||||||
|
schema={getSchema(index)}
|
||||||
|
></RecursionField>
|
||||||
|
</Col>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
loading={service?.loading}
|
||||||
|
/>
|
||||||
|
<Designer />
|
||||||
|
</SortableItem>
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GridCard = InternalGridCard as typeof InternalGridCard & {
|
||||||
|
Item: typeof GridCardItem;
|
||||||
|
Designer: typeof GridCardDesigner;
|
||||||
|
Decorator: typeof GridCardBlockProvider;
|
||||||
|
};
|
||||||
|
|
||||||
|
GridCard.Item = GridCardItem;
|
||||||
|
GridCard.Designer = GridCardDesigner;
|
||||||
|
GridCard.Decorator = GridCardBlockProvider;
|
@ -0,0 +1,12 @@
|
|||||||
|
import { SpaceProps } from 'antd';
|
||||||
|
|
||||||
|
const spaceProps: SpaceProps = {
|
||||||
|
size: ['large', 'small'],
|
||||||
|
wrap: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useGridCardActionBarProps = () => {
|
||||||
|
return {
|
||||||
|
spaceProps,
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './GridCard';
|
@ -0,0 +1,21 @@
|
|||||||
|
export const pageSizeOptions = [12, 24, 60, 96, 120];
|
||||||
|
export const gridSizes = ['xs', 'md', 'lg', 'xxl'];
|
||||||
|
export const screenSizeTitleMaps = {
|
||||||
|
xs: 'Phone device',
|
||||||
|
md: 'Tablet device',
|
||||||
|
lg: 'Desktop device',
|
||||||
|
xxl: 'Large screen device',
|
||||||
|
};
|
||||||
|
export const screenSizeMaps = {
|
||||||
|
xs: '< 768',
|
||||||
|
md: '≥ 768',
|
||||||
|
lg: '≥ 992',
|
||||||
|
xxl: '≥ 1600',
|
||||||
|
};
|
||||||
|
|
||||||
|
export const defaultColumnCount = {
|
||||||
|
xs: 1,
|
||||||
|
md: 2,
|
||||||
|
lg: 3,
|
||||||
|
xxl: 4,
|
||||||
|
};
|
@ -3,7 +3,7 @@ import { css } from '@emotion/css';
|
|||||||
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
import { observer, RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
||||||
import { uid } from '@formily/shared';
|
import { uid } from '@formily/shared';
|
||||||
import cls from 'classnames';
|
import cls from 'classnames';
|
||||||
import React, { createContext, useContext, useEffect, useRef, useState } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { useDesignable, useFormBlockContext, useSchemaInitializer } from '../../../';
|
import { useDesignable, useFormBlockContext, useSchemaInitializer } from '../../../';
|
||||||
import { DndContext } from '../../common/dnd-context';
|
import { DndContext } from '../../common/dnd-context';
|
||||||
|
|
||||||
@ -293,22 +293,26 @@ const wrapColSchema = (schema: Schema) => {
|
|||||||
|
|
||||||
const useRowProperties = () => {
|
const useRowProperties = () => {
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
|
return useMemo(() => {
|
||||||
return fieldSchema.reduceProperties((buf, s) => {
|
return fieldSchema.reduceProperties((buf, s) => {
|
||||||
if (s['x-component'] === 'Grid.Row' && !s['x-hidden']) {
|
if (s['x-component'] === 'Grid.Row' && !s['x-hidden']) {
|
||||||
buf.push(s);
|
buf.push(s);
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}, []);
|
}, []);
|
||||||
|
}, [Object.keys(fieldSchema.properties || {}).join(',')]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const useColProperties = () => {
|
const useColProperties = () => {
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
|
return useMemo(() => {
|
||||||
return fieldSchema.reduceProperties((buf, s) => {
|
return fieldSchema.reduceProperties((buf, s) => {
|
||||||
if (s['x-component'] === 'Grid.Col' && !s['x-hidden']) {
|
if (s['x-component'] === 'Grid.Col' && !s['x-hidden']) {
|
||||||
buf.push(s);
|
buf.push(s);
|
||||||
}
|
}
|
||||||
return buf;
|
return buf;
|
||||||
}, []);
|
}, []);
|
||||||
|
}, [Object.keys(fieldSchema.properties || {}).join(',')]);
|
||||||
};
|
};
|
||||||
|
|
||||||
const DndWrapper = (props) => {
|
const DndWrapper = (props) => {
|
||||||
@ -330,7 +334,7 @@ export const Grid: any = observer((props: any) => {
|
|||||||
const gridRef = useRef(null);
|
const gridRef = useRef(null);
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { render } = useSchemaInitializer(fieldSchema['x-initializer']);
|
const { render, InitializerComponent } = useSchemaInitializer(fieldSchema['x-initializer']);
|
||||||
const addr = field.address.toString();
|
const addr = field.address.toString();
|
||||||
const rows = useRowProperties();
|
const rows = useRowProperties();
|
||||||
const { setPrintContent } = useFormBlockContext();
|
const { setPrintContent } = useFormBlockContext();
|
||||||
@ -338,8 +342,9 @@ export const Grid: any = observer((props: any) => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
gridRef.current && setPrintContent?.(gridRef.current);
|
gridRef.current && setPrintContent?.(gridRef.current);
|
||||||
}, [gridRef.current]);
|
}, [gridRef.current]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<GridContext.Provider value={{ ref: gridRef, fieldSchema, renderSchemaInitializer: render }}>
|
<GridContext.Provider value={{ ref: gridRef, fieldSchema, renderSchemaInitializer: render, InitializerComponent }}>
|
||||||
<div className={'nb-grid'} style={{ position: 'relative' }} ref={gridRef}>
|
<div className={'nb-grid'} style={{ position: 'relative' }} ref={gridRef}>
|
||||||
<DndWrapper dndContext={props.dndContext}>
|
<DndWrapper dndContext={props.dndContext}>
|
||||||
<RowDivider
|
<RowDivider
|
||||||
@ -355,7 +360,7 @@ export const Grid: any = observer((props: any) => {
|
|||||||
/>
|
/>
|
||||||
{rows.map((schema, index) => {
|
{rows.map((schema, index) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={schema.name}>
|
<React.Fragment key={index}>
|
||||||
<RecursionField name={schema.name} schema={schema} />
|
<RecursionField name={schema.name} schema={schema} />
|
||||||
<RowDivider
|
<RowDivider
|
||||||
rows={rows}
|
rows={rows}
|
||||||
@ -372,7 +377,7 @@ export const Grid: any = observer((props: any) => {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</DndWrapper>
|
</DndWrapper>
|
||||||
{render()}
|
<InitializerComponent />
|
||||||
</div>
|
</div>
|
||||||
</GridContext.Provider>
|
</GridContext.Provider>
|
||||||
);
|
);
|
||||||
@ -411,7 +416,7 @@ Grid.Row = observer(() => {
|
|||||||
/>
|
/>
|
||||||
{cols.map((schema, index) => {
|
{cols.map((schema, index) => {
|
||||||
return (
|
return (
|
||||||
<React.Fragment key={schema.name}>
|
<React.Fragment key={index}>
|
||||||
<RecursionField name={schema.name} schema={schema} />
|
<RecursionField name={schema.name} schema={schema} />
|
||||||
<ColDivider
|
<ColDivider
|
||||||
cols={cols}
|
cols={cols}
|
||||||
@ -437,11 +442,16 @@ Grid.Col = observer((props: any) => {
|
|||||||
const { cols = [] } = useContext(GridRowContext);
|
const { cols = [] } = useContext(GridRowContext);
|
||||||
const schema = useFieldSchema();
|
const schema = useFieldSchema();
|
||||||
const field = useField();
|
const field = useField();
|
||||||
|
|
||||||
|
const width = useMemo(() => {
|
||||||
let width = '';
|
let width = '';
|
||||||
if (cols?.length) {
|
if (cols?.length) {
|
||||||
const w = schema?.['x-component-props']?.['width'] || 100 / cols.length;
|
const w = schema?.['x-component-props']?.['width'] || 100 / cols.length;
|
||||||
width = `calc(${w}% - var(--nb-spacing) * ${(cols.length + 1) / cols.length})`;
|
width = `calc(${w}% - var(--nb-spacing) * ${(cols.length + 1) / cols.length})`;
|
||||||
}
|
}
|
||||||
|
return width;
|
||||||
|
}, [cols?.length, schema?.['x-component-props']?.['width']]);
|
||||||
|
|
||||||
const { setNodeRef } = useDroppable({
|
const { setNodeRef } = useDroppable({
|
||||||
id: field.address.toString(),
|
id: field.address.toString(),
|
||||||
data: {
|
data: {
|
||||||
|
@ -19,10 +19,12 @@ export * from './form-v2';
|
|||||||
export * from './g2plot';
|
export * from './g2plot';
|
||||||
export * from './gantt';
|
export * from './gantt';
|
||||||
export * from './grid';
|
export * from './grid';
|
||||||
|
export * from './grid-card';
|
||||||
export * from './icon-picker';
|
export * from './icon-picker';
|
||||||
export * from './input';
|
export * from './input';
|
||||||
export * from './input-number';
|
export * from './input-number';
|
||||||
export * from './kanban';
|
export * from './kanban';
|
||||||
|
export * from './list';
|
||||||
export * from './markdown';
|
export * from './markdown';
|
||||||
export * from './menu';
|
export * from './menu';
|
||||||
export * from './page';
|
export * from './page';
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
import { createForm } from '@formily/core';
|
||||||
|
import { FormContext, useField } from '@formily/react';
|
||||||
|
import React, { createContext, useContext, useEffect, useMemo } from 'react';
|
||||||
|
import { FormLayout } from '@formily/antd';
|
||||||
|
import { useAssociationNames } from '../../../block-provider/hooks';
|
||||||
|
import { BlockProvider, useBlockRequestContext } from '../../../block-provider';
|
||||||
|
|
||||||
|
export const ListBlockContext = createContext<any>({});
|
||||||
|
|
||||||
|
const InternalListBlockProvider = (props) => {
|
||||||
|
const { resource, service } = useBlockRequestContext();
|
||||||
|
|
||||||
|
const field = useField();
|
||||||
|
const form = useMemo(() => {
|
||||||
|
return createForm({
|
||||||
|
readPretty: true,
|
||||||
|
});
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!service?.loading) {
|
||||||
|
form.setValuesIn(field.address.concat('list').toString(), service?.data?.data);
|
||||||
|
}
|
||||||
|
}, [service?.data?.data, service?.loading]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListBlockContext.Provider
|
||||||
|
value={{
|
||||||
|
service,
|
||||||
|
resource,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<FormContext.Provider value={form}>
|
||||||
|
<FormLayout layout={'vertical'}>{props.children}</FormLayout>
|
||||||
|
</FormContext.Provider>
|
||||||
|
</ListBlockContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ListBlockProvider = (props) => {
|
||||||
|
const params = { ...props.params };
|
||||||
|
const { collection } = props;
|
||||||
|
const { appends } = useAssociationNames(collection);
|
||||||
|
if (!Object.keys(params).includes('appends')) {
|
||||||
|
params['appends'] = appends;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BlockProvider {...props} params={params}>
|
||||||
|
<InternalListBlockProvider {...props} />
|
||||||
|
</BlockProvider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useListBlockContext = () => {
|
||||||
|
return useContext(ListBlockContext);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useListItemProps = () => {
|
||||||
|
return {};
|
||||||
|
};
|
@ -0,0 +1,192 @@
|
|||||||
|
import { useFieldSchema, useField, ISchema } from '@formily/react';
|
||||||
|
import React from 'react';
|
||||||
|
import { ArrayItems } from '@formily/antd';
|
||||||
|
import { useListBlockContext } from './List.Decorator';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useCollection, useCollectionFilterOptions, useSortFields } from '../../../collection-manager';
|
||||||
|
import { GeneralSchemaDesigner, SchemaSettings } from '../../../schema-settings';
|
||||||
|
import { useSchemaTemplate } from '../../../schema-templates';
|
||||||
|
import { useDesignable } from '../../hooks';
|
||||||
|
import { removeNullCondition } from '../filter';
|
||||||
|
import { FilterDynamicComponent } from '../table-v2/FilterDynamicComponent';
|
||||||
|
|
||||||
|
export const ListDesigner = () => {
|
||||||
|
const { name, title } = useCollection();
|
||||||
|
const template = useSchemaTemplate();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const field = useField();
|
||||||
|
const dataSource = useCollectionFilterOptions(name);
|
||||||
|
const { service } = useListBlockContext();
|
||||||
|
const { dn } = useDesignable();
|
||||||
|
const sortFields = useSortFields(name);
|
||||||
|
const defaultFilter = fieldSchema?.['x-decorator-props']?.params?.filter || {};
|
||||||
|
const defaultSort = fieldSchema?.['x-decorator-props']?.params?.sort || [];
|
||||||
|
const defaultResource = fieldSchema?.['x-decorator-props']?.resource;
|
||||||
|
const sort = defaultSort?.map((item: string) => {
|
||||||
|
return item.startsWith('-')
|
||||||
|
? {
|
||||||
|
field: item.substring(1),
|
||||||
|
direction: 'desc',
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
field: item,
|
||||||
|
direction: 'asc',
|
||||||
|
};
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<GeneralSchemaDesigner template={template} title={title || name}>
|
||||||
|
<SchemaSettings.BlockTitleItem />
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
title={t('Set the data scope')}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Set the data scope'),
|
||||||
|
properties: {
|
||||||
|
filter: {
|
||||||
|
default: defaultFilter,
|
||||||
|
// title: '数据范围',
|
||||||
|
enum: dataSource,
|
||||||
|
'x-component': 'Filter',
|
||||||
|
'x-component-props': {
|
||||||
|
dynamicComponent: (props) => FilterDynamicComponent({ ...props }),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ filter }) => {
|
||||||
|
filter = removeNullCondition(filter);
|
||||||
|
_.set(fieldSchema, 'x-decorator-props.params.filter', filter);
|
||||||
|
field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 };
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
title={t('Set default sorting rules')}
|
||||||
|
components={{ ArrayItems }}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Set default sorting rules'),
|
||||||
|
properties: {
|
||||||
|
sort: {
|
||||||
|
type: 'array',
|
||||||
|
default: sort,
|
||||||
|
'x-component': 'ArrayItems',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
space: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Space',
|
||||||
|
properties: {
|
||||||
|
sort: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayItems.SortHandle',
|
||||||
|
},
|
||||||
|
field: {
|
||||||
|
type: 'string',
|
||||||
|
enum: sortFields,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Select',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
width: 260,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
direction: {
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-component-props': {
|
||||||
|
optionType: 'button',
|
||||||
|
},
|
||||||
|
enum: [
|
||||||
|
{
|
||||||
|
label: t('ASC'),
|
||||||
|
value: 'asc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('DESC'),
|
||||||
|
value: 'desc',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
remove: {
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'ArrayItems.Remove',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
add: {
|
||||||
|
type: 'void',
|
||||||
|
title: t('Add sort field'),
|
||||||
|
'x-component': 'ArrayItems.Addition',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ sort }) => {
|
||||||
|
const sortArr = sort.map((item) => {
|
||||||
|
return item.direction === 'desc' ? `-${item.field}` : item.field;
|
||||||
|
});
|
||||||
|
|
||||||
|
_.set(fieldSchema, 'x-decorator-props.params.sort', sortArr);
|
||||||
|
field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 };
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SchemaSettings.SelectItem
|
||||||
|
title={t('Records per page')}
|
||||||
|
value={field.decoratorProps?.params?.pageSize || 20}
|
||||||
|
options={[
|
||||||
|
{ label: '10', value: 10 },
|
||||||
|
{ label: '20', value: 20 },
|
||||||
|
{ label: '50', value: 50 },
|
||||||
|
{ label: '80', value: 80 },
|
||||||
|
{ label: '100', value: 100 },
|
||||||
|
]}
|
||||||
|
onChange={(pageSize) => {
|
||||||
|
_.set(fieldSchema, 'x-decorator-props.params.pageSize', pageSize);
|
||||||
|
field.decoratorProps.params = { ...fieldSchema['x-decorator-props'].params, page: 1 };
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<SchemaSettings.Template componentName={'List'} collectionName={name} resourceName={defaultResource} />
|
||||||
|
<SchemaSettings.Divider />
|
||||||
|
<SchemaSettings.Remove
|
||||||
|
removeParentsIfNoChildren
|
||||||
|
breakRemoveOn={{
|
||||||
|
'x-component': 'Grid',
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</GeneralSchemaDesigner>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { css } from '@emotion/css';
|
||||||
|
import { useField } from '@formily/react';
|
||||||
|
import { ObjectField } from '@formily/core';
|
||||||
|
import { RecordSimpleProvider } from '../../../record-provider';
|
||||||
|
|
||||||
|
const itemCss = css`
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
padding: 12px 0;
|
||||||
|
border-bottom: 1px solid #f0f0f0;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const ListItem = (props) => {
|
||||||
|
const field = useField<ObjectField>();
|
||||||
|
return (
|
||||||
|
<div className={itemCss}>
|
||||||
|
<RecordSimpleProvider value={field.value}>{props.children}</RecordSimpleProvider>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
135
packages/core/client/src/schema-component/antd/list/List.tsx
Normal file
135
packages/core/client/src/schema-component/antd/list/List.tsx
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
import { ListDesigner } from './List.Designer';
|
||||||
|
import { ListBlockProvider, useListBlockContext, useListItemProps } from './List.Decorator';
|
||||||
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { RecursionField, Schema, useField, useFieldSchema } from '@formily/react';
|
||||||
|
import { css, cx } from '@emotion/css';
|
||||||
|
import { List as AntdList, PaginationProps } from 'antd';
|
||||||
|
import { useListActionBarProps } from './hooks';
|
||||||
|
import { SortableItem } from '../../common';
|
||||||
|
import { SchemaComponentOptions } from '../../core';
|
||||||
|
import { useDesigner } from '../../hooks';
|
||||||
|
import { ListItem } from './List.Item';
|
||||||
|
import { ArrayField } from '@formily/core';
|
||||||
|
|
||||||
|
const designerCss = css`
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: var(--nb-spacing);
|
||||||
|
&:hover {
|
||||||
|
> .general-schema-designer {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
> .general-schema-designer {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 999;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
display: none;
|
||||||
|
background: rgba(241, 139, 98, 0.06);
|
||||||
|
border: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
> .general-schema-designer-icons {
|
||||||
|
position: absolute;
|
||||||
|
right: 2px;
|
||||||
|
top: 2px;
|
||||||
|
line-height: 16px;
|
||||||
|
pointer-events: all;
|
||||||
|
.ant-space-item {
|
||||||
|
background-color: #f18b62;
|
||||||
|
color: #fff;
|
||||||
|
line-height: 16px;
|
||||||
|
width: 16px;
|
||||||
|
padding-left: 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const InternalList = (props) => {
|
||||||
|
const { service } = useListBlockContext();
|
||||||
|
const { run, params } = service;
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const Designer = useDesigner();
|
||||||
|
const meta = service?.data?.meta;
|
||||||
|
const field = useField<ArrayField>();
|
||||||
|
const [schemaMap] = useState(new Map());
|
||||||
|
const getSchema = useCallback(
|
||||||
|
(key) => {
|
||||||
|
if (!schemaMap.has(key)) {
|
||||||
|
schemaMap.set(
|
||||||
|
key,
|
||||||
|
new Schema({
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
[key]: fieldSchema.properties['item'],
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return schemaMap.get(key);
|
||||||
|
},
|
||||||
|
[fieldSchema.properties, schemaMap],
|
||||||
|
);
|
||||||
|
|
||||||
|
const onPaginationChange: PaginationProps['onChange'] = useCallback(
|
||||||
|
(page, pageSize) => {
|
||||||
|
run({
|
||||||
|
...params?.[0],
|
||||||
|
page: page,
|
||||||
|
pageSize: pageSize,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[run, params],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SchemaComponentOptions
|
||||||
|
scope={{
|
||||||
|
useListItemProps,
|
||||||
|
useListActionBarProps,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<SortableItem className={cx('nb-list', designerCss)}>
|
||||||
|
<AntdList
|
||||||
|
pagination={
|
||||||
|
!meta || meta.count <= meta.pageSize
|
||||||
|
? false
|
||||||
|
: {
|
||||||
|
onChange: onPaginationChange,
|
||||||
|
total: meta?.count || 0,
|
||||||
|
pageSize: meta?.pageSize || 10,
|
||||||
|
current: meta?.page || 1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loading={service?.loading}
|
||||||
|
>
|
||||||
|
{field.value?.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<RecursionField
|
||||||
|
basePath={field.address}
|
||||||
|
key={index}
|
||||||
|
name={index}
|
||||||
|
onlyRenderProperties
|
||||||
|
schema={getSchema(index)}
|
||||||
|
></RecursionField>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</AntdList>
|
||||||
|
<Designer />
|
||||||
|
</SortableItem>
|
||||||
|
</SchemaComponentOptions>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const List = InternalList as typeof InternalList & {
|
||||||
|
Item: typeof ListItem;
|
||||||
|
Designer: typeof ListDesigner;
|
||||||
|
Decorator: typeof ListBlockProvider;
|
||||||
|
};
|
||||||
|
|
||||||
|
List.Item = ListItem;
|
||||||
|
List.Designer = ListDesigner;
|
||||||
|
List.Decorator = ListBlockProvider;
|
12
packages/core/client/src/schema-component/antd/list/hooks.ts
Normal file
12
packages/core/client/src/schema-component/antd/list/hooks.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import { SpaceProps } from 'antd';
|
||||||
|
|
||||||
|
const spaceProps: SpaceProps = {
|
||||||
|
size: ['large', 'small'],
|
||||||
|
wrap: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useListActionBarProps = () => {
|
||||||
|
return {
|
||||||
|
spaceProps,
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export * from './List';
|
@ -1,7 +1,7 @@
|
|||||||
import { useFieldSchema } from '@formily/react';
|
import { useFieldSchema } from '@formily/react';
|
||||||
import { isPlainObj } from '@formily/shared';
|
import { isPlainObj } from '@formily/shared';
|
||||||
import get from 'lodash/get';
|
import get from 'lodash/get';
|
||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';
|
||||||
import { SchemaComponentOptions } from '../schema-component';
|
import { SchemaComponentOptions } from '../schema-component';
|
||||||
import { SchemaInitializer } from './SchemaInitializer';
|
import { SchemaInitializer } from './SchemaInitializer';
|
||||||
import * as globals from './buttons';
|
import * as globals from './buttons';
|
||||||
@ -22,20 +22,32 @@ export const useSchemaInitializer = (name: string, props = {}) => {
|
|||||||
return component && React.createElement(component, props);
|
return component && React.createElement(component, props);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!name) {
|
const initializerPropsRef = useRef({});
|
||||||
return { exists: false, render: (props?: any) => render(null) };
|
const initializer = name ? get(initializers, name || fieldSchema?.['x-initializer']) : null;
|
||||||
}
|
|
||||||
|
|
||||||
const initializer = get(initializers, name || fieldSchema?.['x-initializer']);
|
|
||||||
const initializerProps = { ...props, ...fieldSchema?.['x-initializer-props'] };
|
const initializerProps = { ...props, ...fieldSchema?.['x-initializer-props'] };
|
||||||
|
initializerPropsRef.current = initializerProps;
|
||||||
|
|
||||||
|
const InitializerComponent = useMemo(() => {
|
||||||
|
let C = React.Fragment;
|
||||||
|
if (!initializer) {
|
||||||
|
return C;
|
||||||
|
} else if (isPlainObj(initializer)) {
|
||||||
|
C = (initializer as any).component || SchemaInitializer.Button;
|
||||||
|
return (p) => <C {...initializer} {...initializerPropsRef.current} {...p} />;
|
||||||
|
} else {
|
||||||
|
C = initializer;
|
||||||
|
return (p) => <C {...initializerPropsRef.current} {...p} />;
|
||||||
|
}
|
||||||
|
}, [initializer]);
|
||||||
|
|
||||||
if (!initializer) {
|
if (!initializer) {
|
||||||
return { exists: false, render: (props?: any) => render(null) };
|
return { exists: false, InitializerComponent, render: (props?: any) => render(null) };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPlainObj(initializer)) {
|
if (isPlainObj(initializer)) {
|
||||||
return {
|
return {
|
||||||
exists: true,
|
exists: true,
|
||||||
|
InitializerComponent,
|
||||||
render: (props?: any) => {
|
render: (props?: any) => {
|
||||||
const component = (initializer as any).component || SchemaInitializer.Button;
|
const component = (initializer as any).component || SchemaInitializer.Button;
|
||||||
return render(component, { ...initializer, ...initializerProps, ...props });
|
return render(component, { ...initializer, ...initializerProps, ...props });
|
||||||
@ -45,6 +57,7 @@ export const useSchemaInitializer = (name: string, props = {}) => {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
exists: true,
|
exists: true,
|
||||||
|
InitializerComponent,
|
||||||
render: (props?: any) => render(initializer, { ...initializerProps, ...props }),
|
render: (props?: any) => render(initializer, { ...initializerProps, ...props }),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -18,6 +18,18 @@ export const BlockInitializers = {
|
|||||||
title: '{{t("Table")}}',
|
title: '{{t("Table")}}',
|
||||||
component: 'TableBlockInitializer',
|
component: 'TableBlockInitializer',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'List',
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("List")}}',
|
||||||
|
component: 'ListBlockInitializer',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'GridCard',
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Grid Card")}}',
|
||||||
|
component: 'GridCardBlockInitializer',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'form',
|
key: 'form',
|
||||||
type: 'item',
|
type: 'item',
|
||||||
|
@ -0,0 +1,299 @@
|
|||||||
|
import { useFieldSchema, Schema } from '@formily/react';
|
||||||
|
import { useCollection } from '../../collection-manager';
|
||||||
|
|
||||||
|
// 表单的操作配置
|
||||||
|
export const GridCardActionInitializers = {
|
||||||
|
title: "{{t('Configure actions')}}",
|
||||||
|
icon: 'SettingOutlined',
|
||||||
|
style: {
|
||||||
|
marginLeft: 8,
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: "{{t('Enable actions')}}",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: "{{t('Filter')}}",
|
||||||
|
component: 'FilterActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: "{{t('Add new')}}",
|
||||||
|
component: 'CreateActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-align': 'right',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-acl-action-props': {
|
||||||
|
skipScopeCheck: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
visible: () => {
|
||||||
|
const collection = useCollection();
|
||||||
|
return collection.template !== 'view' && collection.template !== 'file';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: "{{t('Refresh')}}",
|
||||||
|
component: 'RefreshActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-align': 'right',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: "{{t('Import')}}",
|
||||||
|
component: 'ImportActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-align': 'right',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-acl-action-props': {
|
||||||
|
skipScopeCheck: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: "{{t('Export')}}",
|
||||||
|
component: 'ExportActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-align': 'right',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-acl-action-props': {
|
||||||
|
skipScopeCheck: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// type: 'divider',
|
||||||
|
// visible: () => {
|
||||||
|
// const collection = useCollection();
|
||||||
|
// return (collection as any).template !== 'view';
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'subMenu',
|
||||||
|
// title: '{{t("Customize")}}',
|
||||||
|
// children: [
|
||||||
|
// {
|
||||||
|
// type: 'item',
|
||||||
|
// title: '{{t("Bulk update")}}',
|
||||||
|
// component: 'CustomizeActionInitializer',
|
||||||
|
// schema: {
|
||||||
|
// type: 'void',
|
||||||
|
// title: '{{ t("Bulk update") }}',
|
||||||
|
// 'x-component': 'Action',
|
||||||
|
// 'x-align': 'right',
|
||||||
|
// 'x-acl-action': 'update',
|
||||||
|
// 'x-decorator': 'ACLActionProvider',
|
||||||
|
// 'x-acl-action-props': {
|
||||||
|
// skipScopeCheck: true,
|
||||||
|
// },
|
||||||
|
// 'x-action': 'customize:bulkUpdate',
|
||||||
|
// 'x-designer': 'Action.Designer',
|
||||||
|
// 'x-action-settings': {
|
||||||
|
// assignedValues: {},
|
||||||
|
// updateMode: 'selected',
|
||||||
|
// onSuccess: {
|
||||||
|
// manualClose: true,
|
||||||
|
// redirecting: false,
|
||||||
|
// successMessage: '{{t("Updated successfully")}}',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// 'x-component-props': {
|
||||||
|
// icon: 'EditOutlined',
|
||||||
|
// useProps: '{{ useCustomizeBulkUpdateActionProps }}',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'item',
|
||||||
|
// title: '{{t("Bulk edit")}}',
|
||||||
|
// component: 'CustomizeBulkEditActionInitializer',
|
||||||
|
// schema: {
|
||||||
|
// 'x-align': 'right',
|
||||||
|
// 'x-decorator': 'ACLActionProvider',
|
||||||
|
// 'x-acl-action': 'update',
|
||||||
|
// 'x-acl-action-props': {
|
||||||
|
// skipScopeCheck: true,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// visible: () => {
|
||||||
|
// const collection = useCollection();
|
||||||
|
// return (collection as any).template !== 'view';
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const GridCardItemActionInitializers = {
|
||||||
|
title: '{{t("Configure actions")}}',
|
||||||
|
icon: 'SettingOutlined',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: '{{t("Enable actions")}}',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("View")}}',
|
||||||
|
component: 'ViewActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-action': 'view',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Edit")}}',
|
||||||
|
component: 'UpdateActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-action': 'update',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
visible: () => {
|
||||||
|
const collection = useCollection();
|
||||||
|
return (collection as any).template !== 'view';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Delete")}}',
|
||||||
|
component: 'DestroyActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-action': 'destroy',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'subMenu',
|
||||||
|
title: '{{t("Customize")}}',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Popup")}}',
|
||||||
|
component: 'CustomizeActionInitializer',
|
||||||
|
schema: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Popup") }}',
|
||||||
|
'x-action': 'customize:popup',
|
||||||
|
'x-designer': 'Action.Designer',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': {
|
||||||
|
openMode: 'drawer',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Popup") }}',
|
||||||
|
'x-component': 'Action.Container',
|
||||||
|
'x-component-props': {
|
||||||
|
className: 'nb-action-popup',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
tabs: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Tabs',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-initializer': 'TabPaneInitializers',
|
||||||
|
properties: {
|
||||||
|
tab1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{t("Details")}}',
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designer': 'Tabs.Designer',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'RecordBlockInitializers',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Update record")}}',
|
||||||
|
component: 'CustomizeActionInitializer',
|
||||||
|
schema: {
|
||||||
|
title: '{{ t("Update record") }}',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-action': 'customize:update',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-acl-action': 'update',
|
||||||
|
'x-designer': 'Action.Designer',
|
||||||
|
'x-action-settings': {
|
||||||
|
assignedValues: {},
|
||||||
|
onSuccess: {
|
||||||
|
manualClose: true,
|
||||||
|
redirecting: false,
|
||||||
|
successMessage: '{{t("Updated successfully")}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{ useCustomizeUpdateActionProps }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
visible: () => {
|
||||||
|
const collection = useCollection();
|
||||||
|
return (collection as any).template !== 'view';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Custom request")}}',
|
||||||
|
component: 'CustomizeActionInitializer',
|
||||||
|
schema: {
|
||||||
|
title: '{{ t("Custom request") }}',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-action': 'customize:table:request',
|
||||||
|
'x-designer': 'Action.Designer',
|
||||||
|
'x-action-settings': {
|
||||||
|
requestSettings: {},
|
||||||
|
onSuccess: {
|
||||||
|
manualClose: false,
|
||||||
|
redirecting: false,
|
||||||
|
successMessage: '{{t("Request success")}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{ useCustomizeRequestActionProps }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
visible: () => {
|
||||||
|
const collection = useCollection();
|
||||||
|
return (collection as any).template !== 'view';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
@ -0,0 +1,299 @@
|
|||||||
|
import { useFieldSchema, Schema } from '@formily/react';
|
||||||
|
import { useCollection } from '../../collection-manager';
|
||||||
|
|
||||||
|
// 表单的操作配置
|
||||||
|
export const ListActionInitializers = {
|
||||||
|
title: "{{t('Configure actions')}}",
|
||||||
|
icon: 'SettingOutlined',
|
||||||
|
style: {
|
||||||
|
marginLeft: 8,
|
||||||
|
},
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: "{{t('Enable actions')}}",
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: "{{t('Filter')}}",
|
||||||
|
component: 'FilterActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: "{{t('Add new')}}",
|
||||||
|
component: 'CreateActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-align': 'right',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-acl-action-props': {
|
||||||
|
skipScopeCheck: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
visible: () => {
|
||||||
|
const collection = useCollection();
|
||||||
|
return collection.template !== 'view' && collection.template !== 'file';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: "{{t('Refresh')}}",
|
||||||
|
component: 'RefreshActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-align': 'right',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: "{{t('Import')}}",
|
||||||
|
component: 'ImportActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-align': 'right',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-acl-action-props': {
|
||||||
|
skipScopeCheck: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: "{{t('Export')}}",
|
||||||
|
component: 'ExportActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-align': 'right',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-acl-action-props': {
|
||||||
|
skipScopeCheck: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
// {
|
||||||
|
// type: 'divider',
|
||||||
|
// visible: () => {
|
||||||
|
// const collection = useCollection();
|
||||||
|
// return (collection as any).template !== 'view';
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'subMenu',
|
||||||
|
// title: '{{t("Customize")}}',
|
||||||
|
// children: [
|
||||||
|
// {
|
||||||
|
// type: 'item',
|
||||||
|
// title: '{{t("Bulk update")}}',
|
||||||
|
// component: 'CustomizeActionInitializer',
|
||||||
|
// schema: {
|
||||||
|
// type: 'void',
|
||||||
|
// title: '{{ t("Bulk update") }}',
|
||||||
|
// 'x-component': 'Action',
|
||||||
|
// 'x-align': 'right',
|
||||||
|
// 'x-acl-action': 'update',
|
||||||
|
// 'x-decorator': 'ACLActionProvider',
|
||||||
|
// 'x-acl-action-props': {
|
||||||
|
// skipScopeCheck: true,
|
||||||
|
// },
|
||||||
|
// 'x-action': 'customize:bulkUpdate',
|
||||||
|
// 'x-designer': 'Action.Designer',
|
||||||
|
// 'x-action-settings': {
|
||||||
|
// assignedValues: {},
|
||||||
|
// updateMode: 'selected',
|
||||||
|
// onSuccess: {
|
||||||
|
// manualClose: true,
|
||||||
|
// redirecting: false,
|
||||||
|
// successMessage: '{{t("Updated successfully")}}',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// 'x-component-props': {
|
||||||
|
// icon: 'EditOutlined',
|
||||||
|
// useProps: '{{ useCustomizeBulkUpdateActionProps }}',
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// type: 'item',
|
||||||
|
// title: '{{t("Bulk edit")}}',
|
||||||
|
// component: 'CustomizeBulkEditActionInitializer',
|
||||||
|
// schema: {
|
||||||
|
// 'x-align': 'right',
|
||||||
|
// 'x-decorator': 'ACLActionProvider',
|
||||||
|
// 'x-acl-action': 'update',
|
||||||
|
// 'x-acl-action-props': {
|
||||||
|
// skipScopeCheck: true,
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
// ],
|
||||||
|
// visible: () => {
|
||||||
|
// const collection = useCollection();
|
||||||
|
// return (collection as any).template !== 'view';
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ListItemActionInitializers = {
|
||||||
|
title: '{{t("Configure actions")}}',
|
||||||
|
icon: 'SettingOutlined',
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
type: 'itemGroup',
|
||||||
|
title: '{{t("Enable actions")}}',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("View")}}',
|
||||||
|
component: 'ViewActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-action': 'view',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Edit")}}',
|
||||||
|
component: 'UpdateActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-action': 'update',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
visible: () => {
|
||||||
|
const collection = useCollection();
|
||||||
|
return (collection as any).template !== 'view';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Delete")}}',
|
||||||
|
component: 'DestroyActionInitializer',
|
||||||
|
schema: {
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-action': 'destroy',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-align': 'left',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'subMenu',
|
||||||
|
title: '{{t("Customize")}}',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Popup")}}',
|
||||||
|
component: 'CustomizeActionInitializer',
|
||||||
|
schema: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Popup") }}',
|
||||||
|
'x-action': 'customize:popup',
|
||||||
|
'x-designer': 'Action.Designer',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': {
|
||||||
|
openMode: 'drawer',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Popup") }}',
|
||||||
|
'x-component': 'Action.Container',
|
||||||
|
'x-component-props': {
|
||||||
|
className: 'nb-action-popup',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
tabs: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Tabs',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-initializer': 'TabPaneInitializers',
|
||||||
|
properties: {
|
||||||
|
tab1: {
|
||||||
|
type: 'void',
|
||||||
|
title: '{{t("Details")}}',
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designer': 'Tabs.Designer',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'RecordBlockInitializers',
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Update record")}}',
|
||||||
|
component: 'CustomizeActionInitializer',
|
||||||
|
schema: {
|
||||||
|
title: '{{ t("Update record") }}',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-action': 'customize:update',
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-acl-action': 'update',
|
||||||
|
'x-designer': 'Action.Designer',
|
||||||
|
'x-action-settings': {
|
||||||
|
assignedValues: {},
|
||||||
|
onSuccess: {
|
||||||
|
manualClose: true,
|
||||||
|
redirecting: false,
|
||||||
|
successMessage: '{{t("Updated successfully")}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{ useCustomizeUpdateActionProps }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
visible: () => {
|
||||||
|
const collection = useCollection();
|
||||||
|
return (collection as any).template !== 'view';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'item',
|
||||||
|
title: '{{t("Custom request")}}',
|
||||||
|
component: 'CustomizeActionInitializer',
|
||||||
|
schema: {
|
||||||
|
title: '{{ t("Custom request") }}',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-action': 'customize:table:request',
|
||||||
|
'x-designer': 'Action.Designer',
|
||||||
|
'x-action-settings': {
|
||||||
|
requestSettings: {},
|
||||||
|
onSuccess: {
|
||||||
|
manualClose: false,
|
||||||
|
redirecting: false,
|
||||||
|
successMessage: '{{t("Request success")}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{ useCustomizeRequestActionProps }}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
visible: () => {
|
||||||
|
const collection = useCollection();
|
||||||
|
return (collection as any).template !== 'view';
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
@ -21,5 +21,8 @@ export * from './TableColumnInitializers';
|
|||||||
export * from './TableSelectorInitializers';
|
export * from './TableSelectorInitializers';
|
||||||
export * from './TabPaneInitializers';
|
export * from './TabPaneInitializers';
|
||||||
export * from './GanttActionInitializers';
|
export * from './GanttActionInitializers';
|
||||||
|
export * from './DetailsActionInitializers';
|
||||||
|
export * from './ListActionInitializers';
|
||||||
|
export * from './GridCardActionInitializers';
|
||||||
// association filter
|
// association filter
|
||||||
export * from '../../schema-component/antd/association-filter/AssociationFilter';
|
export * from '../../schema-component/antd/association-filter/AssociationFilter';
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { OrderedListOutlined } from '@ant-design/icons';
|
||||||
|
import { createGridCardBlockSchema, createListBlockSchema } from '../utils';
|
||||||
|
import { DataBlockInitializer } from './DataBlockInitializer';
|
||||||
|
import { useCollectionManager } from '../../collection-manager';
|
||||||
|
|
||||||
|
export const GridCardBlockInitializer = (props) => {
|
||||||
|
const { insert } = props;
|
||||||
|
const { getCollection } = useCollectionManager();
|
||||||
|
return (
|
||||||
|
<DataBlockInitializer
|
||||||
|
{...props}
|
||||||
|
icon={<OrderedListOutlined />}
|
||||||
|
componentType={'GridCard'}
|
||||||
|
onCreateBlockSchema={async ({ item }) => {
|
||||||
|
const collection = getCollection(item.name);
|
||||||
|
const schema = createGridCardBlockSchema({
|
||||||
|
collection: item.name,
|
||||||
|
rowKey: collection.filterTargetKey || 'id',
|
||||||
|
});
|
||||||
|
insert(schema);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -3,6 +3,8 @@ import React from 'react';
|
|||||||
|
|
||||||
import { SchemaInitializer } from '..';
|
import { SchemaInitializer } from '..';
|
||||||
import { useCurrentSchema } from '../utils';
|
import { useCurrentSchema } from '../utils';
|
||||||
|
import { useBlockRequestContext } from '../../block-provider';
|
||||||
|
import { useCollection } from '../../collection-manager';
|
||||||
|
|
||||||
export const InitializerWithSwitch = (props) => {
|
export const InitializerWithSwitch = (props) => {
|
||||||
const { type, schema, item, insert, remove: passInRemove } = props;
|
const { type, schema, item, insert, remove: passInRemove } = props;
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { OrderedListOutlined } from '@ant-design/icons';
|
||||||
|
import { createListBlockSchema } from '../utils';
|
||||||
|
import { DataBlockInitializer } from './DataBlockInitializer';
|
||||||
|
import { useCollectionManager } from '../../collection-manager';
|
||||||
|
|
||||||
|
export const ListBlockInitializer = (props) => {
|
||||||
|
const { insert } = props;
|
||||||
|
const { getCollection } = useCollectionManager();
|
||||||
|
return (
|
||||||
|
<DataBlockInitializer
|
||||||
|
{...props}
|
||||||
|
icon={<OrderedListOutlined />}
|
||||||
|
componentType={'List'}
|
||||||
|
onCreateBlockSchema={async ({ item }) => {
|
||||||
|
const collection = getCollection(item.name);
|
||||||
|
const schema = createListBlockSchema({
|
||||||
|
collection: item.name,
|
||||||
|
rowKey: collection.filterTargetKey || 'id',
|
||||||
|
});
|
||||||
|
insert(schema);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -29,8 +29,10 @@ export * from './FilterFormBlockInitializer';
|
|||||||
export * from './FormBlockInitializer';
|
export * from './FormBlockInitializer';
|
||||||
export * from './G2PlotInitializer';
|
export * from './G2PlotInitializer';
|
||||||
export * from './GanttBlockInitializer';
|
export * from './GanttBlockInitializer';
|
||||||
|
export * from './GridCardBlockInitializer';
|
||||||
export * from './InitializerWithSwitch';
|
export * from './InitializerWithSwitch';
|
||||||
export * from './KanbanBlockInitializer';
|
export * from './KanbanBlockInitializer';
|
||||||
|
export * from './ListBlockInitializer';
|
||||||
export * from './MarkdownBlockInitializer';
|
export * from './MarkdownBlockInitializer';
|
||||||
export * from './PrintActionInitializer';
|
export * from './PrintActionInitializer';
|
||||||
export * from './RecordAssociationBlockInitializer';
|
export * from './RecordAssociationBlockInitializer';
|
||||||
@ -41,6 +43,7 @@ export * from './RecordFormBlockInitializer';
|
|||||||
export * from './RecordReadPrettyAssociationFormBlockInitializer';
|
export * from './RecordReadPrettyAssociationFormBlockInitializer';
|
||||||
export * from './RecordReadPrettyFormBlockInitializer';
|
export * from './RecordReadPrettyFormBlockInitializer';
|
||||||
export * from './RefreshActionInitializer';
|
export * from './RefreshActionInitializer';
|
||||||
|
export * from './SelectActionInitializer';
|
||||||
export * from './SubmitActionInitializer';
|
export * from './SubmitActionInitializer';
|
||||||
export * from './TableActionColumnInitializer';
|
export * from './TableActionColumnInitializer';
|
||||||
export * from './TableBlockInitializer';
|
export * from './TableBlockInitializer';
|
||||||
@ -49,4 +52,3 @@ export * from './TableSelectorInitializer';
|
|||||||
export * from './UpdateActionInitializer';
|
export * from './UpdateActionInitializer';
|
||||||
export * from './UpdateSubmitActionInitializer';
|
export * from './UpdateSubmitActionInitializer';
|
||||||
export * from './ViewActionInitializer';
|
export * from './ViewActionInitializer';
|
||||||
export * from './SelectActionInitializer';
|
|
||||||
|
@ -950,6 +950,177 @@ export const createDetailsBlockSchema = (options) => {
|
|||||||
return schema;
|
return schema;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const createListBlockSchema = (options) => {
|
||||||
|
const {
|
||||||
|
formItemInitializers = 'ReadPrettyFormItemInitializers',
|
||||||
|
actionInitializers = 'ListActionInitializers',
|
||||||
|
itemActionInitializers = 'ListItemActionInitializers',
|
||||||
|
collection,
|
||||||
|
association,
|
||||||
|
resource,
|
||||||
|
template,
|
||||||
|
...others
|
||||||
|
} = options;
|
||||||
|
const resourceName = resource || association || collection;
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'void',
|
||||||
|
'x-acl-action': `${resourceName}:view`,
|
||||||
|
'x-decorator': 'List.Decorator',
|
||||||
|
'x-decorator-props': {
|
||||||
|
resource: resourceName,
|
||||||
|
collection,
|
||||||
|
association,
|
||||||
|
readPretty: true,
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
pageSize: 10,
|
||||||
|
},
|
||||||
|
runWhenParamsChanged: true,
|
||||||
|
...others,
|
||||||
|
},
|
||||||
|
'x-component': 'CardItem',
|
||||||
|
'x-designer': 'List.Designer',
|
||||||
|
properties: {
|
||||||
|
actionBar: {
|
||||||
|
type: 'void',
|
||||||
|
'x-initializer': actionInitializers,
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
marginBottom: 'var(--nb-spacing)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'List',
|
||||||
|
'x-component-props': {
|
||||||
|
props: '{{ useListBlockProps }}',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
item: {
|
||||||
|
type: 'object',
|
||||||
|
'x-component': 'List.Item',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{ useListItemProps }}',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
grid: template || {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': formItemInitializers,
|
||||||
|
'x-initializer-props': {
|
||||||
|
useProps: '{{ useListItemInitializerProps }}',
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
actionBar: {
|
||||||
|
type: 'void',
|
||||||
|
'x-align': 'left',
|
||||||
|
'x-initializer': itemActionInitializers,
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{ useListActionBarProps }}',
|
||||||
|
layout: 'one-column',
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return schema;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createGridCardBlockSchema = (options) => {
|
||||||
|
const {
|
||||||
|
formItemInitializers = 'ReadPrettyFormItemInitializers',
|
||||||
|
actionInitializers = 'GridCardActionInitializers',
|
||||||
|
itemActionInitializers = 'GridCardItemActionInitializers',
|
||||||
|
collection,
|
||||||
|
association,
|
||||||
|
resource,
|
||||||
|
template,
|
||||||
|
...others
|
||||||
|
} = options;
|
||||||
|
const resourceName = resource || association || collection;
|
||||||
|
const schema: ISchema = {
|
||||||
|
type: 'void',
|
||||||
|
'x-acl-action': `${resourceName}:view`,
|
||||||
|
'x-decorator': 'GridCard.Decorator',
|
||||||
|
'x-decorator-props': {
|
||||||
|
resource: resourceName,
|
||||||
|
collection,
|
||||||
|
association,
|
||||||
|
readPretty: true,
|
||||||
|
action: 'list',
|
||||||
|
params: {
|
||||||
|
pageSize: 12,
|
||||||
|
},
|
||||||
|
runWhenParamsChanged: true,
|
||||||
|
...others,
|
||||||
|
},
|
||||||
|
'x-component': 'BlockItem',
|
||||||
|
'x-designer': 'GridCard.Designer',
|
||||||
|
properties: {
|
||||||
|
actionBar: {
|
||||||
|
type: 'void',
|
||||||
|
'x-initializer': actionInitializers,
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
style: {
|
||||||
|
marginBottom: 'var(--nb-spacing)',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
list: {
|
||||||
|
type: 'array',
|
||||||
|
'x-component': 'GridCard',
|
||||||
|
'x-component-props': {
|
||||||
|
props: '{{ useGridCardBlockProps }}',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
item: {
|
||||||
|
type: 'object',
|
||||||
|
'x-component': 'GridCard.Item',
|
||||||
|
'x-read-pretty': true,
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{ useGridCardItemProps }}',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
grid: template || {
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': formItemInitializers,
|
||||||
|
'x-initializer-props': {
|
||||||
|
useProps: '{{ useGridCardItemInitializerProps }}',
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
actionBar: {
|
||||||
|
type: 'void',
|
||||||
|
'x-align': 'left',
|
||||||
|
'x-initializer': itemActionInitializers,
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
useProps: '{{ useGridCardActionBarProps }}',
|
||||||
|
layout: 'one-column',
|
||||||
|
},
|
||||||
|
properties: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
return schema;
|
||||||
|
};
|
||||||
export const createFormBlockSchema = (options) => {
|
export const createFormBlockSchema = (options) => {
|
||||||
const {
|
const {
|
||||||
formItemInitializers = 'FormItemInitializers',
|
formItemInitializers = 'FormItemInitializers',
|
||||||
@ -1177,7 +1348,7 @@ export const createTableBlockSchema = (options) => {
|
|||||||
'x-component': 'ActionBar',
|
'x-component': 'ActionBar',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
style: {
|
style: {
|
||||||
marginBottom: 16,
|
marginBottom: 'var(--nb-spacing)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: {},
|
properties: {},
|
||||||
@ -1276,7 +1447,7 @@ export const createTableSelectorSchema = (options) => {
|
|||||||
'x-component': 'ActionBar',
|
'x-component': 'ActionBar',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
style: {
|
style: {
|
||||||
marginBottom: 16,
|
marginBottom: 'var(--nb-spacing)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: {},
|
properties: {},
|
||||||
@ -1546,7 +1717,7 @@ export const createKanbanBlockSchema = (options) => {
|
|||||||
'x-component': 'ActionBar',
|
'x-component': 'ActionBar',
|
||||||
'x-component-props': {
|
'x-component-props': {
|
||||||
style: {
|
style: {
|
||||||
marginBottom: 16,
|
marginBottom: 'var(--nb-spacing)',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
properties: {},
|
properties: {},
|
||||||
|
161
packages/core/client/src/schema-items/GeneralSchemaItems.tsx
Normal file
161
packages/core/client/src/schema-items/GeneralSchemaItems.tsx
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
import { Field } from '@formily/core';
|
||||||
|
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import React from 'react';
|
||||||
|
import { useCollectionManager, useCollection } from '../collection-manager';
|
||||||
|
import { useDesignable } from '../schema-component';
|
||||||
|
import { SchemaSettings } from '../schema-settings';
|
||||||
|
|
||||||
|
export const GeneralSchemaItems: React.FC<{
|
||||||
|
required?: boolean;
|
||||||
|
}> = (props) => {
|
||||||
|
const { required = true } = props;
|
||||||
|
const { getCollectionJoinField } = useCollectionManager();
|
||||||
|
const { getField } = useCollection();
|
||||||
|
const field = useField<Field>();
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { dn, refresh } = useDesignable();
|
||||||
|
const collectionField = getField(fieldSchema['name']) || getCollectionJoinField(fieldSchema['x-collection-field']);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{collectionField && (
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
key="edit-field-title"
|
||||||
|
title={t('Edit field title')}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Edit field title'),
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
title: t('Field title'),
|
||||||
|
default: field?.title,
|
||||||
|
description: `${t('Original field title: ')}${collectionField?.uiSchema?.title}`,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input',
|
||||||
|
'x-component-props': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ title }) => {
|
||||||
|
if (title) {
|
||||||
|
field.title = title;
|
||||||
|
fieldSchema.title = title;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
'x-uid': fieldSchema['x-uid'],
|
||||||
|
title: fieldSchema.title,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<SchemaSettings.SwitchItem
|
||||||
|
checked={field.decoratorProps.showTitle ?? true}
|
||||||
|
title={t('Display title')}
|
||||||
|
onChange={(checked) => {
|
||||||
|
field.decoratorProps.showTitle = checked;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
'x-uid': fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': {
|
||||||
|
...fieldSchema['x-decorator-props'],
|
||||||
|
showTitle: checked,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
></SchemaSettings.SwitchItem>
|
||||||
|
{!field.readPretty && (
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
key="edit-description"
|
||||||
|
title={t('Edit description')}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Edit description'),
|
||||||
|
properties: {
|
||||||
|
description: {
|
||||||
|
// title: t('Description'),
|
||||||
|
default: field?.description,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input.TextArea',
|
||||||
|
'x-component-props': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ description }) => {
|
||||||
|
field.description = description;
|
||||||
|
fieldSchema.description = description;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
'x-uid': fieldSchema['x-uid'],
|
||||||
|
description: fieldSchema.description,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{field.readPretty && (
|
||||||
|
<SchemaSettings.ModalItem
|
||||||
|
key="edit-tooltip"
|
||||||
|
title={t('Edit tooltip')}
|
||||||
|
schema={
|
||||||
|
{
|
||||||
|
type: 'object',
|
||||||
|
title: t('Edit description'),
|
||||||
|
properties: {
|
||||||
|
tooltip: {
|
||||||
|
default: fieldSchema?.['x-decorator-props']?.tooltip,
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Input.TextArea',
|
||||||
|
'x-component-props': {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ISchema
|
||||||
|
}
|
||||||
|
onSubmit={({ tooltip }) => {
|
||||||
|
field.decoratorProps.tooltip = tooltip;
|
||||||
|
fieldSchema['x-decorator-props'] = fieldSchema['x-decorator-props'] || {};
|
||||||
|
fieldSchema['x-decorator-props']['tooltip'] = tooltip;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema: {
|
||||||
|
'x-uid': fieldSchema['x-uid'],
|
||||||
|
'x-decorator-props': fieldSchema['x-decorator-props'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
dn.refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!field.readPretty && fieldSchema['x-component'] !== 'FormField' && required && (
|
||||||
|
<SchemaSettings.SwitchItem
|
||||||
|
key="required"
|
||||||
|
title={t('Required')}
|
||||||
|
checked={fieldSchema.required as boolean}
|
||||||
|
onChange={(required) => {
|
||||||
|
const schema = {
|
||||||
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
};
|
||||||
|
field.required = required;
|
||||||
|
fieldSchema['required'] = required;
|
||||||
|
schema['required'] = required;
|
||||||
|
dn.emit('patch', {
|
||||||
|
schema,
|
||||||
|
});
|
||||||
|
refresh();
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -1 +1,2 @@
|
|||||||
export * from './OpenModeSchemaItems';
|
export * from './OpenModeSchemaItems';
|
||||||
|
export * from './GeneralSchemaItems';
|
||||||
|
@ -3,7 +3,7 @@ import { css } from '@emotion/css';
|
|||||||
import { useField, useFieldSchema } from '@formily/react';
|
import { useField, useFieldSchema } from '@formily/react';
|
||||||
import { Space } from 'antd';
|
import { Space } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { DragHandler, useCompile, useDesignable, useGridContext, useGridRowContext } from '../schema-component';
|
import { DragHandler, useCompile, useDesignable, useGridContext, useGridRowContext } from '../schema-component';
|
||||||
import { gridRowColWrap } from '../schema-initializer/utils';
|
import { gridRowColWrap } from '../schema-initializer/utils';
|
||||||
@ -43,14 +43,24 @@ export const GeneralSchemaDesigner = (props: any) => {
|
|||||||
field,
|
field,
|
||||||
fieldSchema,
|
fieldSchema,
|
||||||
};
|
};
|
||||||
if (!designable) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const rowCtx = useGridRowContext();
|
const rowCtx = useGridRowContext();
|
||||||
const ctx = useGridContext();
|
const ctx = useGridContext();
|
||||||
const templateName = ['FormItem', 'ReadPrettyFormItem'].includes(template?.componentName)
|
const templateName = ['FormItem', 'ReadPrettyFormItem'].includes(template?.componentName)
|
||||||
? `${template?.name} ${t('(Fields only)')}`
|
? `${template?.name} ${t('(Fields only)')}`
|
||||||
: template?.name;
|
: template?.name;
|
||||||
|
const initializerProps = useMemo(() => {
|
||||||
|
return {
|
||||||
|
insertPosition: 'afterEnd',
|
||||||
|
wrap: rowCtx?.cols?.length > 1 ? undefined : gridRowColWrap,
|
||||||
|
component: <PlusOutlined style={{ cursor: 'pointer', fontSize: 14 }} />,
|
||||||
|
};
|
||||||
|
}, [rowCtx?.cols?.length]);
|
||||||
|
|
||||||
|
if (!designable) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'general-schema-designer'}>
|
<div className={'general-schema-designer'}>
|
||||||
{title && (
|
{title && (
|
||||||
@ -73,11 +83,11 @@ export const GeneralSchemaDesigner = (props: any) => {
|
|||||||
</DragHandler>
|
</DragHandler>
|
||||||
)}
|
)}
|
||||||
{!disableInitializer &&
|
{!disableInitializer &&
|
||||||
ctx?.renderSchemaInitializer?.({
|
(ctx?.InitializerComponent ? (
|
||||||
insertPosition: 'afterEnd',
|
<ctx.InitializerComponent {...initializerProps} />
|
||||||
wrap: rowCtx?.cols?.length > 1 ? undefined : gridRowColWrap,
|
) : (
|
||||||
component: <PlusOutlined style={{ cursor: 'pointer', fontSize: 14 }} />,
|
ctx?.renderSchemaInitializer?.(initializerProps)
|
||||||
})}
|
))}
|
||||||
<SchemaSettings title={<MenuOutlined style={{ cursor: 'pointer', fontSize: 12 }} />} {...schemaSettingsProps}>
|
<SchemaSettings title={<MenuOutlined style={{ cursor: 'pointer', fontSize: 12 }} />} {...schemaSettingsProps}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</SchemaSettings>
|
</SchemaSettings>
|
||||||
|
@ -2,6 +2,7 @@ import { Field } from '@formily/core';
|
|||||||
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
||||||
import {
|
import {
|
||||||
GeneralSchemaDesigner,
|
GeneralSchemaDesigner,
|
||||||
|
GeneralSchemaItems,
|
||||||
SchemaSettings,
|
SchemaSettings,
|
||||||
isPatternDisabled,
|
isPatternDisabled,
|
||||||
useCollection,
|
useCollection,
|
||||||
@ -40,122 +41,7 @@ const Designer = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<GeneralSchemaDesigner>
|
<GeneralSchemaDesigner>
|
||||||
<SchemaSettings.ModalItem
|
<GeneralSchemaItems />
|
||||||
key="edit-field-title"
|
|
||||||
title={t('Edit field title')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit field title'),
|
|
||||||
properties: {
|
|
||||||
title: {
|
|
||||||
title: t('Field title'),
|
|
||||||
default: field?.title,
|
|
||||||
description: `${t('Original field title: ')}${collectionField?.uiSchema?.title}`,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ title }) => {
|
|
||||||
if (title) {
|
|
||||||
field.title = title;
|
|
||||||
fieldSchema.title = title;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
title: fieldSchema.title,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{!field.readPretty && (
|
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-description"
|
|
||||||
title={t('Edit description')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit description'),
|
|
||||||
properties: {
|
|
||||||
description: {
|
|
||||||
// title: t('Description'),
|
|
||||||
default: field?.description,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input.TextArea',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ description }) => {
|
|
||||||
field.description = description;
|
|
||||||
fieldSchema.description = description;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
description: fieldSchema.description,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{field.readPretty && (
|
|
||||||
<SchemaSettings.ModalItem
|
|
||||||
key="edit-tooltip"
|
|
||||||
title={t('Edit tooltip')}
|
|
||||||
schema={
|
|
||||||
{
|
|
||||||
type: 'object',
|
|
||||||
title: t('Edit description'),
|
|
||||||
properties: {
|
|
||||||
tooltip: {
|
|
||||||
default: fieldSchema?.['x-decorator-props']?.tooltip,
|
|
||||||
'x-decorator': 'FormItem',
|
|
||||||
'x-component': 'Input.TextArea',
|
|
||||||
'x-component-props': {},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
} as ISchema
|
|
||||||
}
|
|
||||||
onSubmit={({ tooltip }) => {
|
|
||||||
field.decoratorProps.tooltip = tooltip;
|
|
||||||
fieldSchema['x-decorator-props'] = fieldSchema['x-decorator-props'] || {};
|
|
||||||
fieldSchema['x-decorator-props']['tooltip'] = tooltip;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema: {
|
|
||||||
'x-uid': fieldSchema['x-uid'],
|
|
||||||
'x-decorator-props': fieldSchema['x-decorator-props'],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
dn.refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{!field.readPretty && (
|
|
||||||
<SchemaSettings.SwitchItem
|
|
||||||
key="required"
|
|
||||||
title={t('Required')}
|
|
||||||
checked={fieldSchema.required as boolean}
|
|
||||||
onChange={(required) => {
|
|
||||||
const schema = {
|
|
||||||
['x-uid']: fieldSchema['x-uid'],
|
|
||||||
};
|
|
||||||
field.required = required;
|
|
||||||
fieldSchema['required'] = required;
|
|
||||||
schema['required'] = required;
|
|
||||||
dn.emit('patch', {
|
|
||||||
schema,
|
|
||||||
});
|
|
||||||
refresh();
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{form && !form?.readPretty && !isPatternDisabled(fieldSchema) && (
|
{form && !form?.readPretty && !isPatternDisabled(fieldSchema) && (
|
||||||
<SchemaSettings.SelectItem
|
<SchemaSettings.SelectItem
|
||||||
key="pattern"
|
key="pattern"
|
||||||
|
Loading…
Reference in New Issue
Block a user