feat: support add group item in detail & form block (#5498)

* feat: support add group item in detail & form block

* feat: support add group item in detail & form block

* refactor: locale

* refactor: orientationMargin

* fix: test

* fix: test

* refactor: locale impeove
This commit is contained in:
Katherine 2024-10-24 20:13:22 +08:00 committed by GitHub
parent 14ca792ff0
commit 8d83c13fe7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 325 additions and 18 deletions

View File

@ -363,7 +363,7 @@
"is empty": "为空",
"is not empty": "不为空",
"Edit chart": "编辑图表",
"Add text": "添加文本",
"Add Markdown": "添加 Markdown",
"Filterable fields": "可筛选字段",
"Edit button": "编辑按钮",
"Hide": "隐藏",
@ -1007,8 +1007,15 @@
"Stay on the current popup or page": "停留在当前弹窗或页面",
"Return to the previous popup or page": "返回上一层弹窗或页面",
"Action after successful submission": "提交成功后动作",
"Allow disassociation":"允许解除已有数据关联",
"Allow disassociation": "允许解除已有数据关联",
"Layout": "布局",
"Vertical": "垂直",
"Horizontal": "水平"
"Horizontal": "水平",
"Edit group title": "编辑分组标题",
"Title position": "标题位置",
"Dashed": "虚线",
"Left": "左",
"Center": "居中",
"Right": "右",
"Divider line color": "分割线颜色"
}

View File

@ -97,9 +97,9 @@ test.describe('configure fields', () => {
page.getByLabel('block-item-CollectionField-general-details-general.manyToOne.nickname'),
).not.toBeVisible();
// add text
// add markdown
await formItemInitializer.hover();
await page.getByRole('menuitem', { name: 'Add text' }).click();
await page.getByRole('menuitem', { name: 'Add Markdown' }).click();
await expect(page.getByLabel('block-item-Markdown.Void-general-details')).toBeVisible();
});
});

View File

@ -79,7 +79,7 @@ const commonOptions = {
},
{
name: 'addText',
title: '{{t("Add text")}}',
title: '{{t("Add Markdown")}}',
Component: 'BlockItemInitializer',
schema: {
type: 'void',
@ -97,6 +97,21 @@ const commonOptions = {
},
},
},
{
name: 'addDivider',
title: '{{t("Add group")}}',
Component: 'BlockItemInitializer',
schema: {
type: 'void',
'x-decorator': 'FormItem',
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'blockSettings:divider',
'x-component': 'Divider',
'x-component-props': {
children: '{{t("Group")}}',
},
},
},
],
};

View File

@ -87,9 +87,9 @@ test.describe('configure fields', () => {
page.getByLabel('block-item-CollectionField-general-form-general.manyToOne.nickname'),
).not.toBeVisible();
// add text
// add markdown
await page.getByLabel('schema-initializer-Grid-form:configureFields-general').hover();
await page.getByRole('menuitem', { name: 'Text' }).click();
await page.getByRole('menuitem', { name: 'Add Markdown' }).click();
await expect(page.getByLabel('block-item-Markdown.Void-general-form')).toBeVisible();
});

View File

@ -36,9 +36,14 @@ const commonOptions = {
},
{
name: 'addText',
title: '{{t("Add text")}}',
title: '{{t("Add Markdown")}}',
Component: 'MarkdownFormItemInitializer',
},
{
name: 'addDivider',
title: '{{t("Add group")}}',
Component: 'DividerFormItemInitializer',
},
],
};

View File

@ -182,11 +182,11 @@ test.describe('configure fields', () => {
page.getByLabel('block-item-CollectionField-general-grid-card-general.manyToOne.nickname').first(),
).not.toBeVisible();
// add text
// add markdown
await formItemInitializer.hover();
await page.getByRole('menuitem', { name: 'ID', exact: true }).hover();
await page.mouse.wheel(0, 300);
await page.getByRole('menuitem', { name: 'Add text' }).click();
await page.getByRole('menuitem', { name: 'Add Markdown' }).click();
await expect(page.getByLabel('block-item-Markdown.Void-general-grid-card').first()).toBeVisible();
});

View File

@ -180,9 +180,9 @@ test.describe('configure fields', () => {
page.getByLabel('block-item-CollectionField-general-list-general.manyToOne.nickname').first(),
).not.toBeVisible();
// add text
// add markdown
await formItemInitializer.hover();
await page.getByRole('menuitem', { name: 'Add text' }).click();
await page.getByRole('menuitem', { name: 'Add Markdown' }).click();
await expect(page.getByLabel('block-item-Markdown.Void-general-list').first()).toBeVisible();
});
});

