mirror of
https://github.com/nocobase/nocobase
synced 2024-11-15 01:26:11 +00:00
feat: support for displaying deeper level association fields in data blocks (#5243)
* feat(table): add support for selecting child fields of association fields * style: fix style * feat(details): add support for selecting child fields of association fields * fix: correct sourceId retrieval * test: add tests * chore: fix build error * chore: remove ConfigProvider * test: update e2e tests
This commit is contained in:
parent
5eee3dba91
commit
97d2ad6f52
@ -48,7 +48,11 @@ export const SchemaInitializerMenu: FC<MenuProps> = (props) => {
|
||||
const { items, ...others } = props;
|
||||
const { token } = theme.useToken();
|
||||
const itemsWithPopupClass = useMemo(
|
||||
() => items.map((item) => ({ ...item, popupClassName: `${hashId} ${componentCls}-menu-sub` })),
|
||||
() =>
|
||||
items.map((item) => ({
|
||||
...item,
|
||||
popupClassName: `${hashId} ${componentCls}-menu-sub`,
|
||||
})),
|
||||
[componentCls, hashId, items],
|
||||
);
|
||||
// selectedKeys 为了不让有选中效果
|
||||
@ -62,9 +66,23 @@ export const SchemaInitializerMenu: FC<MenuProps> = (props) => {
|
||||
border-inline-end: 0 !important;
|
||||
.ant-menu-sub {
|
||||
max-height: 50vh !important;
|
||||
padding: ${token.paddingXXS}px !important;
|
||||
}
|
||||
.ant-menu-item {
|
||||
margin-block: 0;
|
||||
margin-inline: ${token.marginXXS}px !important;
|
||||
margin-block: 0 !important;
|
||||
width: auto !important;
|
||||
padding: 0 ${token.paddingSM}px 0 ${token.padding}px !important;
|
||||
}
|
||||
.ant-menu-item-group-title {
|
||||
padding: 0 ${token.padding}px;
|
||||
margin-inline: 0;
|
||||
line-height: 32px;
|
||||
}
|
||||
.ant-menu-submenu-title {
|
||||
margin: 0 ${token.marginXXS}px !important;
|
||||
padding-left: ${token.padding}px !important;
|
||||
width: auto !important;
|
||||
}
|
||||
.ant-menu-root {
|
||||
margin: 0 -${token.margin}px;
|
||||
|
@ -51,11 +51,6 @@ export const useSchemaInitializerStyles = genStyleHook('nb-schema-initializer',
|
||||
},
|
||||
},
|
||||
},
|
||||
[`${componentCls}-menu-sub`]: {
|
||||
ul: {
|
||||
maxHeight: '50vh !important',
|
||||
},
|
||||
},
|
||||
[`${componentCls}-item-content`]: {
|
||||
marginLeft: token.marginXS,
|
||||
},
|
||||
|
@ -76,9 +76,7 @@ test.describe('configure fields', () => {
|
||||
await expect(
|
||||
page.getByLabel('block-item-CollectionField-general-details-general.singleSelect-Single select'),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByLabel('block-item-CollectionField-general-details-general.manyToOne.nickname'),
|
||||
).toBeVisible();
|
||||
await expect(page.getByLabel('block-item-CollectionField-general-details-users.nickname-Nickname')).toBeVisible();
|
||||
|
||||
// delete fields
|
||||
await formItemInitializer.hover();
|
||||
|
@ -68,7 +68,7 @@ test.describe('configure fields', () => {
|
||||
|
||||
await page.mouse.move(300, 0);
|
||||
await expect(page.getByLabel('block-item-CollectionField-general-form-general.id-ID')).toBeVisible();
|
||||
await expect(page.getByLabel('block-item-CollectionField-general-form-general.manyToOne.nickname')).toBeVisible();
|
||||
await expect(page.getByLabel('block-item-CollectionField-general-form-users.nickname-Nickname')).toBeVisible();
|
||||
|
||||
// delete fields
|
||||
await page.getByLabel('schema-initializer-Grid-form:configureFields-general').hover();
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
import { expect, oneEmptyTableBlockWithActions, test } from '@nocobase/test/e2e';
|
||||
import { T3848 } from '../../../details-single/__e2e__/templatesOfBug';
|
||||
import { addAssociationFields } from './templatesOfBug';
|
||||
|
||||
test.describe('where edit form block can be added', () => {
|
||||
test('popup', async ({ page, mockPage, mockRecord }) => {
|
||||
@ -69,4 +70,30 @@ test.describe('where edit form block can be added', () => {
|
||||
|
||||
test.describe('configure actions', () => {});
|
||||
|
||||
test.describe('configure fields', () => {});
|
||||
test.describe('configure fields', () => {
|
||||
test('add association fields', async ({ page, mockPage, mockRecord }) => {
|
||||
const nocoPage = await mockPage(addAssociationFields).waitForInit();
|
||||
const record = await mockRecord('general', 3);
|
||||
await nocoPage.goto();
|
||||
|
||||
// Create association fields for the first, second, and third levels respectively, and assert whether the values are correct
|
||||
await page.getByLabel('action-Action.Link-Edit-').first().click();
|
||||
await page.getByLabel('schema-initializer-Grid-form:').hover();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne1', exact: true }).click();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne1 right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne2', exact: true }).click();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne2 right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne3' }).click();
|
||||
await page.mouse.move(600, 0);
|
||||
|
||||
await expect(page.getByLabel('block-item-CollectionField-general-form-general.manyToOne1-manyToOne1')).toHaveText(
|
||||
`manyToOne1:${record.manyToOne1.id}`,
|
||||
);
|
||||
await expect(
|
||||
page.getByLabel('block-item-CollectionField-general-form-targetCollection1.manyToOne2-manyToOne2'),
|
||||
).toHaveText(`manyToOne2:${record.manyToOne1.manyToOne2.id}`);
|
||||
await expect(
|
||||
page.getByLabel('block-item-CollectionField-general-form-targetCollection2.manyToOne3-manyToOne3'),
|
||||
).toHaveText(`manyToOne3:${record.manyToOne1.manyToOne2.manyToOne3.id}`);
|
||||
});
|
||||
});
|
||||
|
@ -1111,3 +1111,370 @@ export const T3924: PageConfig = {
|
||||
'x-index': 1,
|
||||
},
|
||||
};
|
||||
export const addAssociationFields = {
|
||||
collections: [
|
||||
{
|
||||
name: 'general',
|
||||
fields: [
|
||||
{
|
||||
interface: 'm2o',
|
||||
name: 'manyToOne1',
|
||||
target: 'targetCollection1',
|
||||
},
|
||||
{
|
||||
interface: 'input',
|
||||
name: 'generalText',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'targetCollection1',
|
||||
fields: [
|
||||
{
|
||||
interface: 'm2o',
|
||||
name: 'manyToOne2',
|
||||
target: 'targetCollection2',
|
||||
},
|
||||
{
|
||||
interface: 'input',
|
||||
name: 'targetCollection1Text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'targetCollection2',
|
||||
fields: [
|
||||
{
|
||||
interface: 'm2o',
|
||||
name: 'manyToOne3',
|
||||
target: 'emptyCollection',
|
||||
},
|
||||
{
|
||||
interface: 'input',
|
||||
name: 'targetCollection2Text',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'emptyCollection',
|
||||
},
|
||||
],
|
||||
pageSchema: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-component': 'Page',
|
||||
properties: {
|
||||
'6d3i9i6e7vg': {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-component': 'Grid',
|
||||
'x-initializer': 'page:addBlock',
|
||||
properties: {
|
||||
krwfqgbq4fy: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Row',
|
||||
'x-app-version': '1.3.19-beta',
|
||||
properties: {
|
||||
js8p7716v8y: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Col',
|
||||
'x-app-version': '1.3.19-beta',
|
||||
properties: {
|
||||
nwk3otm0wbu: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-decorator': 'TableBlockProvider',
|
||||
'x-acl-action': 'general:list',
|
||||
'x-use-decorator-props': 'useTableBlockDecoratorProps',
|
||||
'x-decorator-props': {
|
||||
collection: 'general',
|
||||
dataSource: 'main',
|
||||
action: 'list',
|
||||
params: {
|
||||
pageSize: 20,
|
||||
},
|
||||
rowKey: 'id',
|
||||
showIndex: true,
|
||||
dragSort: false,
|
||||
},
|
||||
'x-toolbar': 'BlockSchemaToolbar',
|
||||
'x-settings': 'blockSettings:table',
|
||||
'x-component': 'CardItem',
|
||||
'x-filter-targets': [],
|
||||
'x-app-version': '1.3.19-beta',
|
||||
properties: {
|
||||
actions: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-initializer': 'table:configureActions',
|
||||
'x-component': 'ActionBar',
|
||||
'x-component-props': {
|
||||
style: {
|
||||
marginBottom: 'var(--nb-spacing)',
|
||||
},
|
||||
},
|
||||
'x-app-version': '1.3.19-beta',
|
||||
'x-uid': 'wkkuk2ca9oz',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
s00slxnrdog: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'array',
|
||||
'x-initializer': 'table:configureColumns',
|
||||
'x-component': 'TableV2',
|
||||
'x-use-component-props': 'useTableBlockProps',
|
||||
'x-component-props': {
|
||||
rowKey: 'id',
|
||||
rowSelection: {
|
||||
type: 'checkbox',
|
||||
},
|
||||
},
|
||||
'x-app-version': '1.3.19-beta',
|
||||
properties: {
|
||||
actions: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
title: '{{ t("Actions") }}',
|
||||
'x-action-column': 'actions',
|
||||
'x-decorator': 'TableV2.Column.ActionBar',
|
||||
'x-component': 'TableV2.Column',
|
||||
'x-toolbar': 'TableColumnSchemaToolbar',
|
||||
'x-initializer': 'table:configureItemActions',
|
||||
'x-settings': 'fieldSettings:TableColumn',
|
||||
'x-toolbar-props': {
|
||||
initializer: 'table:configureItemActions',
|
||||
},
|
||||
'x-app-version': '1.3.19-beta',
|
||||
properties: {
|
||||
mpthybxwhi6: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-decorator': 'DndContext',
|
||||
'x-component': 'Space',
|
||||
'x-component-props': {
|
||||
split: '|',
|
||||
},
|
||||
'x-app-version': '1.3.19-beta',
|
||||
properties: {
|
||||
yp1u36754xm: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
title: '{{ t("Edit") }}',
|
||||
'x-action': 'update',
|
||||
'x-toolbar': 'ActionSchemaToolbar',
|
||||
'x-settings': 'actionSettings:edit',
|
||||
'x-component': 'Action.Link',
|
||||
'x-component-props': {
|
||||
openMode: 'drawer',
|
||||
icon: 'EditOutlined',
|
||||
},
|
||||
'x-action-context': {
|
||||
dataSource: 'main',
|
||||
collection: 'general',
|
||||
},
|
||||
'x-decorator': 'ACLActionProvider',
|
||||
'x-designer-props': {
|
||||
linkageAction: true,
|
||||
},
|
||||
properties: {
|
||||
drawer: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
title: '{{ t("Edit record") }}',
|
||||
'x-component': 'Action.Container',
|
||||
'x-component-props': {
|
||||
className: 'nb-action-popup',
|
||||
},
|
||||
properties: {
|
||||
tabs: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-component': 'Tabs',
|
||||
'x-component-props': {},
|
||||
'x-initializer': 'popup:addTab',
|
||||
properties: {
|
||||
tab1: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
title: '{{t("Edit")}}',
|
||||
'x-component': 'Tabs.TabPane',
|
||||
'x-designer': 'Tabs.Designer',
|
||||
'x-component-props': {},
|
||||
properties: {
|
||||
grid: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-component': 'Grid',
|
||||
'x-initializer': 'popup:common:addBlock',
|
||||
properties: {
|
||||
dhu7la398bc: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Row',
|
||||
'x-app-version': '1.3.19-beta',
|
||||
properties: {
|
||||
ex9i4u2sm9o: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-component': 'Grid.Col',
|
||||
'x-app-version': '1.3.19-beta',
|
||||
properties: {
|
||||
gdna46r5948: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-acl-action-props': {
|
||||
skipScopeCheck: false,
|
||||
},
|
||||
'x-acl-action': 'general:update',
|
||||
'x-decorator': 'FormBlockProvider',
|
||||
'x-use-decorator-props':
|
||||
'useEditFormBlockDecoratorProps',
|
||||
'x-decorator-props': {
|
||||
action: 'get',
|
||||
dataSource: 'main',
|
||||
collection: 'general',
|
||||
},
|
||||
'x-toolbar': 'BlockSchemaToolbar',
|
||||
'x-settings': 'blockSettings:editForm',
|
||||
'x-component': 'CardItem',
|
||||
'x-app-version': '1.3.19-beta',
|
||||
properties: {
|
||||
q7vswewc9bk: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-component': 'FormV2',
|
||||
'x-use-component-props': 'useEditFormBlockProps',
|
||||
'x-app-version': '1.3.19-beta',
|
||||
properties: {
|
||||
grid: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-component': 'Grid',
|
||||
'x-initializer': 'form:configureFields',
|
||||
'x-app-version': '1.3.19-beta',
|
||||
'x-uid': 'fu2wc0gvxg7',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
jvi33jag3zs: {
|
||||
_isJSONSchemaObject: true,
|
||||
version: '2.0',
|
||||
type: 'void',
|
||||
'x-initializer': 'editForm:configureActions',
|
||||
'x-component': 'ActionBar',
|
||||
'x-component-props': {
|
||||
layout: 'one-column',
|
||||
},
|
||||
'x-app-version': '1.3.19-beta',
|
||||
'x-uid': 'zox6jjontst',
|
||||
'x-async': false,
|
||||
'x-index': 2,
|
||||
},
|
||||
},
|
||||
'x-uid': 'e91gqbinrdp',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': 'd2lh71p96uu',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': 'e5pfc9sit0l',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': '50qpb5g4zcw',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': '3u9vcm0gftv',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': '59ihnv5o5u5',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': '7i9nnjy10pf',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': 'kov4btsbs2c',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': '4fixo409z6d',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': 'kacm537dm0m',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': 'agw5b9adl6m',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': '85dhumz9qp7',
|
||||
'x-async': false,
|
||||
'x-index': 2,
|
||||
},
|
||||
},
|
||||
'x-uid': '300ltjt2u3c',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': 'ogjd21lszel',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': 'fn1knfs54ow',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': 'im83gpz4p8l',
|
||||
'x-async': false,
|
||||
'x-index': 1,
|
||||
},
|
||||
},
|
||||
'x-uid': 'tir06tp0oyx',
|
||||
'x-async': true,
|
||||
'x-index': 1,
|
||||
},
|
||||
};
|
||||
|
@ -159,7 +159,7 @@ test.describe('configure fields', () => {
|
||||
await page.mouse.move(300, 0);
|
||||
await expect(page.getByLabel('block-item-CollectionField-general-grid-card-general.id-ID').first()).toBeVisible();
|
||||
await expect(
|
||||
page.getByLabel('block-item-CollectionField-general-grid-card-general.manyToOne.nickname').first(),
|
||||
page.getByLabel('block-item-CollectionField-general-grid-card-users.nickname-Nickname').first(),
|
||||
).toBeVisible();
|
||||
|
||||
// delete fields
|
||||
|
@ -157,7 +157,7 @@ test.describe('configure fields', () => {
|
||||
await page.mouse.move(300, 0);
|
||||
await expect(page.getByLabel('block-item-CollectionField-general-list-general.id-ID').first()).toBeVisible();
|
||||
await expect(
|
||||
page.getByLabel('block-item-CollectionField-general-list-general.manyToOne.nickname').first(),
|
||||
page.getByLabel('block-item-CollectionField-general-list-users.nickname-Nickname').first(),
|
||||
).toBeVisible();
|
||||
|
||||
// delete fields
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
import { Page, expect, oneEmptyTable, test } from '@nocobase/test/e2e';
|
||||
import { addAssociationFields } from '../../form/__e2e__/form-edit/templatesOfBug';
|
||||
import { oneTableWithInheritFields } from './templatesOfBug';
|
||||
|
||||
const deleteButton = async (page: Page, name: string) => {
|
||||
@ -113,6 +114,141 @@ test.describe('configure columns', () => {
|
||||
await expect(page.getByRole('button', { name: 'Nickname', exact: true })).not.toBeVisible();
|
||||
});
|
||||
|
||||
test('multiple depths of association fields', async ({ page, mockPage, mockRecord, mockRecords }) => {
|
||||
const nocoPage = await mockPage(addAssociationFields).waitForInit();
|
||||
|
||||
// The purpose here is to make the IDs in the same row different
|
||||
await mockRecords('targetCollection1', 2, 0);
|
||||
await mockRecords('targetCollection2', 1, 0);
|
||||
|
||||
const record = await mockRecord('general', 3);
|
||||
await nocoPage.goto();
|
||||
|
||||
// 1. Create association fields for the first, second, and third levels
|
||||
await page.getByLabel('schema-initializer-TableV2-').hover();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne1', exact: true }).click();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne1 right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne2', exact: true }).click();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne2 right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne3' }).click();
|
||||
await page.mouse.move(600, 0);
|
||||
|
||||
// 2. Click on the association field, create a details block in the popup, display the ID field, and assert if it's correct
|
||||
await page
|
||||
.getByRole('button', { name: `${record.manyToOne1.id}`, exact: true })
|
||||
.getByText(record.manyToOne1.id)
|
||||
.click();
|
||||
await page.getByLabel('schema-initializer-Grid-popup').hover();
|
||||
await page.getByRole('menuitem', { name: 'table Details right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'Current record' }).click();
|
||||
await page.getByLabel('schema-initializer-Grid-details:configureFields-targetCollection1').hover();
|
||||
await page.getByRole('menuitem', { name: 'ID', exact: true }).click();
|
||||
await page.mouse.move(600, 0);
|
||||
await expect(page.getByLabel('block-item-CollectionField-')).toHaveText(`ID:${record.manyToOne1.id}`);
|
||||
await page.getByLabel('drawer-AssociationField.Viewer-targetCollection1-View record-mask').click();
|
||||
|
||||
await page
|
||||
.getByRole('button', { name: `${record.manyToOne1.manyToOne2.id}`, exact: true })
|
||||
.getByText(record.manyToOne1.manyToOne2.id)
|
||||
.click();
|
||||
await page.getByLabel('schema-initializer-Grid-popup').hover();
|
||||
await page.getByRole('menuitem', { name: 'table Details right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'Current record' }).click();
|
||||
await page.getByLabel('schema-initializer-Grid-details:configureFields-targetCollection2').hover();
|
||||
await page.getByRole('menuitem', { name: 'ID', exact: true }).click();
|
||||
await page.mouse.move(600, 0);
|
||||
await expect(page.getByLabel('block-item-CollectionField-')).toHaveText(`ID:${record.manyToOne1.manyToOne2.id}`);
|
||||
await page.getByLabel('drawer-AssociationField.Viewer-targetCollection2-View record-mask').click();
|
||||
|
||||
await page
|
||||
.getByRole('button', { name: `${record.manyToOne1.manyToOne2.manyToOne3.id}`, exact: true })
|
||||
.getByText(record.manyToOne1.manyToOne2.manyToOne3.id)
|
||||
.click();
|
||||
await page.getByLabel('schema-initializer-Grid-popup').hover();
|
||||
await page.getByRole('menuitem', { name: 'table Details right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'Current record' }).click();
|
||||
await page.getByLabel('schema-initializer-Grid-details:configureFields-emptyCollection').hover();
|
||||
await page.getByRole('menuitem', { name: 'ID', exact: true }).click();
|
||||
await page.mouse.move(600, 0);
|
||||
await expect(page.getByLabel('block-item-CollectionField-')).toHaveText(
|
||||
`ID:${record.manyToOne1.manyToOne2.manyToOne3.id}`,
|
||||
);
|
||||
await page.getByLabel('drawer-AssociationField.Viewer-emptyCollection-View record-mask').click();
|
||||
|
||||
// 测试详情区块的关系字段
|
||||
// 1. 点击行操作按钮打开弹窗,创建一个详情区块,并配置第一、二、三级关系字段
|
||||
await page.getByLabel('action-Action.Link-Edit-').first().click();
|
||||
await page.getByLabel('schema-initializer-Grid-popup').hover();
|
||||
await page.getByRole('menuitem', { name: 'table Details right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'Current record' }).click();
|
||||
await page.getByLabel('schema-initializer-Grid-details:configureFields-general').hover();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne1', exact: true }).click();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne1 right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne2', exact: true }).click();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne2 right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'manyToOne3' }).click();
|
||||
await page.mouse.move(600, 0);
|
||||
|
||||
// 2. 点击每一个关系字段,创建一个详情区块,显示 ID 字段,断言 ID 是否正确
|
||||
await page
|
||||
.getByLabel('block-item-CollectionField-general-details-general.manyToOne1-manyToOne1')
|
||||
.getByText(String(record.manyToOne1.id), { exact: true })
|
||||
.click();
|
||||
await page
|
||||
.getByTestId('drawer-AssociationField.Viewer-targetCollection1-View record')
|
||||
.getByLabel('schema-initializer-Grid-popup')
|
||||
.hover();
|
||||
await page.getByRole('menuitem', { name: 'table Details right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'Current record' }).click();
|
||||
await page.getByLabel('schema-initializer-Grid-details:configureFields-targetCollection1').hover();
|
||||
await page.getByRole('menuitem', { name: 'ID', exact: true }).click();
|
||||
await expect(
|
||||
page
|
||||
.getByTestId('drawer-AssociationField.Viewer-targetCollection1-View record')
|
||||
.getByLabel('block-item-CollectionField-'),
|
||||
).toHaveText(`ID:${record.manyToOne1.id}`);
|
||||
await page.getByLabel('drawer-AssociationField.Viewer-targetCollection1-View record-mask').click();
|
||||
|
||||
// another field
|
||||
await page
|
||||
.getByLabel('block-item-CollectionField-general-details-targetCollection1.manyToOne2-')
|
||||
.getByText(String(record.manyToOne1.manyToOne2.id), { exact: true })
|
||||
.click();
|
||||
await page
|
||||
.getByTestId('drawer-AssociationField.Viewer-targetCollection2-View record')
|
||||
.getByLabel('schema-initializer-Grid-popup')
|
||||
.hover();
|
||||
await page.getByRole('menuitem', { name: 'table Details right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'Current record' }).click();
|
||||
await page.getByLabel('schema-initializer-Grid-details:configureFields-targetCollection2').hover();
|
||||
await page.getByRole('menuitem', { name: 'ID', exact: true }).click();
|
||||
await expect(
|
||||
page
|
||||
.getByTestId('drawer-AssociationField.Viewer-targetCollection2-View record')
|
||||
.getByLabel('block-item-CollectionField-'),
|
||||
).toHaveText(`ID:${record.manyToOne1.manyToOne2.id}`);
|
||||
await page.getByLabel('drawer-AssociationField.Viewer-targetCollection2-View record-mask').click();
|
||||
|
||||
// another field
|
||||
await page
|
||||
.getByLabel('block-item-CollectionField-general-details-targetCollection2.manyToOne3-')
|
||||
.getByText(String(record.manyToOne1.manyToOne2.manyToOne3.id), { exact: true })
|
||||
.click();
|
||||
await page
|
||||
.getByTestId('drawer-AssociationField.Viewer-emptyCollection-View record')
|
||||
.getByLabel('schema-initializer-Grid-popup')
|
||||
.hover();
|
||||
await page.getByRole('menuitem', { name: 'table Details right' }).hover();
|
||||
await page.getByRole('menuitem', { name: 'Current record' }).click();
|
||||
await page.getByLabel('schema-initializer-Grid-details:configureFields-emptyCollection').hover();
|
||||
await page.getByRole('menuitem', { name: 'ID', exact: true }).click();
|
||||
await expect(
|
||||
page
|
||||
.getByTestId('drawer-AssociationField.Viewer-emptyCollection-View record')
|
||||
.getByLabel('block-item-CollectionField-'),
|
||||
).toHaveText(`ID:${record.manyToOne1.manyToOne2.manyToOne3.id}`);
|
||||
});
|
||||
|
||||
test.pgOnly('display inherit fields', async ({ page, mockPage, mockRecord }) => {
|
||||
const nocoPage = await mockPage(oneTableWithInheritFields).waitForInit();
|
||||
const record = await mockRecord('child');
|
||||
|
@ -9,10 +9,11 @@
|
||||
|
||||
import { observer, RecursionField, useField, useFieldSchema } from '@formily/react';
|
||||
import { toArr } from '@formily/shared';
|
||||
import _ from 'lodash';
|
||||
import React, { FC, Fragment, useRef, useState } from 'react';
|
||||
import { useDesignable } from '../../';
|
||||
import { WithoutTableFieldResource } from '../../../block-provider';
|
||||
import { useCollectionManager, useCollectionRecordData } from '../../../data-source';
|
||||
import { CollectionRecordProvider, useCollectionManager, useCollectionRecordData } from '../../../data-source';
|
||||
import { useOpenModeContext } from '../../../modules/popup/OpenModeProvider';
|
||||
import { VariablePopupRecordProvider } from '../../../modules/variable/variablesProvider/VariablePopupRecordProvider';
|
||||
import { useCompile } from '../../hooks';
|
||||
@ -133,6 +134,25 @@ interface ReadPrettyInternalViewerProps {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* the sourceData is used to get the sourceId
|
||||
* @param recordData
|
||||
* @param fieldSchema
|
||||
* @returns
|
||||
*/
|
||||
const getSourceData = (recordData, fieldSchema) => {
|
||||
const sourceRecordKey = (fieldSchema.name as string)
|
||||
.split('.')
|
||||
.filter((o, i, arr) => i < arr.length - 1)
|
||||
.join('.');
|
||||
|
||||
if (!sourceRecordKey) {
|
||||
return recordData;
|
||||
}
|
||||
|
||||
return _.get(recordData, sourceRecordKey);
|
||||
};
|
||||
|
||||
export const ReadPrettyInternalViewer: React.FC = observer(
|
||||
(props: ReadPrettyInternalViewerProps) => {
|
||||
const { value, ButtonList = ButtonLinkList } = props;
|
||||
@ -146,10 +166,13 @@ export const ReadPrettyInternalViewer: React.FC = observer(
|
||||
const { visibleWithURL, setVisibleWithURL } = usePopupUtils();
|
||||
const [btnHover, setBtnHover] = useState(!!visibleWithURL);
|
||||
const { defaultOpenMode } = useOpenModeContext();
|
||||
const recordData = useCollectionRecordData();
|
||||
|
||||
const btnElement = (
|
||||
<EllipsisWithTooltip ellipsis={true} ref={ellipsisWithTooltipRef}>
|
||||
<ButtonList setBtnHover={setBtnHover} value={value} fieldNames={props.fieldNames} />
|
||||
<CollectionRecordProvider isNew={false} record={getSourceData(recordData, fieldSchema)}>
|
||||
<ButtonList setBtnHover={setBtnHover} value={value} fieldNames={props.fieldNames} />
|
||||
</CollectionRecordProvider>
|
||||
</EllipsisWithTooltip>
|
||||
);
|
||||
|
||||
|
@ -24,8 +24,13 @@ import {
|
||||
} from '../';
|
||||
import { useFormBlockContext } from '../block-provider/FormBlockProvider';
|
||||
import { useFormActiveFields } from '../block-provider/hooks/useFormActiveFields';
|
||||
import { FieldOptions, useCollectionManager_deprecated, useCollection_deprecated } from '../collection-manager';
|
||||
import { Collection, CollectionFieldOptions } from '../data-source/collection/Collection';
|
||||
import {
|
||||
CollectionFieldOptions_deprecated,
|
||||
FieldOptions,
|
||||
useCollectionManager_deprecated,
|
||||
useCollection_deprecated,
|
||||
} from '../collection-manager';
|
||||
import { Collection, CollectionFieldOptions, CollectionOptions } from '../data-source/collection/Collection';
|
||||
import { useDataSourceManager } from '../data-source/data-source/DataSourceManagerProvider';
|
||||
import { isAssocField } from '../filter-provider/utils';
|
||||
import { useActionContext, useCompile, useDesignable } from '../schema-component';
|
||||
@ -172,60 +177,132 @@ export function useTableColumnInitializerFields() {
|
||||
|
||||
export function useAssociatedTableColumnInitializerFields() {
|
||||
const { name, fields } = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
const { getInterface, getCollectionFields, getCollection } = useCollectionManager_deprecated();
|
||||
const groups = fields
|
||||
?.filter((field) => {
|
||||
return ['o2o', 'oho', 'obo', 'm2o'].includes(field.interface);
|
||||
})
|
||||
?.map((field) => {
|
||||
const subFields = getCollectionFields(field.target);
|
||||
const items = subFields
|
||||
// ?.filter((subField) => subField?.interface && !['o2o', 'oho', 'obo', 'o2m', 'm2o', 'subTable', 'linkTo'].includes(subField?.interface))
|
||||
?.filter(
|
||||
(subField) => subField?.interface && !['subTable'].includes(subField?.interface) && !subField?.treeChildren,
|
||||
)
|
||||
?.map((subField) => {
|
||||
const interfaceConfig = getInterface(subField.interface);
|
||||
const schema = {
|
||||
// type: 'string',
|
||||
name: `${field.name}.${subField.name}`,
|
||||
// title: subField?.uiSchema?.title || subField.name,
|
||||
'x-component': 'CollectionField',
|
||||
'x-read-pretty': true,
|
||||
'x-collection-field': `${name}.${field.name}.${subField.name}`,
|
||||
'x-component-props': {},
|
||||
};
|
||||
|
||||
return {
|
||||
type: 'item',
|
||||
name: subField.name,
|
||||
title: subField?.uiSchema?.title || subField.name,
|
||||
Component: 'TableCollectionFieldInitializer',
|
||||
find: findTableColumn,
|
||||
remove: removeTableColumn,
|
||||
schemaInitialize: (s) => {
|
||||
interfaceConfig?.schemaInitialize?.(s, {
|
||||
field: subField,
|
||||
readPretty: true,
|
||||
block: 'Table',
|
||||
targetCollection: getCollection(field.target),
|
||||
});
|
||||
},
|
||||
field: subField,
|
||||
schema,
|
||||
} as SchemaInitializerItemType;
|
||||
});
|
||||
return {
|
||||
type: 'subMenu',
|
||||
name: field.uiSchema?.title,
|
||||
title: field.uiSchema?.title,
|
||||
children: items,
|
||||
} as SchemaInitializerItemType;
|
||||
return getGroupItemForTable({
|
||||
getCollectionFields,
|
||||
field,
|
||||
getInterface,
|
||||
getCollection,
|
||||
schemaName: field.name,
|
||||
maxDepth: 2,
|
||||
depth: 1,
|
||||
t,
|
||||
});
|
||||
});
|
||||
|
||||
return groups;
|
||||
}
|
||||
|
||||
function getGroupItemForTable({
|
||||
getCollectionFields,
|
||||
field,
|
||||
getInterface,
|
||||
getCollection,
|
||||
schemaName,
|
||||
maxDepth,
|
||||
depth,
|
||||
t,
|
||||
}: {
|
||||
getCollectionFields: (name: any, customDataSource?: string) => CollectionFieldOptions_deprecated[];
|
||||
field: CollectionFieldOptions;
|
||||
getInterface: (name: string) => any;
|
||||
getCollection: (name: any, customDataSource?: string) => CollectionOptions;
|
||||
schemaName: string;
|
||||
maxDepth: number;
|
||||
depth: number;
|
||||
t: any;
|
||||
}) {
|
||||
const subFields = getCollectionFields(field.target);
|
||||
const items = subFields
|
||||
?.filter(
|
||||
(subField) => subField?.interface && !['subTable'].includes(subField?.interface) && !subField?.treeChildren,
|
||||
)
|
||||
?.map((subField) => {
|
||||
const interfaceConfig = getInterface(subField.interface);
|
||||
const newSchemaName = `${schemaName}.${subField.name}`;
|
||||
const schema = {
|
||||
// type: 'string',
|
||||
name: newSchemaName,
|
||||
// title: subField?.uiSchema?.title || subField.name,
|
||||
'x-component': 'CollectionField',
|
||||
'x-read-pretty': true,
|
||||
'x-collection-field': `${field.target}.${subField.name}`,
|
||||
'x-component-props': {},
|
||||
};
|
||||
|
||||
return {
|
||||
type: 'item',
|
||||
name: newSchemaName,
|
||||
title: subField?.uiSchema?.title || subField.name,
|
||||
Component: 'TableCollectionFieldInitializer',
|
||||
find: findTableColumn,
|
||||
remove: removeTableColumn,
|
||||
schemaInitialize: (s) => {
|
||||
interfaceConfig?.schemaInitialize?.(s, {
|
||||
field: subField,
|
||||
readPretty: true,
|
||||
block: 'Table',
|
||||
targetCollection: getCollection(field.target),
|
||||
});
|
||||
},
|
||||
field: subField,
|
||||
schema,
|
||||
} as SchemaInitializerItemType;
|
||||
});
|
||||
|
||||
const displayCollectionFields = {
|
||||
type: 'itemGroup',
|
||||
name: `${schemaName}-displayCollectionFields`,
|
||||
title: t('Display fields'),
|
||||
children: items,
|
||||
};
|
||||
|
||||
const children = [displayCollectionFields];
|
||||
|
||||
if (depth < maxDepth) {
|
||||
const subChildren = subFields
|
||||
?.filter((subField) => {
|
||||
return ['o2o', 'oho', 'obo', 'm2o'].includes(subField.interface);
|
||||
})
|
||||
.map((subField) => {
|
||||
return getGroupItemForTable({
|
||||
getCollectionFields,
|
||||
field: subField,
|
||||
getInterface,
|
||||
getCollection,
|
||||
schemaName: `${schemaName}.${subField.name}`,
|
||||
maxDepth,
|
||||
depth: depth + 1,
|
||||
t,
|
||||
});
|
||||
});
|
||||
|
||||
if (subChildren.length) {
|
||||
const group: any = {
|
||||
type: 'itemGroup',
|
||||
name: `${schemaName}-associationFields`,
|
||||
title: t('Display association fields'),
|
||||
children: subChildren,
|
||||
};
|
||||
|
||||
children.push(group);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'subMenu',
|
||||
name: `${schemaName}`,
|
||||
title: field.uiSchema?.title,
|
||||
children,
|
||||
} as SchemaInitializerItemType;
|
||||
}
|
||||
|
||||
export function useInheritsTableColumnInitializerFields() {
|
||||
const { name } = useCollection_deprecated();
|
||||
const { getInterface, getInheritCollections, getCollection, getParentCollectionFields } =
|
||||
@ -429,6 +506,7 @@ export const useAssociatedFormItemInitializerFields = (options?: any) => {
|
||||
const { name, fields } = useCollection_deprecated();
|
||||
const { getInterface, getCollectionFields, getCollection } = useCollectionManager_deprecated();
|
||||
const form = useForm();
|
||||
const { t } = useTranslation();
|
||||
const { readPretty = form.readPretty, block = 'Form' } = options || {};
|
||||
const interfaces = block === 'Form' ? ['m2o'] : ['o2o', 'oho', 'obo', 'm2o'];
|
||||
const groups = fields
|
||||
@ -436,58 +514,18 @@ export const useAssociatedFormItemInitializerFields = (options?: any) => {
|
||||
return interfaces.includes(field.interface);
|
||||
})
|
||||
?.map((field) => {
|
||||
const subFields = getCollectionFields(field.target);
|
||||
const items = subFields
|
||||
?.filter(
|
||||
(subField) => subField?.interface && !['subTable'].includes(subField?.interface) && !subField.treeChildren,
|
||||
)
|
||||
?.map((subField) => {
|
||||
const interfaceConfig = getInterface(subField.interface);
|
||||
const isFileCollection = field?.target && getCollection(field?.target)?.template === 'file';
|
||||
const schema = {
|
||||
type: 'string',
|
||||
name: `${field.name}.${subField.name}`,
|
||||
// 'x-designer': 'FormItem.Designer',
|
||||
'x-toolbar': 'FormItemSchemaToolbar',
|
||||
'x-settings': 'fieldSettings:FormItem',
|
||||
'x-component': 'CollectionField',
|
||||
'x-read-pretty': readPretty,
|
||||
'x-component-props': {
|
||||
'pattern-disable': block === 'Form' && readPretty,
|
||||
fieldNames: isFileCollection
|
||||
? {
|
||||
label: 'preview',
|
||||
value: 'id',
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
'x-decorator': 'FormItem',
|
||||
'x-collection-field': `${name}.${field.name}.${subField.name}`,
|
||||
};
|
||||
return {
|
||||
name: subField?.uiSchema?.title || subField.name,
|
||||
type: 'item',
|
||||
title: subField?.uiSchema?.title || subField.name,
|
||||
Component: 'CollectionFieldInitializer',
|
||||
remove: removeGridFormItem,
|
||||
schemaInitialize: (s) => {
|
||||
interfaceConfig?.schemaInitialize?.(s, {
|
||||
field: subField,
|
||||
block,
|
||||
readPretty,
|
||||
targetCollection: getCollection(field.target),
|
||||
});
|
||||
},
|
||||
schema,
|
||||
} as SchemaInitializerItemType;
|
||||
});
|
||||
|
||||
return {
|
||||
type: 'subMenu',
|
||||
name: field.uiSchema?.title,
|
||||
title: field.uiSchema?.title,
|
||||
children: items,
|
||||
} as SchemaInitializerItemType;
|
||||
return getGroupItemForForm({
|
||||
getCollectionFields,
|
||||
field,
|
||||
getInterface,
|
||||
getCollection,
|
||||
readPretty,
|
||||
block,
|
||||
schemaName: field.name,
|
||||
maxDepth: 2,
|
||||
depth: 1,
|
||||
t,
|
||||
});
|
||||
});
|
||||
return groups;
|
||||
};
|
||||
@ -1540,6 +1578,123 @@ const getChildren = ({
|
||||
});
|
||||
};
|
||||
|
||||
function getGroupItemForForm({
|
||||
getCollectionFields,
|
||||
field,
|
||||
getInterface,
|
||||
getCollection,
|
||||
readPretty,
|
||||
block,
|
||||
maxDepth,
|
||||
depth,
|
||||
schemaName,
|
||||
t,
|
||||
}: {
|
||||
getCollectionFields: (name: any, customDataSource?: string) => CollectionFieldOptions_deprecated[];
|
||||
field: CollectionFieldOptions;
|
||||
getInterface: (name: string) => any;
|
||||
getCollection: (name: any, customDataSource?: string) => CollectionOptions;
|
||||
readPretty: any;
|
||||
block: any;
|
||||
maxDepth: number;
|
||||
depth: number;
|
||||
schemaName: string;
|
||||
t: any;
|
||||
}) {
|
||||
const subFields = getCollectionFields(field.target);
|
||||
const items = subFields
|
||||
?.filter((subField) => subField?.interface && !['subTable'].includes(subField?.interface) && !subField.treeChildren)
|
||||
?.map((subField) => {
|
||||
const interfaceConfig = getInterface(subField.interface);
|
||||
const isFileCollection = field?.target && getCollection(field?.target)?.template === 'file';
|
||||
const newSchemaName = `${schemaName}.${subField.name}`;
|
||||
const schema = {
|
||||
type: 'string',
|
||||
name: newSchemaName,
|
||||
// 'x-designer': 'FormItem.Designer',
|
||||
'x-toolbar': 'FormItemSchemaToolbar',
|
||||
'x-settings': 'fieldSettings:FormItem',
|
||||
'x-component': 'CollectionField',
|
||||
'x-read-pretty': readPretty,
|
||||
'x-component-props': {
|
||||
'pattern-disable': block === 'Form' && readPretty,
|
||||
fieldNames: isFileCollection
|
||||
? {
|
||||
label: 'preview',
|
||||
value: 'id',
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
'x-decorator': 'FormItem',
|
||||
'x-collection-field': `${field.target}.${subField.name}`,
|
||||
};
|
||||
return {
|
||||
name: newSchemaName,
|
||||
type: 'item',
|
||||
title: subField?.uiSchema?.title || subField.name,
|
||||
Component: 'CollectionFieldInitializer',
|
||||
remove: removeGridFormItem,
|
||||
schemaInitialize: (s) => {
|
||||
interfaceConfig?.schemaInitialize?.(s, {
|
||||
field: subField,
|
||||
block,
|
||||
readPretty,
|
||||
targetCollection: getCollection(field.target),
|
||||
});
|
||||
},
|
||||
schema,
|
||||
} as SchemaInitializerItemType;
|
||||
});
|
||||
|
||||
const displayCollectionFields = {
|
||||
type: 'itemGroup',
|
||||
name: `${schemaName}-displayCollectionFields`,
|
||||
title: t('Display fields'),
|
||||
children: items,
|
||||
};
|
||||
|
||||
const children = [displayCollectionFields];
|
||||
|
||||
if (depth < maxDepth) {
|
||||
const subChildren = subFields
|
||||
?.filter((subField) => {
|
||||
return ['o2o', 'oho', 'obo', 'm2o'].includes(subField.interface);
|
||||
})
|
||||
.map((subField) => {
|
||||
return getGroupItemForForm({
|
||||
getCollectionFields,
|
||||
field: subField,
|
||||
getInterface,
|
||||
getCollection,
|
||||
schemaName: `${schemaName}.${subField.name}`,
|
||||
readPretty,
|
||||
block,
|
||||
maxDepth,
|
||||
depth: depth + 1,
|
||||
t,
|
||||
});
|
||||
});
|
||||
|
||||
if (subChildren.length) {
|
||||
const group: any = {
|
||||
type: 'itemGroup',
|
||||
name: `${schemaName}-associationFields`,
|
||||
title: t('Display association fields'),
|
||||
children: subChildren,
|
||||
};
|
||||
|
||||
children.push(group);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'subMenu',
|
||||
name: `${schemaName}.${field.name}`,
|
||||
title: field.uiSchema?.title,
|
||||
children,
|
||||
} as SchemaInitializerItemType;
|
||||
}
|
||||
|
||||
function useAssociationFields({
|
||||
componentName,
|
||||
filterCollections,
|
||||
|
@ -7,11 +7,10 @@
|
||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||
*/
|
||||
|
||||
import { css } from '@emotion/css';
|
||||
import { ISchema, Schema, useField, useForm } from '@formily/react';
|
||||
import { Select } from 'antd';
|
||||
import React from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Select } from 'antd';
|
||||
import { useCollectionManager_deprecated, useDesignable } from '..';
|
||||
import { SchemaSettingsModalItem } from './SchemaSettings';
|
||||
|
||||
@ -41,7 +40,7 @@ export const SchemaSettingsNumberFormat = function NumberFormatConfig(props: { f
|
||||
const collectionField = getCollectionJoinField(fieldSchema?.['x-collection-field']) || {};
|
||||
const { formatStyle, unitConversion, unitConversionType, separator, step, addonBefore, addonAfter } =
|
||||
fieldSchema['x-component-props'] || {};
|
||||
const { step: prescition } = collectionField?.uiSchema['x-component-props'] || {};
|
||||
const { step: prescition } = collectionField?.uiSchema?.['x-component-props'] || {};
|
||||
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
|
Loading…
Reference in New Issue
Block a user