View File

@ -75,9 +75,9 @@ test.describe('configure fields', () => {
page.getByLabel('block-item-CollectionField-general-filter-form-general.manyToOne.nickname'),
).not.toBeVisible();
// add text
// add markdown
await formItemInitializer.hover();
await page.getByRole('menuitem', { name: 'Add text' }).click();
await page.getByRole('menuitem', { name: 'Add Markdown' }).click();
await expect(page.getByLabel('block-item-Markdown.Void-general-filter-form')).toBeVisible();
});

View File

@ -38,7 +38,7 @@ const commonOptions = {
type: 'divider',
},
{
title: '{{t("Add text")}}',
title: '{{t("Add Markdown")}}',
Component: 'MarkdownFormItemInitializer',
name: 'addText',
},

View File

@ -0,0 +1,35 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { LineOutlined } from '@ant-design/icons';
import React from 'react';
import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
export const DividerFormItemInitializer = () => {
const { insert } = useSchemaInitializer();
const itemConfig = useSchemaInitializerItem();
return (
<SchemaInitializerItem
{...itemConfig}
icon={<LineOutlined />}
onClick={() => {
insert({
type: 'void',
'x-decorator': 'FormItem',
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'blockSettings:divider',
'x-component': 'Divider',
'x-component-props': {
children: '{{t("Group")}}',
},
});
}}
/>
);
};

View File

@ -0,0 +1,202 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { useField, useFieldSchema } from '@formily/react';
import { useTranslation } from 'react-i18next';
import { SchemaSettings } from '../../../../application/schema-settings/SchemaSettings';
import { SchemaSettingsModalItem } from '../../../../schema-settings';
import { useDesignable } from '../../../../schema-component/hooks/useDesignable';
import { ColorPicker } from '../../../../schema-component';
import React from 'react';
export function GroupTitleEditor(props) {
const field = useField();
const fieldSchema = useFieldSchema();
const { dn } = useDesignable();
const { t } = useTranslation();
return (
<SchemaSettingsModalItem
title={t('Edit group title')}
schema={{
type: 'object',
title: t('Edit group title'),
properties: {
children: {
'x-decorator': 'FormItem',
'x-component': 'Input',
title: t('Group title'),
default: field.componentProps.children,
'x-component-props': {},
},
},
}}
onSubmit={({ children }) => {
field.componentProps.children = children;
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
fieldSchema['x-component-props'].children = children;
dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
'x-component-props': {
...fieldSchema['x-component-props'],
},
},
});
dn.refresh();
}}
/>
);
}
export const dividerSettings = new SchemaSettings({
name: 'blockSettings:divider',
items: [
{
name: 'editTitle',
type: 'item',
Component: GroupTitleEditor,
},
{
name: 'orientation',
type: 'select',
useComponentProps() {
const field = useField();
const fieldSchema = useFieldSchema();
const { t } = useTranslation();
const { dn } = useDesignable();
return {
title: t('Title position'),
value: field.componentProps?.orientation || 'left',
options: [
{ label: t('Left'), value: 'left' },
{ label: t('Center'), value: 'center' },
{ label: t('Right'), value: 'right' },
],
onChange: (orientation) => {
field.componentProps = field.componentProps || {};
field.componentProps.orientation = orientation;
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
fieldSchema['x-component-props']['orientation'] = orientation;
dn.emit('patch', {
schema: {
['x-uid']: fieldSchema['x-uid'],
'x-component-props': fieldSchema['x-component-props'],
},
});
},
};
},
},
{
name: 'dashed',
type: 'switch',
useComponentProps: () => {
const field = useField();
const fieldSchema = useFieldSchema();
const { t } = useTranslation();
const { dn } = useDesignable();
return {
title: t('Dashed'),
defaultChecked: true,
checked: field.componentProps.dashed,
onChange: (flag) => {
field.componentProps.dashed = flag;
fieldSchema['x-component-props'].dashed = flag;
if (flag === false) {
fieldSchema['x-component-props'].dashed = false;
}
dn.emit('patch', {
schema: fieldSchema,
});
dn.refresh();
},
};
},
},
{
name: 'color',
type: 'item',
useComponentProps: () => {
const { t } = useTranslation();
const { dn } = useDesignable();
const field = useField();
const fieldSchema = useFieldSchema();
return {
title: (
<div style={{ alignItems: 'center', display: 'flex', justifyContent: 'space-between' }}>
{t('Color')}
<div style={{ float: 'right' }}>
<ColorPicker
defaultValue={field.componentProps.color || 'rgba(0, 0, 0, 0.88)'}
onChange={(value) => {
field.componentProps = field.componentProps || {};
field.componentProps.color = value;
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
fieldSchema['x-component-props'].color = value;
dn.emit('patch', {
schema: fieldSchema,
});
dn.refresh();
}}
/>
</div>
</div>
),
};
},
},
{
name: 'borderColor',
type: 'item',
useComponentProps: () => {
const { t } = useTranslation();
const { dn } = useDesignable();
const field = useField();
const fieldSchema = useFieldSchema();
return {
title: (
<div style={{ alignItems: 'center', display: 'flex', justifyContent: 'space-between' }}>
{t('Divider line color')}
<div style={{ float: 'right' }}>
<ColorPicker
defaultValue={field.componentProps.borderColor || 'rgba(5, 5, 5, 0.06)'}
onChange={(value) => {
field.componentProps = field.componentProps || {};
field.componentProps.borderColor = value;
fieldSchema['x-component-props'] = fieldSchema['x-component-props'] || {};
fieldSchema['x-component-props'].borderColor = value;
dn.emit('patch', {
schema: fieldSchema,
});
dn.refresh();
}}
/>
</div>
</div>
),
};
},
},
{
name: 'delete',
type: 'remove',
useComponentProps() {
return {
removeParentsIfNoChildren: true,
breakRemoveOn: {
'x-component': 'Grid',
},
};
},
},
] as any,
});

View File

@ -28,7 +28,7 @@ export const ColorPicker = connect(
trigger="hover"
{...others}
destroyTooltipOnHide
getPopupContainer={(current) => current}
// getPopupContainer={(current) => current}
presets={[
{
label: 'Recommended',

View File

@ -0,0 +1,27 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { connect, mapProps } from '@formily/react';
import { Divider as AntdDivider } from 'antd';
import React from 'react';
export const Divider = connect(
(props) => {
const { color, borderColor } = props;
return <AntdDivider {...props} type="horizontal" style={{ color, borderColor }} orientationMargin="0" />;
},
mapProps((props) => {
return {
orientation: 'left',
...props,
};
}),
);
export default Divider;

View File

@ -0,0 +1,10 @@
/**
* This file is part of the NocoBase (R) project.
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
* Authors: NocoBase Team.
*
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
export * from './Divider';

View File

@ -63,5 +63,6 @@ export * from './unix-timestamp';
export * from './nanoid-input';
export * from './error-fallback';
export * from './expiresRadio';
export * from './divider';
import './index.less';

View File

@ -114,6 +114,8 @@ import { CollectionFieldInitializer } from '../modules/fields/initializer/Collec
import { TableCollectionFieldInitializer } from '../modules/fields/initializer/TableCollectionFieldInitializer';
import { menuItemInitializer, menuItemInitializer_deprecated } from '../modules/menu/menuItemInitializer';
import { blockInitializers, blockInitializers_deprecated } from '../modules/page/BlockInitializers';
import { DividerFormItemInitializer } from '../modules/blocks/other-blocks/divider/DividerFormItemInitializer';
import {
customFormItemInitializers,
customFormItemInitializers_deprecated,
@ -182,6 +184,7 @@ export class SchemaInitializerPlugin extends Plugin {
DisassociateActionInitializer,
FilterActionInitializer,
RefreshActionInitializer,
DividerFormItemInitializer,
} as any);
this.app.schemaInitializerManager.add(blockInitializers_deprecated);

View File

@ -75,6 +75,7 @@ import {
import { subTablePopoverComponentFieldSettings } from '../modules/fields/component/SubTable/subTablePopoverComponentFieldSettings';
import { tagComponentFieldSettings } from '../modules/fields/component/Tag/tagComponentFieldSettings';
import { unixTimestampComponentFieldSettings } from '../modules/fields/component/UnixTimestamp/unixTimestampComponentFieldSettings';
import { dividerSettings } from '../modules/blocks/other-blocks/divider/dividerSettings';
export class SchemaSettingsPlugin extends Plugin {
async load() {
@ -144,5 +145,6 @@ export class SchemaSettingsPlugin extends Plugin {
// this.schemaSettingsManager.add(inputURLComponentFieldSettings);
this.schemaSettingsManager.add(uploadAttachmentComponentFieldSettings);
this.schemaSettingsManager.add(previewComponentFieldSettings);
this.schemaSettingsManager.add(dividerSettings);
}
}

View File

@ -27,7 +27,7 @@ const commonOptions = {
},
{
name: 'addText',
title: '{{t("Add text")}}',
title: '{{t("Add Markdown")}}',
Component: 'BlockItemInitializer',
schema: {
type: 'void',