refactor: flatten and merge Actions (#4336)

* chore: remove switch

* refactor: ensure compatibility with old code

* refactor: flatten Actions

* refactor: extract options

* refactor: remove isCusomeizeCreate

* refactor: merge addNew and addRecord actions

* refactor: merge Submit and Save record actions

* refactor: extract common options

* feat: add tow props called 'currentText' and 'otherText'

* chore: fix failed tests

* refactor: add ActionInitializerItem to replace ActionInitializer

* chore: fix failed tests

* fix: fix T-4284

* fix: fix inherit

* chore: fix failed test

* chore: add Switch

* chore: add Switch for delete button

* test: e2ePageObjectModel

---------

Co-authored-by: hongboji <j414562100@qq.com>
This commit is contained in:
Zeke Zhang 2024-05-17 09:37:23 +08:00 committed by GitHub
parent 779029e348
commit ec558e3b98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
115 changed files with 1639 additions and 3578 deletions

View File

@ -1,83 +0,0 @@
/**
* 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 { SchemaInitializer } from '../schema-initializer/SchemaInitializer';
describe('SchemaInitializer', () => {
it('should initialize with default items when no options provided', () => {
const schema = new SchemaInitializer({ name: 'schema0' });
expect(schema.items).toEqual([]);
});
it('should initialize with provided items', () => {
const schema = new SchemaInitializer({ type: 'item', items: [{ name: 'test', type: 'item' }], name: 'schema1' });
expect(schema.items).toEqual([{ type: 'item', name: 'test' }]);
});
it('should add item with unique name', () => {
const schema = new SchemaInitializer({ items: [], name: 'schema2' });
schema.add('item1', { type: 'item', test: true });
expect(schema.items).toContainEqual({ type: 'item', name: 'item1', test: true });
});
it('should replace item with same name', () => {
const schema = new SchemaInitializer({
type: 'item',
items: [{ type: 'item', name: 'item1', test: false }],
name: 'schema3',
});
schema.add('item1', { type: 'item', test: true });
expect(schema.items).toContainEqual({ type: 'item', name: 'item1', test: true });
expect(schema.items.length).toBe(1);
});
it('should add children to the specified parent item', () => {
const schema = new SchemaInitializer({
type: 'item',
items: [{ type: 'item', name: 'parent', children: [] }],
name: 'schema4',
});
schema.add('parent.child', { type: 'item', test: true });
expect(schema.get('parent').children).toContainEqual({ type: 'item', name: 'child', test: true });
});
it('should get the item by nested name', () => {
const schema = new SchemaInitializer({
type: 'item',
items: [{ type: 'item', name: 'parent', children: [{ type: 'item', name: 'child', test: true }] }],
name: 'schema5',
});
expect(schema.get('parent.child')).toEqual({ type: 'item', name: 'child', test: true });
});
it('should return undefined for non-existent item', () => {
const schema = new SchemaInitializer({ type: 'item', items: [], name: 'schema6' });
expect(schema.get('nonexistent')).toBeUndefined();
});
it('should remove the specified item', () => {
const schema = new SchemaInitializer({
type: 'item',
items: [{ type: 'item', name: 'toRemove', test: true }],
name: 'schema7',
});
schema.remove('toRemove');
expect(schema.items).not.toContainEqual({ type: 'item', name: 'toRemove', test: true });
});
it('should remove the specified nested item', () => {
const schema = new SchemaInitializer({
type: 'item',
items: [{ type: 'item', name: 'parent', children: [{ type: 'item', name: 'toRemove', test: true }] }],
name: 'schema8',
});
schema.remove('parent.toRemove');
expect(schema.get('parent').children).not.toContainEqual({ type: 'item', name: 'toRemove', test: true });
});
});

View File

@ -43,6 +43,23 @@ describe('SchemaInitializer', () => {
}); });
}); });
// 为了能让旧版插件代码正常工作操作按钮拍平后https://nocobase.feishu.cn/wiki/O7pjwSbBEigpOWkY9s5c03Yenkh需要满足下面的测试用例
test('add an item with nested name', () => {
// 等同于 initializer.add('item1', { title: 'item1 title' });
initializer.add('parent.item1', { title: 'item1 title' });
// 等同于 initializer.get('item1')
expect(initializer.get('parent.item1')).toEqual({
name: 'item1',
title: 'item1 title',
});
expect(initializer.get('item1')).toEqual({
name: 'item1',
title: 'item1 title',
});
expect(initializer.get('parent')).toBe(undefined);
});
test('updates a nested item if it already exists', () => { test('updates a nested item if it already exists', () => {
initializer.add('parent', { title: 'parent title' }); initializer.add('parent', { title: 'parent title' });
initializer.add('parent.item1', { title: 'title' }); initializer.add('parent.item1', { title: 'title' });

View File

@ -10,7 +10,7 @@
import { SchemaInitializer } from './SchemaInitializer'; import { SchemaInitializer } from './SchemaInitializer';
/** /**
* @deprecated * @deprecated - name使
* *
* SchemaInitializer name Schema * SchemaInitializer name Schema
* 使 Schema 使 * 使 Schema 使
@ -99,7 +99,7 @@ const oldToNewNameMap = {
/** /**
* schema x-initializer * schema x-initializer
* *
* @param oldOrNewName x-initializer * @param oldOrNewName x-initializer
* @param newName * @param newName
*/ */

View File

@ -24,14 +24,20 @@ export class SchemaInitializer<P1 = ButtonProps, P2 = {}> {
add(name: string, item: SchemaInitializerItemTypeWithoutName) { add(name: string, item: SchemaInitializerItemTypeWithoutName) {
const arr = name.split('.'); const arr = name.split('.');
const data: any = { ...item, name: arr[arr.length - 1] }; const itemName = arr[arr.length - 1];
if (arr.length === 1) { const data: any = { ...item, name: itemName };
const pushData = (name: string, data: any) => {
const index = this.items.findIndex((item: any) => item.name === name); const index = this.items.findIndex((item: any) => item.name === name);
if (index === -1) { if (index === -1) {
this.items.push(data); this.items.push(data);
} else { } else {
this.items[index] = data; this.items[index] = data;
} }
};
if (arr.length === 1) {
pushData(itemName, data);
return; return;
} }
@ -48,25 +54,28 @@ export class SchemaInitializer<P1 = ButtonProps, P2 = {}> {
} else { } else {
parentItem.children[index] = data; parentItem.children[index] = data;
} }
// 这里是为了兼容这个改动https://nocobase.feishu.cn/wiki/O7pjwSbBEigpOWkY9s5c03Yenkh
} else {
pushData(itemName, data);
} }
} }
get(nestedName: string): SchemaInitializerItemType | undefined { get(nestedName: string): SchemaInitializerItemType | undefined {
if (!nestedName) return undefined; if (!nestedName) return undefined;
const arr = nestedName.split('.'); const arr = nestedName.split('.');
let current: any = this.items; let current: any = { children: this.items };
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
const name = arr[i]; const name = arr[i];
current = current.find((item) => item.name === name); const _current = current.children?.find((item) => item.name === name);
if (!current || i === arr.length - 1) {
return current; if (_current) {
current = _current;
} }
if (current.children) { if (i === arr.length - 1) {
current = current.children; return _current;
} else {
return undefined;
} }
} }
} }

View File

@ -12,7 +12,6 @@ import { Schema, useField } from '@formily/react';
import { Spin } from 'antd'; import { Spin } from 'antd';
import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react'; import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';
import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps'; import { withDynamicSchemaProps } from '../application/hoc/withDynamicSchemaProps';
import { useCollection_deprecated } from '../collection-manager';
import { import {
CollectionRecord, CollectionRecord,
useCollectionManager, useCollectionManager,
@ -20,8 +19,8 @@ import {
useCollectionRecord, useCollectionRecord,
} from '../data-source'; } from '../data-source';
import { useTreeParentRecord } from '../modules/blocks/data-blocks/table/TreeRecordProvider'; import { useTreeParentRecord } from '../modules/blocks/data-blocks/table/TreeRecordProvider';
import { RecordProvider, useRecord } from '../record-provider'; import { RecordProvider } from '../record-provider';
import { useActionContext, useDesignable } from '../schema-component'; import { useActionContext } from '../schema-component';
import { Templates as DataTemplateSelect } from '../schema-component/antd/form-v2/Templates'; import { Templates as DataTemplateSelect } from '../schema-component/antd/form-v2/Templates';
import { BlockProvider, useBlockRequestContext } from './BlockProvider'; import { BlockProvider, useBlockRequestContext } from './BlockProvider';
import { TemplateBlockProvider } from './TemplateBlockProvider'; import { TemplateBlockProvider } from './TemplateBlockProvider';
@ -125,27 +124,8 @@ export const useIsDetailBlock = () => {
}; };
export const FormBlockProvider = withDynamicSchemaProps((props) => { export const FormBlockProvider = withDynamicSchemaProps((props) => {
const record = useRecord();
const parentRecordData = useCollectionParentRecordData(); const parentRecordData = useCollectionParentRecordData();
const { collection, isCusomeizeCreate, parentRecord } = props; const { parentRecord } = props;
const { __collection } = record;
const currentCollection = useCollection_deprecated();
const { designable } = useDesignable();
const isDetailBlock = useIsDetailBlock();
let detailFlag = false;
if (isDetailBlock) {
detailFlag = true;
if (!designable && __collection) {
detailFlag = __collection === collection;
}
}
const createFlag =
(currentCollection.name === (collection?.name || collection) && !isDetailBlock) ||
!currentCollection.name ||
!collection;
if (!detailFlag && !createFlag && !isCusomeizeCreate) {
return null;
}
return ( return (
<TemplateBlockProvider> <TemplateBlockProvider>

View File

@ -39,6 +39,8 @@ export interface AllDataBlockProps {
requestService?: UseRequestService<any>; requestService?: UseRequestService<any>;
requestOptions?: UseRequestOptions; requestOptions?: UseRequestOptions;
dataLoadingMode?: 'auto' | 'manual'; dataLoadingMode?: 'auto' | 'manual';
/** 如果为 true则区块会被隐藏 */
hidden?: boolean;
[index: string]: any; [index: string]: any;
} }
@ -149,9 +151,13 @@ export const AssociationOrCollectionProvider = (props: {
export const DataBlockProvider: FC<DataBlockProviderProps & { children?: ReactNode }> = withDynamicSchemaProps( export const DataBlockProvider: FC<DataBlockProviderProps & { children?: ReactNode }> = withDynamicSchemaProps(
(props) => { (props) => {
const { collection, association, dataSource, children, ...resets } = props as Partial<AllDataBlockProps>; const { collection, association, dataSource, children, hidden, ...resets } = props as Partial<AllDataBlockProps>;
const { dn } = useDesignable(); const { dn } = useDesignable();
if (hidden) {
return null;
}
return ( return (
<DataBlockContext.Provider <DataBlockContext.Provider
value={{ value={{

View File

@ -628,6 +628,8 @@
"Current user": "Current user", "Current user": "Current user",
"Current role": "Current role", "Current role": "Current role",
"Current record": "Current record", "Current record": "Current record",
"Current collection": "Current collection",
"Other collections": "Other collections",
"Current popup record": "Current popup record", "Current popup record": "Current popup record",
"Associated records": "Associated records", "Associated records": "Associated records",
"Parent record": "Parent record", "Parent record": "Parent record",

View File

@ -617,6 +617,8 @@
"Current user": "Usuario actual", "Current user": "Usuario actual",
"Current role": "Rol actual", "Current role": "Rol actual",
"Current record": "Registro actual", "Current record": "Registro actual",
"Current collection": "Colección actual",
"Other collections": "Otras colecciones",
"Current popup record": "Registro actual del popup", "Current popup record": "Registro actual del popup",
"Associated records": "Registros asociados", "Associated records": "Registros asociados",
"Parent record": "Registro padre", "Parent record": "Registro padre",

View File

@ -614,6 +614,8 @@
"Current user": "Utilisateur actuel", "Current user": "Utilisateur actuel",
"Current role": "Rôle actuel", "Current role": "Rôle actuel",
"Current record": "Enregistrement actuel", "Current record": "Enregistrement actuel",
"Current collection": "Collection actuelle",
"Other collections": "Autres collections",
"Current popup record": "Enregistrement popup actuel", "Current popup record": "Enregistrement popup actuel",
"Associated records": "Enregistrements associés", "Associated records": "Enregistrements associés",
"Parent record": "Enregistrement parent", "Parent record": "Enregistrement parent",

View File

@ -517,6 +517,8 @@
"Current user": "現在のユーザー", "Current user": "現在のユーザー",
"Current role": "現在の役割", "Current role": "現在の役割",
"Current record": "現在のレコード", "Current record": "現在のレコード",
"Current collection": "現在のコレクション",
"Other collections": "他のコレクション",
"Current popup record": "現在のポップアップレコード", "Current popup record": "現在のポップアップレコード",
"Associated records": "関連付けられたレコード", "Associated records": "関連付けられたレコード",
"Popup close method": "ポップアップを閉じる方法", "Popup close method": "ポップアップを閉じる方法",

View File

@ -642,6 +642,8 @@
"Current user": "현재 사용자", "Current user": "현재 사용자",
"Current role": "현재 역할", "Current role": "현재 역할",
"Current record": "현재 레코드", "Current record": "현재 레코드",
"Current collection": "현재 데이터 테이블",
"Other collections": "기타 데이터 테이블",
"Current popup record": "현재 팝업 레코드", "Current popup record": "현재 팝업 레코드",
"Associated records": "관련 레코드", "Associated records": "관련 레코드",
"Parent record": "상위 레코드", "Parent record": "상위 레코드",

View File

@ -452,6 +452,8 @@
"Current user": "Текущий пользователь", "Current user": "Текущий пользователь",
"Current role": "Текущая роль", "Current role": "Текущая роль",
"Current record": "Текущая запись", "Current record": "Текущая запись",
"Current collection": "Текущая коллекция",
"Other collections": "Другие коллекции",
"Current popup record": "Текущая запись всплывающего окна", "Current popup record": "Текущая запись всплывающего окна",
"Associated records": "Связанные записи", "Associated records": "Связанные записи",
"Parent record": "Родительская запись", "Parent record": "Родительская запись",

View File

@ -452,6 +452,8 @@
"Current user": "Seçili kullanıcı", "Current user": "Seçili kullanıcı",
"Current role": "Seçili rol", "Current role": "Seçili rol",
"Current record": "Seçili kayıt", "Current record": "Seçili kayıt",
"Current collection": "Seçili koleksiyon",
"Other collections": "Diğer koleksiyonlar",
"Current popup record": "Açılır pencere kaydı", "Current popup record": "Açılır pencere kaydı",
"Associated records": "İlişkili kayıtlar", "Associated records": "İlişkili kayıtlar",
"Parent record": "Üst kayıt", "Parent record": "Üst kayıt",

View File

@ -634,6 +634,8 @@
"Current user": "Поточний користувач", "Current user": "Поточний користувач",
"Current role": "Поточна роль", "Current role": "Поточна роль",
"Current record": "Поточний запис", "Current record": "Поточний запис",
"Current collection": "Поточна колекція",
"Other collections": "Інші колекції",
"Current popup record": "Поточний запис спливаючого вікна", "Current popup record": "Поточний запис спливаючого вікна",
"Associated records": "Пов'язані записи", "Associated records": "Пов'язані записи",
"Parent record": "Батьківський запис", "Parent record": "Батьківський запис",

View File

@ -646,6 +646,8 @@
"Current user": "当前用户", "Current user": "当前用户",
"Current role": "当前角色", "Current role": "当前角色",
"Current record": "当前记录", "Current record": "当前记录",
"Current collection": "当前数据表",
"Other collections": "其他数据表",
"Current popup record": "当前弹窗记录", "Current popup record": "当前弹窗记录",
"Associated records": "关联记录", "Associated records": "关联记录",
"Parent record": "上级记录", "Parent record": "上级记录",

View File

@ -642,6 +642,8 @@
"Current user": "當前使用者", "Current user": "當前使用者",
"Current role": "當前角色", "Current role": "當前角色",
"Current record": "當前記錄", "Current record": "當前記錄",
"Current collection": "當前資料表",
"Other collections": "其他資料表",
"Current popup record": "當前彈窗記錄", "Current popup record": "當前彈窗記錄",
"Associated records": "關聯記錄", "Associated records": "關聯記錄",
"Parent record": "上級記錄", "Parent record": "上級記錄",

View File

@ -8,7 +8,7 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer'; import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
export const CreateChildInitializer = (props) => { export const CreateChildInitializer = (props) => {
const schema = { const schema = {
type: 'void', type: 'void',
@ -64,5 +64,5 @@ export const CreateChildInitializer = (props) => {
}, },
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -9,7 +9,7 @@
import React from 'react'; import React from 'react';
import { useSchemaInitializerItem } from '../../../application'; import { useSchemaInitializerItem } from '../../../application';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer'; import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
export const CreateActionInitializer = () => { export const CreateActionInitializer = () => {
const schema = { const schema = {
@ -67,5 +67,5 @@ export const CreateActionInitializer = () => {
}, },
}; };
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
return <ActionInitializer {...itemConfig} item={itemConfig} schema={schema} />; return <ActionInitializerItem {...itemConfig} item={itemConfig} schema={schema} />;
}; };

View File

@ -7,15 +7,12 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { useTranslation } from 'react-i18next';
import { CompatibleSchemaInitializer } from '../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCollection } from '../../../data-source/collection/CollectionProvider';
import { gridRowColWrap } from '../../../schema-initializer/utils'; import { gridRowColWrap } from '../../../schema-initializer/utils';
/** const commonOptions = {
* @deprecated
* use `createFormBlockInitializers` instead
*/
export const createFormBlockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CreateFormBlockInitializers',
wrap: gridRowColWrap, wrap: gridRowColWrap,
title: '{{t("Add block")}}', title: '{{t("Add block")}}',
icon: 'PlusOutlined', icon: 'PlusOutlined',
@ -24,13 +21,36 @@ export const createFormBlockInitializers_deprecated = new CompatibleSchemaInitia
type: 'itemGroup', type: 'itemGroup',
title: '{{t("Data blocks")}}', title: '{{t("Data blocks")}}',
name: 'dataBlocks', name: 'dataBlocks',
children: [ useChildren() {
{ const currentCollection = useCollection();
name: 'form', const { t } = useTranslation();
title: '{{t("Form")}}',
Component: 'CreateFormBlockInitializer', return [
}, {
], name: 'form',
title: '{{t("Form")}}',
Component: 'FormBlockInitializer',
collectionName: currentCollection.name,
dataSource: currentCollection.dataSource,
componentProps: {
filterCollections({ collection, associationField }) {
if (associationField) {
return false;
}
if (collection.name === currentCollection.name) {
return true;
}
},
showAssociationFields: true,
onlyCurrentDataSource: true,
hideSearch: true,
componentType: 'FormItem',
currentText: t('Current collection'),
otherText: t('Other collections'),
},
},
];
},
}, },
{ {
type: 'itemGroup', type: 'itemGroup',
@ -45,40 +65,21 @@ export const createFormBlockInitializers_deprecated = new CompatibleSchemaInitia
], ],
}, },
], ],
};
/**
* @deprecated
* use `createFormBlockInitializers` instead
*/
export const createFormBlockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CreateFormBlockInitializers',
...commonOptions,
}); });
export const createFormBlockInitializers = new CompatibleSchemaInitializer( export const createFormBlockInitializers = new CompatibleSchemaInitializer(
{ {
name: 'popup:addNew:addBlock', name: 'popup:addNew:addBlock',
wrap: gridRowColWrap, ...commonOptions,
title: '{{t("Add block")}}',
icon: 'PlusOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Data blocks")}}',
name: 'dataBlocks',
children: [
{
name: 'form',
title: '{{t("Form")}}',
Component: 'CreateFormBlockInitializer',
},
],
},
{
type: 'itemGroup',
title: '{{t("Other blocks")}}',
name: 'otherBlocks',
children: [
{
name: 'markdown',
title: '{{t("Markdown")}}',
Component: 'MarkdownBlockInitializer',
},
],
},
],
}, },
createFormBlockInitializers_deprecated, createFormBlockInitializers_deprecated,
); );

View File

@ -1,68 +0,0 @@
/**
* 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 React from 'react';
import { useSchemaInitializerItem } from '../../../application';
import { BlockInitializer } from '../../../schema-initializer/items/BlockInitializer';
export const CustomizeAddRecordActionInitializer = () => {
const schema = {
type: 'void',
title: '{{t("Add record")}}',
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:addRecord',
'x-component': 'Action',
'x-action': 'customize:create',
'x-component-props': {
openMode: 'drawer',
icon: 'PlusOutlined',
},
properties: {
drawer: {
type: 'void',
title: '{{t("Add record")}}',
'x-component': 'Action.Container',
'x-component-props': {
className: 'nb-action-popup',
},
properties: {
tabs: {
type: 'void',
'x-component': 'Tabs',
'x-component-props': {},
'x-initializer': 'popup:addTab',
'x-initializer-props': {
gridInitializer: 'popup:addRecord:addBlock',
},
properties: {
tab1: {
type: 'void',
title: '{{t("Add record")}}',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
properties: {
grid: {
type: 'void',
'x-component': 'Grid',
'x-initializer': 'popup:addRecord:addBlock',
properties: {},
},
},
},
},
},
},
},
},
};
const itemConfig = useSchemaInitializerItem();
return <BlockInitializer {...itemConfig} schema={schema} item={itemConfig} />;
};

View File

@ -10,12 +10,7 @@
import { CompatibleSchemaInitializer } from '../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../application/schema-initializer/CompatibleSchemaInitializer';
import { gridRowColWrap } from '../../../schema-initializer/utils'; import { gridRowColWrap } from '../../../schema-initializer/utils';
/** const commonOptions = {
* @deprecated
* use `customizeCreateFormBlockInitializers` instead
*/
export const customizeCreateFormBlockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CusomeizeCreateFormBlockInitializers',
wrap: gridRowColWrap, wrap: gridRowColWrap,
title: '{{t("Add block")}}', title: '{{t("Add block")}}',
icon: 'PlusOutlined', icon: 'PlusOutlined',
@ -29,6 +24,7 @@ export const customizeCreateFormBlockInitializers_deprecated = new CompatibleSch
name: 'form', name: 'form',
title: '{{t("Form")}}', title: '{{t("Form")}}',
Component: 'FormBlockInitializer', Component: 'FormBlockInitializer',
/** 表示是通过 Other collections 选项创建的区块(由于历史遗留问题,这里的命名暂不做更改) */
isCusomeizeCreate: true, isCusomeizeCreate: true,
}, },
], ],
@ -46,41 +42,21 @@ export const customizeCreateFormBlockInitializers_deprecated = new CompatibleSch
], ],
}, },
], ],
};
/**
* @deprecated
* use `customizeCreateFormBlockInitializers` instead
*/
export const customizeCreateFormBlockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CusomeizeCreateFormBlockInitializers',
...commonOptions,
}); });
export const customizeCreateFormBlockInitializers = new CompatibleSchemaInitializer( export const customizeCreateFormBlockInitializers = new CompatibleSchemaInitializer(
{ {
name: 'popup:addRecord:addBlock', name: 'popup:addRecord:addBlock',
wrap: gridRowColWrap, ...commonOptions,
title: '{{t("Add block")}}',
icon: 'PlusOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Data blocks")}}',
name: 'dataBlocks',
children: [
{
name: 'form',
title: '{{t("Form")}}',
Component: 'FormBlockInitializer',
isCusomeizeCreate: true,
},
],
},
{
type: 'itemGroup',
title: '{{t("Other blocks")}}',
name: 'otherBlocks',
children: [
{
name: 'markdown',
title: '{{t("Markdown")}}',
Component: 'MarkdownBlockInitializer',
},
],
},
],
}, },
customizeCreateFormBlockInitializers_deprecated, customizeCreateFormBlockInitializers_deprecated,
); );

View File

@ -9,7 +9,6 @@
import React from 'react'; import React from 'react';
import { useCollection_deprecated } from '../../../collection-manager'; import { useCollection_deprecated } from '../../../collection-manager';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer'; import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
export const BulkDestroyActionInitializer = (props) => { export const BulkDestroyActionInitializer = (props) => {

View File

@ -8,7 +8,6 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer'; import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
export const DestroyActionInitializer = (props) => { export const DestroyActionInitializer = (props) => {

View File

@ -8,8 +8,7 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
export const DisassociateActionInitializer = (props) => { export const DisassociateActionInitializer = (props) => {
const schema = { const schema = {
@ -31,5 +30,5 @@ export const DisassociateActionInitializer = (props) => {
triggerWorkflows: [], triggerWorkflows: [],
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -8,7 +8,6 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer'; import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
export const FilterActionInitializer = (props) => { export const FilterActionInitializer = (props) => {

View File

@ -1,40 +0,0 @@
/**
* 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 React from 'react';
import { BlockInitializer } from '../../../schema-initializer/items';
import { useSchemaInitializerItem } from '../../../application';
export const SaveRecordActionInitializer = () => {
const schema = {
title: '{{ t("Save record") }}',
'x-action': 'customize:save',
'x-component': 'Action',
'x-use-component-props': 'useCreateActionProps',
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:saveRecord',
'x-designer-props': {
modalTip:
'{{ t("When the button is clicked, the following fields will be assigned and saved together with the fields in the form. If there are overlapping fields, the value here will overwrite the value in the form.") }}',
},
'x-action-settings': {
assignedValues: {},
skipValidator: false,
onSuccess: {
manualClose: true,
redirecting: false,
successMessage: '{{t("Submitted successfully")}}',
},
triggerWorkflows: [],
},
};
const itemConfig = useSchemaInitializerItem();
return <BlockInitializer {...itemConfig} schema={schema} item={itemConfig} />;
};

View File

@ -15,13 +15,17 @@ import {
AfterSuccess, AfterSuccess,
AssignedFieldValues, AssignedFieldValues,
ButtonEditor, ButtonEditor,
RefreshDataBlockRequest,
RemoveButton, RemoveButton,
SecondConFirm, SecondConFirm,
SkipValidation, SkipValidation,
WorkflowConfig, WorkflowConfig,
RefreshDataBlockRequest,
} from '../../../schema-component/antd/action/Action.Designer'; } from '../../../schema-component/antd/action/Action.Designer';
/**
* @deprecated
* Schema
*/
export const customizeSaveRecordActionSettings = new SchemaSettings({ export const customizeSaveRecordActionSettings = new SchemaSettings({
name: 'actionSettings:saveRecord', name: 'actionSettings:saveRecord',
items: [ items: [

View File

@ -8,7 +8,7 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer'; import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
export const CreateSubmitActionInitializer = (props) => { export const CreateSubmitActionInitializer = (props) => {
const schema = { const schema = {
@ -26,5 +26,5 @@ export const CreateSubmitActionInitializer = (props) => {
triggerWorkflows: [], triggerWorkflows: [],
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -8,8 +8,7 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
export const UpdateSubmitActionInitializer = (props) => { export const UpdateSubmitActionInitializer = (props) => {
const schema = { const schema = {
@ -28,5 +27,5 @@ export const UpdateSubmitActionInitializer = (props) => {
triggerWorkflows: [], triggerWorkflows: [],
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -7,22 +7,26 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { useFieldSchema, useField, connect, mapProps, ISchema } from '@formily/react'; import { ISchema, connect, mapProps, useField, useFieldSchema } from '@formily/react';
import { isValid } from '@formily/shared'; import { isValid } from '@formily/shared';
import React, { useEffect, useState } from 'react';
import { Tree as AntdTree } from 'antd'; import { Tree as AntdTree } from 'antd';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSchemaToolbar } from '../../../application'; import { useSchemaToolbar } from '../../../application';
import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings'; import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings';
import { useCollection_deprecated } from '../../../collection-manager';
import { useDesignable } from '../../../schema-component';
import { import {
AfterSuccess,
AssignedFieldValues,
ButtonEditor, ButtonEditor,
RefreshDataBlockRequest,
RemoveButton, RemoveButton,
SecondConFirm, SecondConFirm,
SkipValidation,
WorkflowConfig, WorkflowConfig,
} from '../../../schema-component/antd/action/Action.Designer'; } from '../../../schema-component/antd/action/Action.Designer';
import { useTranslation } from 'react-i18next';
import { useDesignable } from '../../../schema-component';
import { useCollectionState } from '../../../schema-settings/DataTemplates/hooks/useCollectionState'; import { useCollectionState } from '../../../schema-settings/DataTemplates/hooks/useCollectionState';
import { useCollection_deprecated } from '../../../collection-manager';
import { SchemaSettingsModalItem } from '../../../schema-settings/SchemaSettings'; import { SchemaSettingsModalItem } from '../../../schema-settings/SchemaSettings';
const Tree = connect( const Tree = connect(
@ -132,6 +136,7 @@ export function SaveMode() {
/> />
); );
} }
export const createSubmitActionSettings = new SchemaSettings({ export const createSubmitActionSettings = new SchemaSettings({
name: 'actionSettings:createSubmit', name: 'actionSettings:createSubmit',
items: [ items: [
@ -159,6 +164,31 @@ export const createSubmitActionSettings = new SchemaSettings({
name: 'saveMode', name: 'saveMode',
Component: SaveMode, Component: SaveMode,
}, },
{
name: 'assignFieldValues',
Component: AssignedFieldValues,
},
{
name: 'skipRequiredValidation',
Component: SkipValidation,
},
{
name: 'afterSuccessfulSubmission',
Component: AfterSuccess,
useVisible() {
const fieldSchema = useFieldSchema();
return isValid(fieldSchema?.['x-action-settings']?.onSuccess);
},
},
{
name: 'refreshDataBlockRequest',
Component: RefreshDataBlockRequest,
useComponentProps() {
return {
isPopupAction: false,
};
},
},
{ {
name: 'remove', name: 'remove',
sort: 100, sort: 100,

View File

@ -12,9 +12,13 @@ import { isValid } from '@formily/shared';
import { isInitializersSame, useSchemaToolbar } from '../../../application'; import { isInitializersSame, useSchemaToolbar } from '../../../application';
import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings'; import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings';
import { import {
AfterSuccess,
AssignedFieldValues,
ButtonEditor, ButtonEditor,
RefreshDataBlockRequest,
RemoveButton, RemoveButton,
SecondConFirm, SecondConFirm,
SkipValidation,
WorkflowConfig, WorkflowConfig,
} from '../../../schema-component/antd/action/Action.Designer'; } from '../../../schema-component/antd/action/Action.Designer';
import { SaveMode } from './createSubmitActionSettings'; import { SaveMode } from './createSubmitActionSettings';
@ -42,6 +46,31 @@ export const updateSubmitActionSettings = new SchemaSettings({
return isValid(fieldSchema?.['x-action-settings']?.triggerWorkflows); return isValid(fieldSchema?.['x-action-settings']?.triggerWorkflows);
}, },
}, },
{
name: 'assignFieldValues',
Component: AssignedFieldValues,
},
{
name: 'skipRequiredValidation',
Component: SkipValidation,
},
{
name: 'afterSuccessfulSubmission',
Component: AfterSuccess,
useVisible() {
const fieldSchema = useFieldSchema();
return isValid(fieldSchema?.['x-action-settings']?.onSuccess);
},
},
{
name: 'refreshDataBlockRequest',
Component: RefreshDataBlockRequest,
useComponentProps() {
return {
isPopupAction: false,
};
},
},
{ {
name: 'remove', name: 'remove',
sort: 100, sort: 100,

View File

@ -8,8 +8,7 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
export const UpdateActionInitializer = (props) => { export const UpdateActionInitializer = (props) => {
const schema = { const schema = {
@ -59,5 +58,5 @@ export const UpdateActionInitializer = (props) => {
}, },
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -8,8 +8,7 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
export const ViewActionInitializer = (props) => { export const ViewActionInitializer = (props) => {
const schema = { const schema = {
@ -58,5 +57,5 @@ export const ViewActionInitializer = (props) => {
}, },
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -9,13 +9,7 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
/** const commonOptions = {
* @deprecated
* use `detailsActionInitializers` instead
*
*/
export const detailsActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'DetailsActionInitializers',
title: '{{t("Configure actions")}}', title: '{{t("Configure actions")}}',
icon: 'SettingOutlined', icon: 'SettingOutlined',
style: { style: {
@ -50,17 +44,17 @@ export const detailsActionInitializers_deprecated = new CompatibleSchemaInitiali
}, },
], ],
}, },
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
name: 'customize',
title: '{{t("Customize")}}',
children: [],
},
], ],
};
/**
* @deprecated
* use `detailsActionInitializers` instead
*
*/
export const detailsActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'DetailsActionInitializers',
...commonOptions,
}); });
/** /**
@ -70,41 +64,7 @@ export const detailsActionInitializers_deprecated = new CompatibleSchemaInitiali
export const detailsActionInitializers = new CompatibleSchemaInitializer( export const detailsActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'detailsWithPaging:configureActions', name: 'detailsWithPaging:configureActions',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'itemGroup',
title: '{{t("Enable actions")}}',
name: 'enableActions',
children: [
{
name: 'edit',
title: '{{t("Edit")}}',
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
'x-component-props': {
type: 'primary',
},
},
},
{
name: 'delete',
title: '{{t("Delete")}}',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
},
},
],
},
],
}, },
detailsActionInitializers_deprecated, detailsActionInitializers_deprecated,
); );

View File

@ -7,9 +7,16 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { createBlockInPage, expect, oneEmptyDetailsBlock, test } from '@nocobase/test/e2e'; import { Page, createBlockInPage, expect, oneEmptyDetailsBlock, test } from '@nocobase/test/e2e';
import { oneEmptyTableWithUsers } from './templatesOfBug'; import { oneEmptyTableWithUsers } from './templatesOfBug';
const deleteButton = async (page: Page, name: string) => {
await page.getByRole('button', { name }).hover();
await page.getByRole('button', { name }).getByLabel('designer-schema-settings-').hover();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
};
test.describe('where multi data details block can be added', () => { test.describe('where multi data details block can be added', () => {
test('page', async ({ page, mockPage }) => { test('page', async ({ page, mockPage }) => {
await mockPage().goto(); await mockPage().goto();
@ -109,20 +116,13 @@ test.describe('configure actions', () => {
await page.getByRole('menuitem', { name: 'Edit' }).click(); await page.getByRole('menuitem', { name: 'Edit' }).click();
await page.getByRole('menuitem', { name: 'Delete' }).click(); await page.getByRole('menuitem', { name: 'Delete' }).click();
await expect(page.getByRole('menuitem', { name: 'Edit' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Edit' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Edit' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Delete' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Delete' })).toBeVisible();
// delete buttons // delete buttons
await page.getByLabel('schema-initializer-ActionBar-detailsWithPaging:configureActions-general').hover(); await deleteButton(page, 'Edit');
await page.getByRole('menuitem', { name: 'Edit' }).click(); await deleteButton(page, 'Delete');
await page.getByRole('menuitem', { name: 'Delete' }).click();
await expect(page.getByRole('menuitem', { name: 'Edit' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).not.toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Edit' })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Edit' })).not.toBeVisible();

View File

@ -15,13 +15,7 @@ const useVisibleCollection = () => {
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql'; return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
}; };
/** const commonOptions = {
* @deprecated
* use `readPrettyFormActionInitializers` instead
*
*/
export const readPrettyFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ReadPrettyFormActionInitializers',
title: '{{t("Configure actions")}}', title: '{{t("Configure actions")}}',
icon: 'SettingOutlined', icon: 'SettingOutlined',
style: { style: {
@ -29,154 +23,72 @@ export const readPrettyFormActionInitializers_deprecated = new CompatibleSchemaI
}, },
items: [ items: [
{ {
type: 'itemGroup', title: '{{t("Edit")}}',
name: 'enableActions', name: 'edit',
title: '{{t("Enable actions")}}', Component: 'UpdateActionInitializer',
children: [ schema: {
{ 'x-component': 'Action',
title: '{{t("Edit")}}', 'x-decorator': 'ACLActionProvider',
name: 'edit', 'x-component-props': {
Component: 'UpdateActionInitializer', type: 'primary',
schema: {
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
'x-component-props': {
type: 'primary',
},
},
useVisible: useVisibleCollection,
}, },
{ },
title: '{{t("Delete")}}', useVisible: useVisibleCollection,
name: 'delete',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
},
useVisible: useVisibleCollection,
},
],
}, },
{ {
name: 'divider', title: '{{t("Delete")}}',
type: 'divider', name: 'delete',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
},
useVisible: useVisibleCollection,
}, },
{ {
type: 'subMenu', name: 'popup',
name: 'customize', title: '{{t("Popup")}}',
title: '{{t("Customize")}}', Component: 'PopupActionInitializer',
children: [ useComponentProps() {
{ return {
name: 'popup', 'x-component': 'Action',
title: '{{t("Popup")}}', };
Component: 'PopupActionInitializer', },
useComponentProps() { },
return { {
'x-component': 'Action', name: 'updateRecord',
}; title: '{{t("Update record")}}',
}, Component: 'UpdateRecordActionInitializer',
}, useComponentProps() {
{ return {
name: 'updateRecord', 'x-component': 'Action',
title: '{{t("Update record")}}', };
Component: 'UpdateRecordActionInitializer', },
useComponentProps() { useVisible: useVisibleCollection,
return { },
'x-component': 'Action', {
}; name: 'customRequest',
}, title: '{{t("Custom request")}}',
useVisible: useVisibleCollection, Component: 'CustomRequestInitializer',
}, useVisible: useVisibleCollection,
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
useVisible: useVisibleCollection,
},
],
}, },
], ],
};
/**
* @deprecated
* use `readPrettyFormActionInitializers` instead
*
*/
export const readPrettyFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ReadPrettyFormActionInitializers',
...commonOptions,
}); });
export const readPrettyFormActionInitializers = new CompatibleSchemaInitializer( export const readPrettyFormActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'details:configureActions', name: 'details:configureActions',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'itemGroup',
name: 'enableActions',
title: '{{t("Enable actions")}}',
children: [
{
title: '{{t("Edit")}}',
name: 'edit',
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
'x-component-props': {
type: 'primary',
},
},
useVisible: useVisibleCollection,
},
{
title: '{{t("Delete")}}',
name: 'delete',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
},
useVisible: useVisibleCollection,
},
],
},
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
name: 'customize',
title: '{{t("Customize")}}',
children: [
{
name: 'popup',
title: '{{t("Popup")}}',
Component: 'PopupActionInitializer',
useComponentProps() {
return {
'x-component': 'Action',
};
},
},
{
name: 'updateRecord',
title: '{{t("Update record")}}',
Component: 'UpdateRecordActionInitializer',
useComponentProps() {
return {
'x-component': 'Action',
};
},
useVisible: useVisibleCollection,
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
useVisible: useVisibleCollection,
},
],
},
],
}, },
readPrettyFormActionInitializers_deprecated, readPrettyFormActionInitializers_deprecated,
); );

View File

@ -54,12 +54,7 @@ const AssociatedFields = () => {
return <SchemaInitializerChildren>{schema}</SchemaInitializerChildren>; return <SchemaInitializerChildren>{schema}</SchemaInitializerChildren>;
}; };
/** const commonOptions = {
* @deprecated
* use `readPrettyFormItemInitializers` instead
*/
export const readPrettyFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ReadPrettyFormItemInitializers',
wrap: gridRowColWrap, wrap: gridRowColWrap,
icon: 'SettingOutlined', icon: 'SettingOutlined',
title: '{{t("Configure fields")}}', title: '{{t("Configure fields")}}',
@ -100,51 +95,21 @@ export const readPrettyFormItemInitializers_deprecated = new CompatibleSchemaIni
}, },
}, },
], ],
};
/**
* @deprecated
* use `readPrettyFormItemInitializers` instead
*/
export const readPrettyFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ReadPrettyFormItemInitializers',
...commonOptions,
}); });
export const readPrettyFormItemInitializers = new CompatibleSchemaInitializer( export const readPrettyFormItemInitializers = new CompatibleSchemaInitializer(
{ {
name: 'details:configureFields', name: 'details:configureFields',
wrap: gridRowColWrap, ...commonOptions,
icon: 'SettingOutlined',
title: '{{t("Configure fields")}}',
items: [
{
type: 'itemGroup',
name: 'displayFields',
title: '{{t("Display fields")}}',
useChildren: useFormItemInitializerFields,
},
{
name: 'parentCollectionFields',
Component: ParentCollectionFields,
},
{
name: 'associationFields',
Component: AssociatedFields,
},
{
name: 'divider',
type: 'divider',
},
{
name: 'addText',
title: '{{t("Add text")}}',
Component: 'BlockItemInitializer',
schema: {
type: 'void',
'x-editable': false,
'x-decorator': 'FormItem',
// 'x-designer': 'Markdown.Void.Designer',
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'blockSettings:markdown',
'x-component': 'Markdown.Void',
'x-component-props': {
content: '{{t("This is a demo text, **supports Markdown syntax**.")}}',
},
},
},
],
}, },
readPrettyFormItemInitializers_deprecated, readPrettyFormItemInitializers_deprecated,
); );

View File

@ -143,13 +143,11 @@ test.describe('configure fields', () => {});
async function createAction(page: Page, name: string) { async function createAction(page: Page, name: string) {
await page.getByLabel('schema-initializer-ActionBar-details:configureActions-general').hover(); await page.getByLabel('schema-initializer-ActionBar-details:configureActions-general').hover();
await page.getByRole('menuitem', { name: name }).click(); await page.getByRole('menuitem', { name: name }).click();
await expect(page.getByRole('menuitem', { name: name }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
} }
async function createCustomAction(page: Page, name: string) { async function createCustomAction(page: Page, name: string) {
await page.getByLabel('schema-initializer-ActionBar-details:configureActions-general').hover(); await page.getByLabel('schema-initializer-ActionBar-details:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: name }).click(); await page.getByRole('menuitem', { name: name }).click();
await page.mouse.move(0, 400); await page.mouse.move(0, 400);
} }

View File

@ -1,75 +0,0 @@
/**
* 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 { FormOutlined } from '@ant-design/icons';
import React from 'react';
import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
import { useCollection_deprecated } from '../../../../collection-manager';
import { useRecordCollectionDataSourceItems } from '../../../../schema-initializer/utils';
import { useSchemaTemplateManager } from '../../../../schema-templates';
import { createCreateFormBlockUISchema } from './createCreateFormBlockUISchema';
import { useAssociationName } from '../../../../data-source';
// TODO: `SchemaInitializerItem` items
export const CreateFormBlockInitializer = () => {
const itemConfig = useSchemaInitializerItem();
const { onCreateBlockSchema, componentType, createBlockSchema, ...others } = itemConfig;
const { getTemplateSchemaByMode } = useSchemaTemplateManager();
const { insert } = useSchemaInitializer();
const association = useAssociationName();
const collection = useCollection_deprecated();
return (
<SchemaInitializerItem
icon={<FormOutlined />}
{...others}
onClick={async ({ item }) => {
if (item.template) {
const s = await getTemplateSchemaByMode(item);
if (item.template.componentName === 'FormItem') {
const blockSchema = createCreateFormBlockUISchema(
association
? {
association,
dataSource: collection.dataSource,
templateSchema: s,
}
: {
collectionName: collection.name,
dataSource: collection.dataSource,
templateSchema: s,
},
);
if (item.mode === 'reference') {
blockSchema['x-template-key'] = item.template.key;
}
insert(blockSchema);
} else {
insert(s);
}
} else {
insert(
createCreateFormBlockUISchema(
association
? {
association,
dataSource: collection.dataSource,
}
: {
collectionName: collection.name,
dataSource: collection.dataSource,
},
),
);
}
}}
items={useRecordCollectionDataSourceItems('FormItem')}
/>
);
};

View File

@ -10,6 +10,7 @@
import { FormOutlined } from '@ant-design/icons'; import { FormOutlined } from '@ant-design/icons';
import React, { useCallback } from 'react'; import React, { useCallback } from 'react';
import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application'; import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
import { useAssociationName } from '../../../../data-source/collection/AssociationProvider';
import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection'; import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection';
import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer'; import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer';
import { createCreateFormBlockUISchema } from './createCreateFormBlockUISchema'; import { createCreateFormBlockUISchema } from './createCreateFormBlockUISchema';
@ -24,6 +25,8 @@ export const FormBlockInitializer = ({
showAssociationFields, showAssociationFields,
hideChildrenIfSingleCollection, hideChildrenIfSingleCollection,
hideOtherRecordsInPopup, hideOtherRecordsInPopup,
currentText,
otherText,
}: { }: {
filterCollections: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean; filterCollections: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean;
onlyCurrentDataSource: boolean; onlyCurrentDataSource: boolean;
@ -47,6 +50,10 @@ export const FormBlockInitializer = ({
* Other records * Other records
*/ */
hideOtherRecordsInPopup?: boolean; hideOtherRecordsInPopup?: boolean;
/** 用于更改 Current record 的文案 */
currentText?: string;
/** 用于更改 Other records 的文案 */
otherText?: string;
}) => { }) => {
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
const { createFormBlock, templateWrap } = useCreateFormBlock(); const { createFormBlock, templateWrap } = useCreateFormBlock();
@ -84,42 +91,84 @@ export const FormBlockInitializer = ({
showAssociationFields={showAssociationFields} showAssociationFields={showAssociationFields}
hideChildrenIfSingleCollection={hideChildrenIfSingleCollection} hideChildrenIfSingleCollection={hideChildrenIfSingleCollection}
hideOtherRecordsInPopup={hideOtherRecordsInPopup} hideOtherRecordsInPopup={hideOtherRecordsInPopup}
currentText={currentText}
otherText={otherText}
/> />
); );
}; };
export const useCreateFormBlock = () => { export const useCreateFormBlock = () => {
const { insert } = useSchemaInitializer(); const { insert } = useSchemaInitializer();
const itemConfig = useSchemaInitializerItem(); const association = useAssociationName();
const { isCusomeizeCreate: isCustomizeCreate } = itemConfig; const { isCusomeizeCreate: isCustomizeCreate } = useSchemaInitializerItem();
const createFormBlock = useCallback( const createFormBlock = useCallback(
({ item }) => { ({ item, fromOthersInPopup }) => {
insert( if (fromOthersInPopup) {
createCreateFormBlockUISchema({ insert(
collectionName: item.collectionName || item.name, createCreateFormBlockUISchema({
dataSource: item.dataSource, collectionName: item.collectionName || item.name,
isCusomeizeCreate: isCustomizeCreate, dataSource: item.dataSource,
}), isCusomeizeCreate: true,
); }),
);
} else {
insert(
createCreateFormBlockUISchema(
association
? {
association,
dataSource: item.dataSource,
isCusomeizeCreate: isCustomizeCreate,
}
: {
collectionName: item.collectionName || item.name,
dataSource: item.dataSource,
isCusomeizeCreate: isCustomizeCreate,
},
),
);
}
}, },
[insert, isCustomizeCreate], [association, insert, isCustomizeCreate],
); );
const templateWrap = useCallback( const templateWrap = useCallback(
(templateSchema, { item }) => { (templateSchema, { item, fromOthersInPopup }) => {
const schema = createCreateFormBlockUISchema({ let schema;
isCusomeizeCreate: isCustomizeCreate,
dataSource: item.dataSource, if (fromOthersInPopup) {
templateSchema: templateSchema, schema = createCreateFormBlockUISchema({
collectionName: item.name, dataSource: item.dataSource,
}); templateSchema: templateSchema,
collectionName: item.name,
isCusomeizeCreate: true,
});
} else {
schema = createCreateFormBlockUISchema(
association
? {
dataSource: item.dataSource,
templateSchema: templateSchema,
collectionName: item.name,
association,
isCusomeizeCreate: isCustomizeCreate,
}
: {
dataSource: item.dataSource,
templateSchema: templateSchema,
collectionName: item.name,
isCusomeizeCreate: isCustomizeCreate,
},
);
}
if (item.template && item.mode === 'reference') { if (item.template && item.mode === 'reference') {
schema['x-template-key'] = item.template.key; schema['x-template-key'] = item.template.key;
} }
return schema; return schema;
}, },
[isCustomizeCreate], [association, isCustomizeCreate],
); );
return { return {

View File

@ -62,7 +62,8 @@ test.describe('association form block', () => {
.getByLabel('schema-initializer-Grid-popup') .getByLabel('schema-initializer-Grid-popup')
.click(); .click();
await page.getByRole('menuitem', { name: 'form Form' }).click(); await page.getByRole('menuitem', { name: 'form Form' }).hover();
await page.getByRole('menuitem', { name: 'Current collection' }).click();
await expect(await page.getByLabel('block-item-CardItem-roles-form')).toBeVisible(); await expect(await page.getByLabel('block-item-CardItem-roles-form')).toBeVisible();
}); });
}); });

View File

@ -8,10 +8,17 @@
*/ */
import { uid } from '@formily/shared'; import { uid } from '@formily/shared';
import { createBlockInPage, expect, oneEmptyForm, test } from '@nocobase/test/e2e'; import { Page, createBlockInPage, expect, oneEmptyForm, test } from '@nocobase/test/e2e';
import { oneEmptyTableWithUsers } from '../../../details-multi/__e2e__/templatesOfBug'; import { oneEmptyTableWithUsers } from '../../../details-multi/__e2e__/templatesOfBug';
import { T3106, T3469, oneFormWithInheritFields } from './templatesOfBug'; import { T3106, T3469, oneFormWithInheritFields } from './templatesOfBug';
const deleteButton = async (page: Page, name: string) => {
await page.getByRole('button', { name }).hover();
await page.getByRole('button', { name }).getByLabel('designer-schema-settings-').hover();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
};
test.describe('where creation form block can be added', () => { test.describe('where creation form block can be added', () => {
test('page', async ({ page, mockPage }) => { test('page', async ({ page, mockPage }) => {
await mockPage().goto(); await mockPage().goto();
@ -111,16 +118,11 @@ test.describe('configure actions', () => {
// add button // add button
await page.getByRole('menuitem', { name: 'Submit' }).click(); await page.getByRole('menuitem', { name: 'Submit' }).click();
await expect(page.getByRole('menuitem', { name: 'Submit' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Submit' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Submit' })).toBeVisible();
// delete button // delete button
await page.getByLabel('schema-initializer-ActionBar-createForm:configureActions-general').hover(); await deleteButton(page, 'Submit');
await page.getByRole('menuitem', { name: 'Submit' }).click();
await expect(page.getByRole('menuitem', { name: 'Submit' }).getByRole('switch')).not.toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Submit' })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Submit' })).not.toBeVisible();
}); });
@ -178,14 +180,4 @@ test.describe('configure actions', () => {
page.getByLabel('block-item-CollectionField-users-form-users.username-Username').getByRole('textbox'), page.getByLabel('block-item-CollectionField-users-form-users.username-Username').getByRole('textbox'),
).toHaveValue(''); ).toHaveValue('');
}); });
test('customize: save record', async ({ page, mockPage }) => {
await mockPage(oneEmptyForm).goto();
await page.getByLabel('schema-initializer-ActionBar-createForm:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: 'Save record' }).click();
await expect(page.getByRole('button', { name: 'Save record' })).toBeVisible();
});
}); });

View File

@ -402,16 +402,16 @@ test.describe('actions schema settings', () => {
await mockPage(oneFormAndOneTableWithUsers).goto(); await mockPage(oneFormAndOneTableWithUsers).goto();
const openPopup = async () => { const openPopup = async () => {
if (!(await page.getByLabel('action-Action-Save record-').isVisible())) { if (!(await page.getByLabel('action-Action-Submit-').isVisible())) {
await page.getByLabel('schema-initializer-ActionBar-createForm:configureActions-users').hover(); await page.getByLabel('schema-initializer-ActionBar-createForm:configureActions-users').hover();
await page.getByRole('menuitem', { name: 'Customize right' }).hover(); await page.getByRole('menuitem', { name: 'Submit' }).click();
await page.getByRole('menuitem', { name: 'Save record' }).click();
} }
await page.getByLabel('action-Action-Save record-').hover(); await page.getByLabel('action-Action-Submit-').hover();
await page.getByLabel('designer-schema-settings-Action-actionSettings:saveRecord-users').hover(); await page.getByLabel('designer-schema-settings-Action-actionSettings:createSubmit-users').hover();
await page.getByRole('menuitem', { name: 'Assign field values' }).click(); await page.getByRole('menuitem', { name: 'Assign field values' }).click();
await page.waitForTimeout(500);
if (!(await page.getByLabel('block-item-AssignedField-').getByRole('textbox').isVisible())) { if (!(await page.getByLabel('block-item-AssignedField-').getByRole('textbox').isVisible())) {
await page.getByLabel('schema-initializer-Grid-assignFieldValuesForm:configureFields-users').hover(); await page.getByLabel('schema-initializer-Grid-assignFieldValuesForm:configureFields-users').hover();
await page.getByRole('menuitem', { name: 'Nickname' }).click(); await page.getByRole('menuitem', { name: 'Nickname' }).click();
@ -419,8 +419,7 @@ test.describe('actions schema settings', () => {
}; };
const expectNewValue = async (value: string) => { const expectNewValue = async (value: string) => {
await page.getByLabel('action-Action-Save record-').click(); await page.getByLabel('action-Action-Submit-').click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await page.getByLabel('action-Action-Refresh-refresh').click(); await page.getByLabel('action-Action-Refresh-refresh').click();
await expect(page.getByLabel('block-item-CardItem-users-table').getByText(value)).toBeVisible(); await expect(page.getByLabel('block-item-CardItem-users-table').getByText(value)).toBeVisible();
}; };
@ -431,9 +430,9 @@ test.describe('actions schema settings', () => {
// 2. 将 Nickname 字段的值设置为 `123456` // 2. 将 Nickname 字段的值设置为 `123456`
await page.getByLabel('block-item-AssignedField-').getByRole('textbox').click(); await page.getByLabel('block-item-AssignedField-').getByRole('textbox').click();
await page.getByLabel('block-item-AssignedField-').getByRole('textbox').fill('123456'); await page.getByLabel('block-item-AssignedField-').getByRole('textbox').fill('123456');
await page.getByRole('button', { name: 'Submit' }).click(); await page.getByRole('button', { name: 'Submit', exact: true }).click();
// 3. 保存后点击 Save record 按钮,然后刷新表格,应该显示一条 Nickname 为 “123456” 的记录 // 3. 保存后点击 Submit 按钮,然后刷新表格,应该显示一条 Nickname 为 “123456” 的记录
await expectNewValue('123456'); await expectNewValue('123456');
// 4. 再次打开 Assign field values 配置弹窗,这次为 Nickname 设置一个变量值Current role // 4. 再次打开 Assign field values 配置弹窗,这次为 Nickname 设置一个变量值Current role
@ -447,9 +446,9 @@ test.describe('actions schema settings', () => {
'Current form', 'Current form',
]); ]);
await page.getByRole('menuitemcheckbox', { name: 'Current role' }).click(); await page.getByRole('menuitemcheckbox', { name: 'Current role' }).click();
await page.getByRole('button', { name: 'Submit' }).click(); await page.getByRole('button', { name: 'Submit', exact: true }).click();
// 5. 保存后点击 Save record 按钮,然后刷新表格,应该显示一条 Nickname 为 “root” 的记录 // 5. 保存后点击 Submit 按钮,然后刷新表格,应该显示一条 Nickname 为 “root” 的记录
await expectNewValue('root'); await expectNewValue('root');
}); });
}); });

View File

@ -741,6 +741,7 @@ test.describe('creation form block schema settings', () => {
await page.getByLabel('action-Action-Add new-create-users-table').click(); await page.getByLabel('action-Action-Add new-create-users-table').click();
await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-users').hover(); await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-users').hover();
await page.getByRole('menuitem', { name: 'form Form' }).first().hover(); await page.getByRole('menuitem', { name: 'form Form' }).first().hover();
await page.getByRole('menuitem', { name: 'Current collection' }).hover();
await page.getByRole('menuitem', { name: 'Reference template' }).hover(); await page.getByRole('menuitem', { name: 'Reference template' }).hover();
await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).first().click(); await page.getByRole('menuitem', { name: 'Users_Form (Fields only)' }).first().click();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);

View File

@ -16,6 +16,7 @@ export interface CreateFormBlockUISchemaOptions {
collectionName?: string; collectionName?: string;
association?: string; association?: string;
templateSchema?: ISchema; templateSchema?: ISchema;
/** 表示是通过 Other collections 选项创建的区块(由于历史遗留问题,这里的命名暂不做更改) */
isCusomeizeCreate?: boolean; isCusomeizeCreate?: boolean;
} }

View File

@ -9,97 +9,39 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
const commonOptions = {
title: '{{t("Configure actions")}}',
icon: 'SettingOutlined',
items: [
{
name: 'submit',
title: '{{t("Submit")}}',
Component: 'CreateSubmitActionInitializer',
schema: {
'x-action-settings': {},
},
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
},
],
};
/** /**
* @deprecated * @deprecated
* use `createFormActionInitializers` instead * use `createFormActionInitializers` instead
*/ */
export const createFormActionInitializers_deprecated = new CompatibleSchemaInitializer({ export const createFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CreateFormActionInitializers', name: 'CreateFormActionInitializers',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Enable actions")}}',
name: 'enableActions',
children: [
{
name: 'submit',
title: '{{t("Submit")}}',
Component: 'CreateSubmitActionInitializer',
schema: {
'x-action-settings': {},
},
},
],
},
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
title: '{{t("Customize")}}',
name: 'customize',
children: [
{
name: 'saveRecord',
title: '{{t("Save record")}}',
Component: 'SaveRecordActionInitializer',
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
},
],
},
],
}); });
export const createFormActionInitializers = new CompatibleSchemaInitializer( export const createFormActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'createForm:configureActions', name: 'createForm:configureActions',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Enable actions")}}',
name: 'enableActions',
children: [
{
name: 'submit',
title: '{{t("Submit")}}',
Component: 'CreateSubmitActionInitializer',
schema: {
'x-action-settings': {},
},
},
],
},
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
title: '{{t("Customize")}}',
name: 'customize',
children: [
{
name: 'saveRecord',
title: '{{t("Save record")}}',
Component: 'SaveRecordActionInitializer',
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
},
],
},
],
}, },
createFormActionInitializers_deprecated, createFormActionInitializers_deprecated,
); );

View File

@ -19,40 +19,17 @@ export const formActionInitializers = new SchemaInitializer({
icon: 'SettingOutlined', icon: 'SettingOutlined',
items: [ items: [
{ {
type: 'itemGroup', name: 'submit',
name: 'enableActions', title: '{{t("Submit")}}',
title: '{{t("Enable actions")}}', Component: 'CreateSubmitActionInitializer',
children: [ schema: {
{ 'x-action-settings': {},
name: 'submit', },
title: '{{t("Submit")}}',
Component: 'CreateSubmitActionInitializer',
schema: {
'x-action-settings': {},
},
},
],
}, },
{ {
name: 'divider', name: 'customRequest',
type: 'divider', title: '{{t("Custom request")}}',
}, Component: 'CustomRequestInitializer',
{
name: 'customize',
type: 'subMenu',
title: '{{t("Customize")}}',
children: [
{
name: 'saveRecord',
title: '{{t("Save record")}}',
Component: 'SaveRecordActionInitializer',
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
},
],
}, },
], ],
}); });

View File

@ -11,13 +11,7 @@ import { CompatibleSchemaInitializer } from '../../../../application/schema-init
import { AssociatedFields, ParentCollectionFields } from '../../../../schema-initializer/buttons/FormItemInitializers'; import { AssociatedFields, ParentCollectionFields } from '../../../../schema-initializer/buttons/FormItemInitializers';
import { gridRowColWrap, useFormItemInitializerFields } from '../../../../schema-initializer/utils'; import { gridRowColWrap, useFormItemInitializerFields } from '../../../../schema-initializer/utils';
/** const commonOptions = {
* @deprecated
* use `formItemInitializers` instead
*
*/
export const formItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'FormItemInitializers',
wrap: gridRowColWrap, wrap: gridRowColWrap,
icon: 'SettingOutlined', icon: 'SettingOutlined',
title: '{{t("Configure fields")}}', title: '{{t("Configure fields")}}',
@ -46,39 +40,22 @@ export const formItemInitializers_deprecated = new CompatibleSchemaInitializer({
Component: 'MarkdownFormItemInitializer', Component: 'MarkdownFormItemInitializer',
}, },
], ],
};
/**
* @deprecated
* use `formItemInitializers` instead
*
*/
export const formItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'FormItemInitializers',
...commonOptions,
}); });
export const formItemInitializers = new CompatibleSchemaInitializer( export const formItemInitializers = new CompatibleSchemaInitializer(
{ {
name: 'form:configureFields', name: 'form:configureFields',
wrap: gridRowColWrap, ...commonOptions,
icon: 'SettingOutlined',
title: '{{t("Configure fields")}}',
items: [
{
type: 'itemGroup',
name: 'displayFields',
title: '{{t("Display fields")}}',
useChildren: useFormItemInitializerFields,
},
{
name: 'parentCollectionFields',
Component: ParentCollectionFields,
},
{
name: 'associationFields',
Component: AssociatedFields,
},
{
name: 'divider',
type: 'divider',
},
{
name: 'addText',
title: '{{t("Add text")}}',
Component: 'MarkdownFormItemInitializer',
},
],
}, },
formItemInitializers_deprecated, formItemInitializers_deprecated,
); );

View File

@ -8,10 +8,13 @@
*/ */
import { useParentRecordCommon } from '../../../useParentRecordCommon'; import { useParentRecordCommon } from '../../../useParentRecordCommon';
import { useHiddenForInherit } from './useHiddenForInherit';
export function useCreateFormBlockDecoratorProps(props) { export function useCreateFormBlockDecoratorProps(props) {
let parentRecord; let parentRecord;
const { hidden } = useHiddenForInherit(props);
// association 的值是固定不变的,所以这里可以使用 hooks // association 的值是固定不变的,所以这里可以使用 hooks
if (props.association) { if (props.association) {
// eslint-disable-next-line react-hooks/rules-of-hooks // eslint-disable-next-line react-hooks/rules-of-hooks
@ -20,5 +23,6 @@ export function useCreateFormBlockDecoratorProps(props) {
return { return {
parentRecord, parentRecord,
hidden,
}; };
} }

View File

@ -9,11 +9,14 @@
import { useParamsFromRecord } from '../../../../../block-provider/BlockProvider'; import { useParamsFromRecord } from '../../../../../block-provider/BlockProvider';
import { useDetailsParentRecord } from '../../details-single/hooks/useDetailsDecoratorProps'; import { useDetailsParentRecord } from '../../details-single/hooks/useDetailsDecoratorProps';
import { useHiddenForInherit } from './useHiddenForInherit';
export function useEditFormBlockDecoratorProps(props) { export function useEditFormBlockDecoratorProps(props) {
const params = useFormBlockParams(); const params = useFormBlockParams();
let parentRecord; let parentRecord;
const { hidden } = useHiddenForInherit(props);
// association 的值是固定不变的,所以这里可以使用 hooks // association 的值是固定不变的,所以这里可以使用 hooks
if (props.association) { if (props.association) {
// 复用详情区块的 sourceId 获取逻辑 // 复用详情区块的 sourceId 获取逻辑
@ -24,6 +27,7 @@ export function useEditFormBlockDecoratorProps(props) {
return { return {
params, params,
parentRecord, parentRecord,
hidden,
}; };
} }

View File

@ -0,0 +1,48 @@
/**
* 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 { useIsDetailBlock } from '../../../../../block-provider/FormBlockProvider';
import { useCollection } from '../../../../../data-source/collection/CollectionProvider';
import { useRecord } from '../../../../../record-provider';
import { useDesignable } from '../../../../../schema-component/hooks/useDesignable';
/**
*
* https://nocobase.feishu.cn/docx/A3L9dNZhnoMBjRxVciBcFzwLnae
*/
export const useHiddenForInherit = (props) => {
const record = useRecord();
const { collection, isCusomeizeCreate, hidden } = props;
const { __collection } = record;
const currentCollection = useCollection();
const { designable } = useDesignable();
const isDetailBlock = useIsDetailBlock();
if (!currentCollection) {
return {
hidden: hidden || false,
};
}
let detailFlag = false;
if (isDetailBlock) {
detailFlag = true;
if (!designable && __collection) {
detailFlag = __collection === collection;
}
}
const createFlag =
(currentCollection.name === (collection?.name || collection) && !isDetailBlock) ||
!currentCollection.name ||
!collection;
return {
hidden: hidden || (!detailFlag && !createFlag && !isCusomeizeCreate),
};
};

View File

@ -7,7 +7,6 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
export * from './CreateFormBlockInitializer';
export * from './FormBlockInitializer'; export * from './FormBlockInitializer';
export * from './FormItemSchemaToolbar'; export * from './FormItemSchemaToolbar';
export * from './RecordFormBlockInitializer'; export * from './RecordFormBlockInitializer';

View File

@ -9,119 +9,50 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
const commonOptions = {
title: '{{t("Configure actions")}}',
icon: 'SettingOutlined',
items: [
{
name: 'submit',
title: '{{t("Submit")}}',
Component: 'UpdateSubmitActionInitializer',
schema: {
'x-action-settings': {},
},
},
{
name: 'popup',
title: '{{t("Popup")}}',
Component: 'PopupActionInitializer',
useComponentProps() {
return {
'x-component': 'Action',
};
},
},
{
type: 'item',
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
},
],
};
/** /**
* @deprecated * @deprecated
* use `updateFormActionInitializers` instead * use `updateFormActionInitializers` instead
*/ */
export const updateFormActionInitializers_deprecated = new CompatibleSchemaInitializer({ export const updateFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'UpdateFormActionInitializers', name: 'UpdateFormActionInitializers',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Enable actions")}}',
name: 'enableActions',
children: [
{
name: 'submit',
title: '{{t("Submit")}}',
Component: 'UpdateSubmitActionInitializer',
schema: {
'x-action-settings': {},
},
},
],
},
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
title: '{{t("Customize")}}',
name: 'customize',
children: [
{
name: 'popup',
title: '{{t("Popup")}}',
Component: 'PopupActionInitializer',
useComponentProps() {
return {
'x-component': 'Action',
};
},
},
{
name: 'saveRecord',
title: '{{t("Save record")}}',
Component: 'SaveRecordActionInitializer',
},
{
type: 'item',
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
},
],
},
],
}); });
export const updateFormActionInitializers = new CompatibleSchemaInitializer( export const updateFormActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'editForm:configureActions', name: 'editForm:configureActions',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Enable actions")}}',
name: 'enableActions',
children: [
{
name: 'submit',
title: '{{t("Submit")}}',
Component: 'UpdateSubmitActionInitializer',
schema: {
'x-action-settings': {},
},
},
],
},
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
title: '{{t("Customize")}}',
name: 'customize',
children: [
{
name: 'popup',
title: '{{t("Popup")}}',
Component: 'PopupActionInitializer',
useComponentProps() {
return {
'x-component': 'Action',
};
},
},
{
name: 'saveRecord',
title: '{{t("Save record")}}',
Component: 'SaveRecordActionInitializer',
},
{
type: 'item',
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
},
],
},
],
}, },
updateFormActionInitializers_deprecated, updateFormActionInitializers_deprecated,
); );

View File

@ -10,12 +10,7 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCollection_deprecated } from '../../../../collection-manager'; import { useCollection_deprecated } from '../../../../collection-manager';
/** const commonOptions = {
* @deprecated
* use `gridCardActionInitializers` instead
*/
export const gridCardActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'GridCardActionInitializers',
title: "{{t('Configure actions')}}", title: "{{t('Configure actions')}}",
icon: 'SettingOutlined', icon: 'SettingOutlined',
style: { style: {
@ -23,154 +18,82 @@ export const gridCardActionInitializers_deprecated = new CompatibleSchemaInitial
}, },
items: [ items: [
{ {
type: 'itemGroup', name: 'filter',
title: "{{t('Enable actions')}}", title: "{{t('Filter')}}",
name: 'enableActions', Component: 'FilterActionInitializer',
children: [ schema: {
{ 'x-align': 'left',
name: 'filter', },
title: "{{t('Filter')}}", },
Component: 'FilterActionInitializer', {
schema: { name: 'addNew',
'x-align': 'left', title: "{{t('Add new')}}",
}, Component: 'CreateActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
}, },
{ },
name: 'addNew', useVisible() {
title: "{{t('Add new')}}", const collection = useCollection_deprecated();
Component: 'CreateActionInitializer', return !['view', 'file', 'sql'].includes(collection.template) || collection?.writableView;
schema: { },
'x-align': 'right', },
'x-decorator': 'ACLActionProvider', {
'x-acl-action-props': { name: 'refresh',
skipScopeCheck: true, title: "{{t('Refresh')}}",
}, Component: 'RefreshActionInitializer',
}, schema: {
useVisible() { 'x-align': 'right',
const collection = useCollection_deprecated(); },
return !['view', 'file', 'sql'].includes(collection.template) || collection?.writableView; },
}, {
name: 'import',
title: "{{t('Import')}}",
Component: 'ImportActionInitializer',
schema: {
'x-align': 'right',
'x-acl-action': 'importXlsx',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
}, },
{ },
name: 'refresh', useVisible() {
title: "{{t('Refresh')}}", const collection = useCollection_deprecated();
Component: 'RefreshActionInitializer', return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
schema: { },
'x-align': 'right', },
}, {
name: 'export',
title: "{{t('Export')}}",
Component: 'ExportActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
}, },
{ },
name: 'import',
title: "{{t('Import')}}",
Component: 'ImportActionInitializer',
schema: {
'x-align': 'right',
'x-acl-action': 'importXlsx',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'export',
title: "{{t('Export')}}",
Component: 'ExportActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
},
],
}, },
], ],
};
/**
* @deprecated
* use `gridCardActionInitializers` instead
*/
export const gridCardActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'GridCardActionInitializers',
...commonOptions,
}); });
export const gridCardActionInitializers = new CompatibleSchemaInitializer( export const gridCardActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'gridCard:configureActions', name: 'gridCard:configureActions',
title: "{{t('Configure actions')}}", ...commonOptions,
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'itemGroup',
title: "{{t('Enable actions')}}",
name: 'enableActions',
children: [
{
name: 'filter',
title: "{{t('Filter')}}",
Component: 'FilterActionInitializer',
schema: {
'x-align': 'left',
},
},
{
name: 'addNew',
title: "{{t('Add new')}}",
Component: 'CreateActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
useVisible() {
const collection = useCollection_deprecated();
return !['view', 'file', 'sql'].includes(collection.template) || collection?.writableView;
},
},
{
name: 'refresh',
title: "{{t('Refresh')}}",
Component: 'RefreshActionInitializer',
schema: {
'x-align': 'right',
},
},
{
name: 'import',
title: "{{t('Import')}}",
Component: 'ImportActionInitializer',
schema: {
'x-align': 'right',
'x-acl-action': 'importXlsx',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'export',
title: "{{t('Export')}}",
Component: 'ExportActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
},
],
},
],
}, },
gridCardActionInitializers_deprecated, gridCardActionInitializers_deprecated,
); );

View File

@ -7,10 +7,17 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { createBlockInPage, expect, oneEmptyGridCardBlock, test } from '@nocobase/test/e2e'; import { Page, createBlockInPage, expect, oneEmptyGridCardBlock, test } from '@nocobase/test/e2e';
import { oneEmptyTableWithUsers } from '../../details-multi/__e2e__/templatesOfBug'; import { oneEmptyTableWithUsers } from '../../details-multi/__e2e__/templatesOfBug';
import { oneGridCardWithInheritFields } from './templatesOfBug'; import { oneGridCardWithInheritFields } from './templatesOfBug';
const deleteButton = async (page: Page, name: string) => {
await page.getByRole('button', { name }).hover();
await page.getByRole('button', { name }).getByLabel('designer-schema-settings-').hover();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
};
test.describe('where grid card block can be added', () => { test.describe('where grid card block can be added', () => {
test('page', async ({ page, mockPage }) => { test('page', async ({ page, mockPage }) => {
await mockPage().goto(); await mockPage().goto();
@ -63,24 +70,15 @@ test.describe('configure global actions', () => {
await page.getByRole('menuitem', { name: 'Add new' }).click(); await page.getByRole('menuitem', { name: 'Add new' }).click();
await page.getByRole('menuitem', { name: 'Refresh' }).click(); await page.getByRole('menuitem', { name: 'Refresh' }).click();
await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible();
// delete buttons // delete buttons
await page.getByLabel('schema-initializer-ActionBar-gridCard:configureActions-general').hover(); await deleteButton(page, 'Filter');
await page.getByRole('menuitem', { name: 'Filter' }).click(); await deleteButton(page, 'Add new');
await page.getByRole('menuitem', { name: 'Add new' }).click(); await deleteButton(page, 'Refresh');
await page.getByRole('menuitem', { name: 'Refresh' }).click();
await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).not.toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible();
@ -100,24 +98,15 @@ test.describe('configure item actions', () => {
await page.getByRole('menuitem', { name: 'Edit' }).click(); await page.getByRole('menuitem', { name: 'Edit' }).click();
await page.getByRole('menuitem', { name: 'Delete' }).click(); await page.getByRole('menuitem', { name: 'Delete' }).click();
await expect(page.getByRole('menuitem', { name: 'View' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Edit' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByLabel('action-Action.Link-View-view-general-grid-card').first()).toBeVisible(); await expect(page.getByLabel('action-Action.Link-View-view-general-grid-card').first()).toBeVisible();
await expect(page.getByLabel('action-Action.Link-Edit-update-general-grid-card').first()).toBeVisible(); await expect(page.getByLabel('action-Action.Link-Edit-update-general-grid-card').first()).toBeVisible();
await expect(page.getByLabel('action-Action.Link-Delete-destroy-general-grid-card').first()).toBeVisible(); await expect(page.getByLabel('action-Action.Link-Delete-destroy-general-grid-card').first()).toBeVisible();
// delete buttons // delete buttons
await page.getByLabel('schema-initializer-ActionBar-gridCard:configureItemActions-general').first().hover(); await deleteButton(page, 'View');
await page.getByRole('menuitem', { name: 'View' }).click(); await deleteButton(page, 'Edit');
await page.getByRole('menuitem', { name: 'Edit' }).click(); await deleteButton(page, 'Delete');
await page.getByRole('menuitem', { name: 'Delete' }).click();
await expect(page.getByRole('menuitem', { name: 'View' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Edit' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).not.toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByLabel('action-Action.Link-View-view-general-grid-card').first()).not.toBeVisible(); await expect(page.getByLabel('action-Action.Link-View-view-general-grid-card').first()).not.toBeVisible();
@ -131,7 +120,6 @@ test.describe('configure item actions', () => {
await nocoPage.goto(); await nocoPage.goto();
await page.getByLabel('schema-initializer-ActionBar-gridCard:configureItemActions-general').first().hover(); await page.getByLabel('schema-initializer-ActionBar-gridCard:configureItemActions-general').first().hover();
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: 'Popup' }).click(); await page.getByRole('menuitem', { name: 'Popup' }).click();
await page.getByRole('menuitem', { name: 'Update record' }).click(); await page.getByRole('menuitem', { name: 'Update record' }).click();

View File

@ -10,205 +10,98 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCollection_deprecated } from '../../../../collection-manager'; import { useCollection_deprecated } from '../../../../collection-manager';
const commonOptions = {
title: '{{t("Configure actions")}}',
icon: 'SettingOutlined',
items: [
{
name: 'view',
title: '{{t("View")}}',
Component: 'ViewActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'view',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
},
{
name: 'edit',
title: '{{t("Edit")}}',
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'update',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'delete',
title: '{{t("Delete")}}',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'destroy',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return collection.template !== 'sql';
},
},
{
name: 'popup',
title: '{{t("Popup")}}',
Component: 'PopupActionInitializer',
useComponentProps() {
return {
'x-component': 'Action.Link',
};
},
},
{
name: 'update-record',
title: '{{t("Update record")}}',
Component: 'UpdateRecordActionInitializer',
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
schema: {
'x-action': 'customize:table:request',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
],
};
/** /**
* @deprecated * @deprecated
* use `gridCardItemActionInitializers` instead * use `gridCardItemActionInitializers` instead
*/ */
export const gridCardItemActionInitializers_deprecated = new CompatibleSchemaInitializer({ export const gridCardItemActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'GridCardItemActionInitializers', name: 'GridCardItemActionInitializers',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Enable actions")}}',
name: 'enable-actions',
children: [
{
name: 'view',
title: '{{t("View")}}',
Component: 'ViewActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'view',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
},
{
name: 'edit',
title: '{{t("Edit")}}',
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'update',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'delete',
title: '{{t("Delete")}}',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'destroy',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return collection.template !== 'sql';
},
},
],
},
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
title: '{{t("Customize")}}',
name: 'customize',
children: [
{
name: 'popup',
title: '{{t("Popup")}}',
Component: 'PopupActionInitializer',
useComponentProps() {
return {
'x-component': 'Action.Link',
};
},
},
{
name: 'update-record',
title: '{{t("Update record")}}',
Component: 'UpdateRecordActionInitializer',
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
schema: {
'x-action': 'customize:table:request',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
],
},
],
}); });
export const gridCardItemActionInitializers = new CompatibleSchemaInitializer( export const gridCardItemActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'gridCard:configureItemActions', name: 'gridCard:configureItemActions',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Enable actions")}}',
name: 'enable-actions',
children: [
{
name: 'view',
title: '{{t("View")}}',
Component: 'ViewActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'view',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
},
{
name: 'edit',
title: '{{t("Edit")}}',
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'update',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'delete',
title: '{{t("Delete")}}',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'destroy',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return collection.template !== 'sql';
},
},
],
},
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
title: '{{t("Customize")}}',
name: 'customize',
children: [
{
name: 'popup',
title: '{{t("Popup")}}',
Component: 'PopupActionInitializer',
useComponentProps() {
return {
'x-component': 'Action.Link',
};
},
},
{
name: 'update-record',
title: '{{t("Update record")}}',
Component: 'UpdateRecordActionInitializer',
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
schema: {
'x-action': 'customize:table:request',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
],
},
],
}, },
gridCardItemActionInitializers_deprecated, gridCardItemActionInitializers_deprecated,
); );

View File

@ -10,13 +10,7 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCollection_deprecated } from '../../../../collection-manager'; import { useCollection_deprecated } from '../../../../collection-manager';
/** const commonOptions = {
* @deprecated
* use `listActionInitializers` instead
*
*/
export const listActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ListActionInitializers',
title: "{{t('Configure actions')}}", title: "{{t('Configure actions')}}",
icon: 'SettingOutlined', icon: 'SettingOutlined',
style: { style: {
@ -24,162 +18,87 @@ export const listActionInitializers_deprecated = new CompatibleSchemaInitializer
}, },
items: [ items: [
{ {
type: 'itemGroup', name: 'filter',
name: 'enableActions', title: "{{t('Filter')}}",
title: "{{t('Enable actions')}}", Component: 'FilterActionInitializer',
children: [ schema: {
{ 'x-align': 'left',
name: 'filter', },
title: "{{t('Filter')}}", },
Component: 'FilterActionInitializer', {
schema: { name: 'addNew',
'x-align': 'left', title: "{{t('Add new')}}",
}, Component: 'CreateActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
}, },
{ },
name: 'addNew', useVisible() {
title: "{{t('Add new')}}", const collection = useCollection_deprecated();
Component: 'CreateActionInitializer', return (
schema: { (collection.template !== 'view' || collection?.writableView) &&
'x-align': 'right', collection.template !== 'file' &&
'x-decorator': 'ACLActionProvider', collection.template !== 'sql'
'x-acl-action-props': { );
skipScopeCheck: true, },
}, },
}, {
useVisible() { name: 'refresh',
const collection = useCollection_deprecated(); title: "{{t('Refresh')}}",
return ( Component: 'RefreshActionInitializer',
(collection.template !== 'view' || collection?.writableView) && schema: {
collection.template !== 'file' && 'x-align': 'right',
collection.template !== 'sql' },
); },
}, {
name: 'import',
title: "{{t('Import')}}",
Component: 'ImportActionInitializer',
schema: {
'x-align': 'right',
'x-acl-action': 'importXlsx',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
}, },
{ },
name: 'refresh', useVisible() {
title: "{{t('Refresh')}}", const collection = useCollection_deprecated();
Component: 'RefreshActionInitializer', return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
schema: { },
'x-align': 'right', },
}, {
name: 'export',
title: "{{t('Export')}}",
Component: 'ExportActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
}, },
{ },
name: 'import',
title: "{{t('Import')}}",
Component: 'ImportActionInitializer',
schema: {
'x-align': 'right',
'x-acl-action': 'importXlsx',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'export',
title: "{{t('Export')}}",
Component: 'ExportActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
},
],
}, },
], ],
};
/**
* @deprecated
* use `listActionInitializers` instead
*
*/
export const listActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ListActionInitializers',
...commonOptions,
}); });
export const listActionInitializers = new CompatibleSchemaInitializer( export const listActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'list:configureActions', name: 'list:configureActions',
title: "{{t('Configure actions')}}", ...commonOptions,
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'itemGroup',
name: 'enableActions',
title: "{{t('Enable actions')}}",
children: [
{
name: 'filter',
title: "{{t('Filter')}}",
Component: 'FilterActionInitializer',
schema: {
'x-align': 'left',
},
},
{
name: 'addNew',
title: "{{t('Add new')}}",
Component: 'CreateActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
useVisible() {
const collection = useCollection_deprecated();
return (
(collection.template !== 'view' || collection?.writableView) &&
collection.template !== 'file' &&
collection.template !== 'sql'
);
},
},
{
name: 'refresh',
title: "{{t('Refresh')}}",
Component: 'RefreshActionInitializer',
schema: {
'x-align': 'right',
},
},
{
name: 'import',
title: "{{t('Import')}}",
Component: 'ImportActionInitializer',
schema: {
'x-align': 'right',
'x-acl-action': 'importXlsx',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'export',
title: "{{t('Export')}}",
Component: 'ExportActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
},
],
},
],
}, },
listActionInitializers_deprecated, listActionInitializers_deprecated,
); );

View File

@ -7,9 +7,16 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { createBlockInPage, expect, oneEmptyListBlock, test } from '@nocobase/test/e2e'; import { Page, createBlockInPage, expect, oneEmptyListBlock, test } from '@nocobase/test/e2e';
import { oneEmptyTableWithUsers } from '../../details-multi/__e2e__/templatesOfBug'; import { oneEmptyTableWithUsers } from '../../details-multi/__e2e__/templatesOfBug';
const deleteButton = async (page: Page, name: string) => {
await page.getByRole('button', { name }).hover();
await page.getByRole('button', { name }).getByLabel('designer-schema-settings-').hover();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
};
test.describe('where list block can be added', () => { test.describe('where list block can be added', () => {
test('page', async ({ page, mockPage }) => { test('page', async ({ page, mockPage }) => {
await mockPage().goto(); await mockPage().goto();
@ -60,24 +67,15 @@ test.describe('configure global actions', () => {
await page.getByRole('menuitem', { name: 'Add new' }).click(); await page.getByRole('menuitem', { name: 'Add new' }).click();
await page.getByRole('menuitem', { name: 'Refresh' }).click(); await page.getByRole('menuitem', { name: 'Refresh' }).click();
await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible();
// delete buttons // delete buttons
await page.getByLabel('schema-initializer-ActionBar-list:configureActions-general').hover(); await deleteButton(page, 'Filter');
await page.getByRole('menuitem', { name: 'Filter' }).click(); await deleteButton(page, 'Add new');
await page.getByRole('menuitem', { name: 'Add new' }).click(); await deleteButton(page, 'Refresh');
await page.getByRole('menuitem', { name: 'Refresh' }).click();
await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).not.toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible();
@ -97,24 +95,15 @@ test.describe('configure item actions', () => {
await page.getByRole('menuitem', { name: 'Edit' }).click(); await page.getByRole('menuitem', { name: 'Edit' }).click();
await page.getByRole('menuitem', { name: 'Delete' }).click(); await page.getByRole('menuitem', { name: 'Delete' }).click();
await expect(page.getByRole('menuitem', { name: 'View' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Edit' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByLabel('action-Action.Link-View-view-general-list').first()).toBeVisible(); await expect(page.getByLabel('action-Action.Link-View-view-general-list').first()).toBeVisible();
await expect(page.getByLabel('action-Action.Link-Edit-update-general-list').first()).toBeVisible(); await expect(page.getByLabel('action-Action.Link-Edit-update-general-list').first()).toBeVisible();
await expect(page.getByLabel('action-Action.Link-Delete-destroy-general-list').first()).toBeVisible(); await expect(page.getByLabel('action-Action.Link-Delete-destroy-general-list').first()).toBeVisible();
// delete buttons // delete buttons
await page.getByLabel('schema-initializer-ActionBar-list:configureItemActions-general').first().hover(); await deleteButton(page, 'View');
await page.getByRole('menuitem', { name: 'View' }).click(); await deleteButton(page, 'Edit');
await page.getByRole('menuitem', { name: 'Edit' }).click(); await deleteButton(page, 'Delete');
await page.getByRole('menuitem', { name: 'Delete' }).click();
await expect(page.getByRole('menuitem', { name: 'View' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Edit' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).not.toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByLabel('action-Action.Link-View-view-general-list').first()).not.toBeVisible(); await expect(page.getByLabel('action-Action.Link-View-view-general-list').first()).not.toBeVisible();
@ -128,7 +117,6 @@ test.describe('configure item actions', () => {
await nocoPage.goto(); await nocoPage.goto();
await page.getByLabel('schema-initializer-ActionBar-list:configureItemActions-general').first().hover(); await page.getByLabel('schema-initializer-ActionBar-list:configureItemActions-general').first().hover();
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: 'Popup' }).click(); await page.getByRole('menuitem', { name: 'Popup' }).click();
await page.getByRole('menuitem', { name: 'Update record' }).click(); await page.getByRole('menuitem', { name: 'Update record' }).click();

View File

@ -10,205 +10,98 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCollection_deprecated } from '../../../../collection-manager'; import { useCollection_deprecated } from '../../../../collection-manager';
const commonOptions = {
title: '{{t("Configure actions")}}',
icon: 'SettingOutlined',
items: [
{
name: 'view',
title: '{{t("View")}}',
Component: 'ViewActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'view',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
},
{
name: 'edit',
title: '{{t("Edit")}}',
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'update',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'delete',
title: '{{t("Delete")}}',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'destroy',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return collection.template !== 'sql';
},
},
{
name: 'popup',
title: '{{t("Popup")}}',
Component: 'PopupActionInitializer',
useComponentProps() {
return {
'x-component': 'Action.Link',
};
},
},
{
name: 'updateRecord',
title: '{{t("Update record")}}',
Component: 'UpdateRecordActionInitializer',
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
schema: {
'x-action': 'customize:table:request',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
],
};
/** /**
* @deprecated * @deprecated
* use `listItemActionInitializers` instead * use `listItemActionInitializers` instead
*/ */
export const listItemActionInitializers_deprecated = new CompatibleSchemaInitializer({ export const listItemActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ListItemActionInitializers', name: 'ListItemActionInitializers',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
name: 'enableActions',
title: '{{t("Enable actions")}}',
children: [
{
name: 'view',
title: '{{t("View")}}',
Component: 'ViewActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'view',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
},
{
name: 'edit',
title: '{{t("Edit")}}',
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'update',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'delete',
title: '{{t("Delete")}}',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'destroy',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return collection.template !== 'sql';
},
},
],
},
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
title: '{{t("Customize")}}',
name: 'customize',
children: [
{
name: 'popup',
title: '{{t("Popup")}}',
Component: 'PopupActionInitializer',
useComponentProps() {
return {
'x-component': 'Action.Link',
};
},
},
{
name: 'updateRecord',
title: '{{t("Update record")}}',
Component: 'UpdateRecordActionInitializer',
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
schema: {
'x-action': 'customize:table:request',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
],
},
],
}); });
export const listItemActionInitializers = new CompatibleSchemaInitializer( export const listItemActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'list:configureItemActions', name: 'list:configureItemActions',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
name: 'enableActions',
title: '{{t("Enable actions")}}',
children: [
{
name: 'view',
title: '{{t("View")}}',
Component: 'ViewActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'view',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
},
{
name: 'edit',
title: '{{t("Edit")}}',
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'update',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'delete',
title: '{{t("Delete")}}',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'destroy',
'x-decorator': 'ACLActionProvider',
'x-align': 'left',
},
useVisible() {
const collection = useCollection_deprecated();
return collection.template !== 'sql';
},
},
],
},
{
name: 'divider',
type: 'divider',
},
{
type: 'subMenu',
title: '{{t("Customize")}}',
name: 'customize',
children: [
{
name: 'popup',
title: '{{t("Popup")}}',
Component: 'PopupActionInitializer',
useComponentProps() {
return {
'x-component': 'Action.Link',
};
},
},
{
name: 'updateRecord',
title: '{{t("Update record")}}',
Component: 'UpdateRecordActionInitializer',
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
schema: {
'x-action': 'customize:table:request',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
],
},
],
}, },
listItemActionInitializers_deprecated, listItemActionInitializers_deprecated,
); );

View File

@ -10,6 +10,13 @@
import { Page, expect, test } from '@nocobase/test/e2e'; import { Page, expect, test } from '@nocobase/test/e2e';
import { createTable } from './utils'; import { createTable } from './utils';
const deleteButton = async (page: Page, name: string) => {
await page.getByRole('button', { name }).hover();
await page.getByRole('button', { name }).getByLabel('designer-schema-settings-').hover();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
};
test.describe('where table data selector can be added', () => { test.describe('where table data selector can be added', () => {
test('popup', async ({ page, mockPage }) => { test('popup', async ({ page, mockPage }) => {
await createTable({ page, mockPage, fieldName: 'manyToOne' }); await createTable({ page, mockPage, fieldName: 'manyToOne' });
@ -35,11 +42,6 @@ test.describe('configure actions', () => {
await page.getByRole('menuitem', { name: 'Delete' }).click(); await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('menuitem', { name: 'Refresh' }).click(); await page.getByRole('menuitem', { name: 'Refresh' }).click();
await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible();
@ -47,16 +49,10 @@ test.describe('configure actions', () => {
await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible();
// delete buttons // delete buttons
await page.getByLabel('schema-initializer-ActionBar-table:configureActions-users').hover(); await deleteButton(page, 'Filter');
await page.getByRole('menuitem', { name: 'Filter' }).click(); await deleteButton(page, 'Add new');
await page.getByRole('menuitem', { name: 'Add new' }).click(); await deleteButton(page, 'Delete');
await page.getByRole('menuitem', { name: 'Delete' }).click(); await deleteButton(page, 'Refresh');
await page.getByRole('menuitem', { name: 'Refresh' }).click();
await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).not.toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible();
@ -69,7 +65,6 @@ test.describe('configure actions', () => {
await createTable({ page, mockPage, fieldName: 'manyToOne' }); await createTable({ page, mockPage, fieldName: 'manyToOne' });
await page.getByLabel('schema-initializer-ActionBar-table:configureActions-users').hover(); await page.getByLabel('schema-initializer-ActionBar-table:configureActions-users').hover();
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: 'Bulk update' }).click(); await page.getByRole('menuitem', { name: 'Bulk update' }).click();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);

View File

@ -8,7 +8,7 @@
*/ */
import { MenuOutlined } from '@ant-design/icons'; import { MenuOutlined } from '@ant-design/icons';
import { ISchema, useFieldSchema, useField } from '@formily/react'; import { ISchema, useField, useFieldSchema } from '@formily/react';
import _ from 'lodash'; import _ from 'lodash';
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -18,10 +18,10 @@ import { SchemaInitializerActionModal } from '../../../../application/schema-ini
import { SchemaInitializerItem } from '../../../../application/schema-initializer/components/SchemaInitializerItem'; import { SchemaInitializerItem } from '../../../../application/schema-initializer/components/SchemaInitializerItem';
import { useSchemaInitializer } from '../../../../application/schema-initializer/context'; import { useSchemaInitializer } from '../../../../application/schema-initializer/context';
import { useCollection_deprecated } from '../../../../collection-manager'; import { useCollection_deprecated } from '../../../../collection-manager';
import { SelectWithTitle } from '../../../../common/SelectWithTitle';
import { useDataBlockProps } from '../../../../data-source'; import { useDataBlockProps } from '../../../../data-source';
import { createDesignable, useDesignable } from '../../../../schema-component'; import { createDesignable, useDesignable } from '../../../../schema-component';
import { useGetAriaLabelOfDesigner } from '../../../../schema-settings/hooks/useGetAriaLabelOfDesigner'; import { useGetAriaLabelOfDesigner } from '../../../../schema-settings/hooks/useGetAriaLabelOfDesigner';
import { SelectWithTitle } from '../../../../common/SelectWithTitle';
export const Resizable = () => { export const Resizable = () => {
const { t } = useTranslation(); const { t } = useTranslation();
@ -112,6 +112,7 @@ export const SchemaSettingsFixed = () => {
</SchemaInitializerItem> </SchemaInitializerItem>
); );
}; };
const commonOptions = { const commonOptions = {
insertPosition: 'beforeEnd', insertPosition: 'beforeEnd',
useInsert: function useInsert() { useInsert: function useInsert() {
@ -154,145 +155,130 @@ const commonOptions = {
}, },
items: [ items: [
{ {
type: 'itemGroup', type: 'item',
name: 'actions', title: '{{t("View")}}',
title: '{{t("Enable actions")}}', name: 'view',
children: [ Component: 'ViewActionInitializer',
{ schema: {
type: 'item', 'x-component': 'Action.Link',
title: '{{t("View")}}', 'x-action': 'view',
name: 'view', 'x-decorator': 'ACLActionProvider',
Component: 'ViewActionInitializer', },
schema: { },
'x-component': 'Action.Link', {
'x-action': 'view', type: 'item',
'x-decorator': 'ACLActionProvider', name: 'edit',
}, title: '{{t("Edit")}}',
}, Component: 'UpdateActionInitializer',
{ schema: {
type: 'item', 'x-component': 'Action.Link',
name: 'edit', 'x-action': 'update',
title: '{{t("Edit")}}', 'x-decorator': 'ACLActionProvider',
Component: 'UpdateActionInitializer', },
schema: { useVisible() {
'x-component': 'Action.Link', const collection = useCollection_deprecated();
'x-action': 'update', return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
'x-decorator': 'ACLActionProvider', },
}, },
useVisible() { {
const collection = useCollection_deprecated(); type: 'item',
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql'; title: '{{t("Delete")}}',
}, name: 'delete',
}, Component: 'DestroyActionInitializer',
{ schema: {
type: 'item', 'x-component': 'Action.Link',
title: '{{t("Delete")}}', 'x-action': 'destroy',
name: 'delete', 'x-decorator': 'ACLActionProvider',
Component: 'DestroyActionInitializer', },
schema: { useVisible() {
'x-component': 'Action.Link', const collection = useCollection_deprecated();
'x-action': 'destroy', return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
'x-decorator': 'ACLActionProvider', },
}, },
useVisible() { {
const collection = useCollection_deprecated(); type: 'item',
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql'; title: '{{t("Disassociate")}}',
}, name: 'disassociate',
}, Component: 'DisassociateActionInitializer',
{ schema: {
type: 'item', 'x-component': 'Action.Link',
title: '{{t("Disassociate")}}', 'x-action': 'disassociate',
name: 'disassociate', 'x-acl-action': 'destroy',
Component: 'DisassociateActionInitializer', 'x-decorator': 'ACLActionProvider',
schema: { },
'x-component': 'Action.Link', useVisible() {
'x-action': 'disassociate', const props = useDataBlockProps();
'x-acl-action': 'destroy', const collection = useCollection_deprecated();
'x-decorator': 'ACLActionProvider', return (
}, !!props?.association &&
useVisible() { (collection.template !== 'view' || collection?.writableView) &&
const props = useDataBlockProps(); collection.template !== 'sql'
const collection = useCollection_deprecated(); );
return ( },
!!props?.association && },
(collection.template !== 'view' || collection?.writableView) && {
collection.template !== 'sql' type: 'item',
); title: '{{t("Add child")}}',
}, name: 'addChildren',
}, Component: 'CreateChildInitializer',
{ schema: {
type: 'item', 'x-component': 'Action.Link',
title: '{{t("Add child")}}', 'x-action': 'create',
name: 'addChildren', 'x-decorator': 'ACLActionProvider',
Component: 'CreateChildInitializer', },
schema: { useVisible() {
'x-component': 'Action.Link', const fieldSchema = useFieldSchema();
'x-action': 'create', const collection = useCollection_deprecated();
'x-decorator': 'ACLActionProvider', const { treeTable } = fieldSchema?.parent?.parent['x-decorator-props'] || {};
}, return collection.tree && treeTable;
useVisible() { },
const fieldSchema = useFieldSchema(); },
const collection = useCollection_deprecated(); {
const { treeTable } = fieldSchema?.parent?.parent['x-decorator-props'] || {}; type: 'item',
return collection.tree && treeTable; title: '{{t("Popup")}}',
}, name: 'popup',
}, Component: 'PopupActionInitializer',
], },
{
type: 'item',
title: '{{t("Update record")}}',
name: 'updateRecord',
Component: 'UpdateRecordActionInitializer',
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
schema: {
'x-action': 'customize:table:request',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
}, },
{ {
name: 'divider', name: 'divider',
type: 'divider', type: 'divider',
}, sort: 100,
{
type: 'subMenu',
title: '{{t("Customize")}}',
name: 'customize',
children: [
{
type: 'item',
title: '{{t("Popup")}}',
name: 'popup',
Component: 'PopupActionInitializer',
},
{
type: 'item',
title: '{{t("Update record")}}',
name: 'updateRecord',
Component: 'UpdateRecordActionInitializer',
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
schema: {
'x-action': 'customize:table:request',
},
useVisible() {
const collection = useCollection_deprecated();
return (collection.template !== 'view' || collection?.writableView) && collection.template !== 'sql';
},
},
],
},
{
name: 'divider2',
type: 'divider',
}, },
{ {
name: 'fixed', name: 'fixed',
title: 't("Fixed")', title: 't("Fixed")',
type: 'item', type: 'item',
Component: SchemaSettingsFixed, Component: SchemaSettingsFixed,
sort: 100,
}, },
{ {
type: 'item', type: 'item',
name: 'columnWidth', name: 'columnWidth',
title: 't("Column width")', title: 't("Column width")',
Component: Resizable, Component: Resizable,
sort: 100,
}, },
], ],
}; };

View File

@ -11,13 +11,7 @@ import { useFieldSchema } from '@formily/react';
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCollection_deprecated } from '../../../../collection-manager/hooks/useCollection_deprecated'; import { useCollection_deprecated } from '../../../../collection-manager/hooks/useCollection_deprecated';
/** const commonOptions = {
* @deprecated
* use `tableActionInitializers` instead
*
*/
export const tableActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'TableActionInitializers',
title: "{{t('Configure actions')}}", title: "{{t('Configure actions')}}",
icon: 'SettingOutlined', icon: 'SettingOutlined',
style: { style: {
@ -25,224 +19,85 @@ export const tableActionInitializers_deprecated = new CompatibleSchemaInitialize
}, },
items: [ items: [
{ {
type: 'itemGroup', type: 'item',
name: 'enableActions', name: 'filter',
title: "{{t('Enable actions')}}", title: "{{t('Filter')}}",
children: [ Component: 'FilterActionInitializer',
{ schema: {
type: 'item', 'x-align': 'left',
name: 'filter', },
title: "{{t('Filter')}}",
Component: 'FilterActionInitializer',
schema: {
'x-align': 'left',
},
},
{
type: 'item',
title: "{{t('Add new')}}",
name: 'addNew',
Component: 'CreateActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
useVisible() {
const collection = useCollection_deprecated();
return !['view', 'file', 'sql'].includes(collection.template) || collection?.writableView;
},
},
{
type: 'item',
title: "{{t('Delete')}}",
name: 'delete',
Component: 'BulkDestroyActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
},
useVisible() {
const collection = useCollection_deprecated();
return !['view', 'sql'].includes(collection.template) || collection?.writableView;
},
},
{
type: 'item',
title: "{{t('Refresh')}}",
name: 'refresh',
Component: 'RefreshActionInitializer',
schema: {
'x-align': 'right',
},
},
{
name: 'toggle',
title: "{{t('Expand/Collapse')}}",
Component: 'ExpandableActionInitializer',
schema: {
'x-align': 'right',
},
useVisible() {
const schema = useFieldSchema();
const collection = useCollection_deprecated();
const { treeTable } = schema?.parent?.['x-decorator-props'] || {};
return collection.tree && treeTable;
},
},
],
}, },
{ {
name: 'divider', type: 'item',
type: 'divider', title: "{{t('Add new')}}",
name: 'addNew',
Component: 'CreateActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
useVisible() {
const collection = useCollection_deprecated();
return !['view', 'file', 'sql'].includes(collection.template) || collection?.writableView;
},
},
{
type: 'item',
title: "{{t('Delete')}}",
name: 'delete',
Component: 'BulkDestroyActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
},
useVisible() { useVisible() {
const collection = useCollection_deprecated(); const collection = useCollection_deprecated();
return !['view', 'sql'].includes(collection.template) || collection?.writableView; return !['view', 'sql'].includes(collection.template) || collection?.writableView;
}, },
}, },
{ {
type: 'subMenu', type: 'item',
name: 'customize', title: "{{t('Refresh')}}",
title: '{{t("Customize")}}', name: 'refresh',
children: [ Component: 'RefreshActionInitializer',
{ schema: {
type: 'item', 'x-align': 'right',
title: '{{t("Add record")}}', },
name: 'addRecord', },
Component: 'CustomizeAddRecordActionInitializer', {
schema: { name: 'toggle',
'x-align': 'right', title: "{{t('Expand/Collapse')}}",
'x-decorator': 'ACLActionProvider', Component: 'ExpandableActionInitializer',
'x-acl-action': 'create', schema: {
'x-acl-action-props': { 'x-align': 'right',
skipScopeCheck: true, },
},
},
},
],
useVisible() { useVisible() {
const schema = useFieldSchema();
const collection = useCollection_deprecated(); const collection = useCollection_deprecated();
return !['view', 'sql'].includes(collection.template) || collection?.writableView; const { treeTable } = schema?.parent?.['x-decorator-props'] || {};
return collection.tree && treeTable;
}, },
}, },
], ],
};
/**
* @deprecated
* use `tableActionInitializers` instead
*
*/
export const tableActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'TableActionInitializers',
...commonOptions,
}); });
export const tableActionInitializers = new CompatibleSchemaInitializer( export const tableActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'table:configureActions', name: 'table:configureActions',
title: "{{t('Configure actions')}}", ...commonOptions,
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'itemGroup',
name: 'enableActions',
title: "{{t('Enable actions')}}",
children: [
{
type: 'item',
name: 'filter',
title: "{{t('Filter')}}",
Component: 'FilterActionInitializer',
schema: {
'x-align': 'left',
},
},
{
type: 'item',
title: "{{t('Add new')}}",
name: 'addNew',
Component: 'CreateActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
useVisible() {
const collection = useCollection_deprecated();
return !['view', 'file', 'sql'].includes(collection.template) || collection?.writableView;
},
},
{
type: 'item',
title: "{{t('Delete')}}",
name: 'delete',
Component: 'BulkDestroyActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
},
useVisible() {
const collection = useCollection_deprecated();
return !['view', 'sql'].includes(collection.template) || collection?.writableView;
},
},
{
type: 'item',
title: "{{t('Refresh')}}",
name: 'refresh',
Component: 'RefreshActionInitializer',
schema: {
'x-align': 'right',
},
},
{
name: 'toggle',
title: "{{t('Expand/Collapse')}}",
Component: 'ExpandableActionInitializer',
schema: {
'x-align': 'right',
},
useVisible() {
const schema = useFieldSchema();
const collection = useCollection_deprecated();
const { treeTable } = schema?.parent?.['x-decorator-props'] || {};
return collection.tree && treeTable;
},
},
],
},
{
name: 'divider',
type: 'divider',
useVisible() {
const collection = useCollection_deprecated();
return !['view', 'sql'].includes(collection.template) || collection?.writableView;
},
},
{
type: 'subMenu',
name: 'customize',
title: '{{t("Customize")}}',
children: [
{
type: 'item',
title: '{{t("Add record")}}',
name: 'addRecord',
Component: 'CustomizeAddRecordActionInitializer',
schema: {
'x-align': 'right',
'x-decorator': 'ACLActionProvider',
'x-acl-action': 'create',
'x-acl-action-props': {
skipScopeCheck: true,
},
},
},
],
useVisible() {
const collection = useCollection_deprecated();
return !['view', 'sql'].includes(collection.template) || collection?.writableView;
},
},
],
}, },
tableActionInitializers_deprecated, tableActionInitializers_deprecated,
); );

View File

@ -7,9 +7,16 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { expect, oneEmptyTable, test } from '@nocobase/test/e2e'; import { Page, expect, oneEmptyTable, test } from '@nocobase/test/e2e';
import { oneTableWithInheritFields } from './templatesOfBug'; import { oneTableWithInheritFields } from './templatesOfBug';
const deleteButton = async (page: Page, name: string) => {
await page.getByLabel(`action-Action.Link-${name}-`).hover();
await page.getByLabel(`action-Action.Link-${name}-`).getByLabel('designer-schema-settings-').hover();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
};
test.describe('configure columns', () => { test.describe('configure columns', () => {
// 该用例在 CI 并发环境下容易报错,原因未知,通过增加重试次数可以解决 // 该用例在 CI 并发环境下容易报错,原因未知,通过增加重试次数可以解决
test.describe.configure({ retries: process.env.CI ? 4 : 0 }); test.describe.configure({ retries: process.env.CI ? 4 : 0 });
@ -135,11 +142,6 @@ test.describe('configure actions column', () => {
await page.getByRole('menuitem', { name: 'Delete' }).click(); await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('menuitem', { name: 'Duplicate' }).click(); await page.getByRole('menuitem', { name: 'Duplicate' }).click();
await expect(page.getByRole('menuitem', { name: 'View' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Edit' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Duplicate' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByLabel('action-Action.Link-View-view-t_unp4scqamw9-table-0')).toBeVisible(); await expect(page.getByLabel('action-Action.Link-View-view-t_unp4scqamw9-table-0')).toBeVisible();
await expect(page.getByLabel('action-Action.Link-Edit-update-t_unp4scqamw9-table-0')).toBeVisible(); await expect(page.getByLabel('action-Action.Link-Edit-update-t_unp4scqamw9-table-0')).toBeVisible();
@ -147,17 +149,10 @@ test.describe('configure actions column', () => {
await expect(page.getByLabel('action-Action.Link-Duplicate-duplicate-t_unp4scqamw9-table-0')).toBeVisible(); await expect(page.getByLabel('action-Action.Link-Duplicate-duplicate-t_unp4scqamw9-table-0')).toBeVisible();
// delete view & Edit & Delete & Duplicate ------------------------------------------------------------ // delete view & Edit & Delete & Duplicate ------------------------------------------------------------
await page.getByText('Actions', { exact: true }).hover(); await deleteButton(page, 'View');
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-t_unp4scqamw9').hover(); await deleteButton(page, 'Edit');
await page.getByRole('menuitem', { name: 'View' }).click(); await deleteButton(page, 'Delete');
await page.getByRole('menuitem', { name: 'Edit' }).click(); await deleteButton(page, 'Duplicate');
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('menuitem', { name: 'Duplicate' }).click();
await expect(page.getByRole('menuitem', { name: 'View' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Edit' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Duplicate' }).getByRole('switch')).not.toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByLabel('action-Action.Link-View-view-t_unp4scqamw9-table-0')).not.toBeVisible(); await expect(page.getByLabel('action-Action.Link-View-view-t_unp4scqamw9-table-0')).not.toBeVisible();
@ -168,7 +163,6 @@ test.describe('configure actions column', () => {
// add custom action ------------------------------------------------------------ // add custom action ------------------------------------------------------------
await page.getByText('Actions', { exact: true }).hover(); await page.getByText('Actions', { exact: true }).hover();
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-t_unp4scqamw9').hover(); await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-t_unp4scqamw9').hover();
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: 'Popup' }).click(); await page.getByRole('menuitem', { name: 'Popup' }).click();
// 此时二级菜单,不应该关闭,可以继续点击? // 此时二级菜单,不应该关闭,可以继续点击?

View File

@ -7,9 +7,16 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { createBlockInPage, expect, oneEmptyTable, test } from '@nocobase/test/e2e'; import { Page, createBlockInPage, expect, oneEmptyTable, test } from '@nocobase/test/e2e';
import { T3686, T4005 } from './templatesOfBug'; import { T3686, T4005 } from './templatesOfBug';
const deleteButton = async (page: Page, name: string) => {
await page.getByRole('button', { name }).hover();
await page.getByRole('button', { name }).getByLabel('designer-schema-settings-').hover();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
};
test.describe('where table block can be added', () => { test.describe('where table block can be added', () => {
test('page', async ({ page, mockPage }) => { test('page', async ({ page, mockPage }) => {
await mockPage().goto(); await mockPage().goto();
@ -116,11 +123,6 @@ test.describe('configure actions', () => {
await page.getByRole('menuitem', { name: 'Delete' }).click(); await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('menuitem', { name: 'Refresh' }).click(); await page.getByRole('menuitem', { name: 'Refresh' }).click();
await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Filter' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible();
@ -128,16 +130,10 @@ test.describe('configure actions', () => {
await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible();
// delete buttons // delete buttons
await page.getByLabel('schema-initializer-ActionBar-table:configureActions-t_unp4scqamw9').hover(); await deleteButton(page, 'Filter');
await page.getByRole('menuitem', { name: 'Filter' }).click(); await deleteButton(page, 'Add new');
await page.getByRole('menuitem', { name: 'Add new' }).click(); await deleteButton(page, 'Delete');
await page.getByRole('menuitem', { name: 'Delete' }).click(); await deleteButton(page, 'Refresh');
await page.getByRole('menuitem', { name: 'Refresh' }).click();
await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Add new' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Delete' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Refresh' }).getByRole('switch')).not.toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible();
@ -145,15 +141,4 @@ test.describe('configure actions', () => {
await expect(page.getByRole('button', { name: 'Delete' })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Delete' })).not.toBeVisible();
await expect(page.getByRole('button', { name: 'Refresh' })).not.toBeVisible(); await expect(page.getByRole('button', { name: 'Refresh' })).not.toBeVisible();
}); });
test('customize: add record', async ({ page, mockPage }) => {
await mockPage(oneEmptyTable).goto();
await page.getByLabel('schema-initializer-ActionBar-table:configureActions-t_unp4scqamw9').hover();
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: 'add record' }).click();
await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Add record' })).toBeVisible();
});
}); });

View File

@ -19,6 +19,27 @@ import {
} from '@nocobase/test/e2e'; } from '@nocobase/test/e2e';
import { T3843, oneTableWithColumnFixed, oneTableWithUpdateRecord } from './templatesOfBug'; import { T3843, oneTableWithColumnFixed, oneTableWithUpdateRecord } from './templatesOfBug';
const addSomeCustomActions = async (page: Page) => {
// 先删除掉之前的 actions
const deleteAction = async (name: string) => {
await page.getByLabel(`action-Action.Link-${name}-`).hover();
await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-Action.Designer-general' }).hover();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
};
await deleteAction('View');
await deleteAction('Edit');
await deleteAction('Delete');
await deleteAction('Duplicate');
// 再增加两个自定义的 actions
await page.getByRole('button', { name: 'Actions', exact: true }).hover();
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-general').hover();
await page.getByRole('menuitem', { name: 'Popup' }).click();
await page.getByRole('menuitem', { name: 'Update record' }).click();
};
test.describe('actions schema settings', () => { test.describe('actions schema settings', () => {
test.describe('add new', () => { test.describe('add new', () => {
const showMenu = async (page: Page) => { const showMenu = async (page: Page) => {
@ -295,21 +316,6 @@ test.describe('actions schema settings', () => {
}); });
test.describe('popup', () => { test.describe('popup', () => {
const addSomeCustomActions = async (page: Page) => {
// 先删除掉之前的 actions
await page.getByRole('button', { name: 'Actions', exact: true }).hover();
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-general').hover();
await page.getByRole('menuitem', { name: 'View' }).click();
await page.getByRole('menuitem', { name: 'Edit' }).click();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('menuitem', { name: 'Duplicate' }).click();
// 再增加两个自定义的 actions
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: 'Popup' }).click();
await page.getByRole('menuitem', { name: 'Update record' }).click();
};
const showMenu = async (page: Page) => { const showMenu = async (page: Page) => {
await page.getByLabel('action-Action.Link-Popup-customize:popup-general-table-0').hover(); await page.getByLabel('action-Action.Link-Popup-customize:popup-general-table-0').hover();
await page await page
@ -352,21 +358,6 @@ test.describe('actions schema settings', () => {
}); });
test.describe('update record', () => { test.describe('update record', () => {
const addSomeCustomActions = async (page: Page) => {
// 先删除掉之前的 actions
await page.getByRole('button', { name: 'Actions', exact: true }).hover();
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-general').hover();
await page.getByRole('menuitem', { name: 'View' }).click();
await page.getByRole('menuitem', { name: 'Edit' }).click();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('menuitem', { name: 'Duplicate' }).click();
// 再增加两个自定义的 actions
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: 'Popup' }).click();
await page.getByRole('menuitem', { name: 'Update record' }).click();
};
const showMenu = async (page: Page) => { const showMenu = async (page: Page) => {
await page.getByLabel('action-Action.Link-Update record-customize:update-general-table-0').hover(); await page.getByLabel('action-Action.Link-Update record-customize:update-general-table-0').hover();
await page await page
@ -403,7 +394,6 @@ test.describe('actions schema settings', () => {
if (!(await page.getByLabel('action-Action.Link-Update record-customize:update-users2-table-0').isVisible())) { if (!(await page.getByLabel('action-Action.Link-Update record-customize:update-users2-table-0').isVisible())) {
await page.getByRole('button', { name: 'Actions', exact: true }).hover(); await page.getByRole('button', { name: 'Actions', exact: true }).hover();
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-users2').hover(); await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-users2').hover();
await page.getByRole('menuitem', { name: 'Customize right' }).hover();
await page.getByRole('menuitem', { name: 'Update record' }).click(); await page.getByRole('menuitem', { name: 'Update record' }).click();
} }
@ -473,7 +463,8 @@ test.describe('actions schema settings', () => {
await page.getByRole('menuitem', { name: 'Add new' }).click(); await page.getByRole('menuitem', { name: 'Add new' }).click();
await page.getByRole('button', { name: 'Add new' }).click(); await page.getByRole('button', { name: 'Add new' }).click();
await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-treeCollection').hover(); await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-treeCollection').hover();
await page.getByRole('menuitem', { name: 'form Form' }).click(); await page.getByRole('menuitem', { name: 'form Form' }).hover();
await page.getByRole('menuitem', { name: 'Current collection' }).click();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await page.getByLabel('schema-initializer-ActionBar-createForm:configureActions-treeCollection').hover(); await page.getByLabel('schema-initializer-ActionBar-createForm:configureActions-treeCollection').hover();
await page.getByRole('menuitem', { name: 'Submit' }).click(); await page.getByRole('menuitem', { name: 'Submit' }).click();
@ -500,7 +491,8 @@ test.describe('actions schema settings', () => {
position: { x: 5, y: 5 }, // 防止按钮被遮挡 position: { x: 5, y: 5 }, // 防止按钮被遮挡
}); });
await page.getByLabel('schema-initializer-Grid-popup').hover(); await page.getByLabel('schema-initializer-Grid-popup').hover();
await page.getByRole('menuitem', { name: 'form Form' }).click(); await page.getByRole('menuitem', { name: 'form Form' }).hover();
await page.getByRole('menuitem', { name: 'Current collection' }).click();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await page.getByLabel('schema-initializer-Grid-form:').hover(); await page.getByLabel('schema-initializer-Grid-form:').hover();
await page.getByRole('menuitem', { name: 'Parent', exact: true }).click(); await page.getByRole('menuitem', { name: 'Parent', exact: true }).click();

View File

@ -8,6 +8,28 @@
*/ */
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
const commonOptions = {
title: '{{t("Configure actions")}}',
icon: 'SettingOutlined',
items: [
{
name: 'filter',
title: '{{t("Filter")}}',
Component: 'CreateFilterActionInitializer',
schema: {
'x-action-settings': {},
},
},
{
name: 'reset',
title: '{{t("Reset")}}',
Component: 'CreateResetActionInitializer',
schema: {
'x-action-settings': {},
},
},
],
};
/** /**
* @deprecated * @deprecated
@ -16,65 +38,13 @@ import { CompatibleSchemaInitializer } from '../../../../application/schema-init
*/ */
export const filterFormActionInitializers_deprecated = new CompatibleSchemaInitializer({ export const filterFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'FilterFormActionInitializers', name: 'FilterFormActionInitializers',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Enable actions")}}',
name: 'enableActions',
children: [
{
name: 'filter',
title: '{{t("Filter")}}',
Component: 'CreateFilterActionInitializer',
schema: {
'x-action-settings': {},
},
},
{
name: 'reset',
title: '{{t("Reset")}}',
Component: 'CreateResetActionInitializer',
schema: {
'x-action-settings': {},
},
},
],
},
],
}); });
export const filterFormActionInitializers = new CompatibleSchemaInitializer( export const filterFormActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'filterForm:configureActions', name: 'filterForm:configureActions',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Enable actions")}}',
name: 'enableActions',
children: [
{
name: 'filter',
title: '{{t("Filter")}}',
Component: 'CreateFilterActionInitializer',
schema: {
'x-action-settings': {},
},
},
{
name: 'reset',
title: '{{t("Reset")}}',
Component: 'CreateResetActionInitializer',
schema: {
'x-action-settings': {},
},
},
],
},
],
}, },
filterFormActionInitializers_deprecated, filterFormActionInitializers_deprecated,
); );

View File

@ -7,9 +7,16 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { createBlockInPage, expect, oneEmptyFilterFormBlock, test } from '@nocobase/test/e2e'; import { Page, createBlockInPage, expect, oneEmptyFilterFormBlock, test } from '@nocobase/test/e2e';
import { oneFilterFormWithInherit } from './templatesOfBug'; import { oneFilterFormWithInherit } from './templatesOfBug';
const deleteButton = async (page: Page, name: string) => {
await page.getByLabel(`action-Action-${name}-`).hover();
await page.getByLabel(`action-Action-${name}-`).getByLabel('designer-schema-settings-').hover();
await page.getByRole('menuitem', { name: 'Delete' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
};
test.describe('where filter form block can be added', () => { test.describe('where filter form block can be added', () => {
test('page', async ({ page, mockPage }) => { test('page', async ({ page, mockPage }) => {
await mockPage().goto(); await mockPage().goto();
@ -104,21 +111,13 @@ test.describe('configure actions', () => {
await page.getByRole('menuitem', { name: 'Filter' }).click(); await page.getByRole('menuitem', { name: 'Filter' }).click();
await page.getByRole('menuitem', { name: 'Reset' }).click(); await page.getByRole('menuitem', { name: 'Reset' }).click();
await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Reset' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByLabel('action-Action-Filter-submit-general-filter-form')).toBeVisible(); await expect(page.getByLabel('action-Action-Filter-submit-general-filter-form')).toBeVisible();
await expect(page.getByLabel('action-Action-Reset-general-filter-form')).toBeVisible(); await expect(page.getByLabel('action-Action-Reset-general-filter-form')).toBeVisible();
// delete buttons // delete buttons
await page.getByLabel('schema-initializer-ActionBar-filterForm:configureActions-general').hover(); await deleteButton(page, 'Filter');
await page.getByRole('menuitem', { name: 'Filter' }).click(); await deleteButton(page, 'Reset');
await page.getByRole('menuitem', { name: 'Reset' }).click();
await expect(page.getByRole('menuitem', { name: 'Filter' }).getByRole('switch')).not.toBeChecked();
await expect(page.getByRole('menuitem', { name: 'Reset' }).getByRole('switch')).not.toBeChecked();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByLabel('action-Action-Filter-submit-general-filter-form')).not.toBeVisible(); await expect(page.getByLabel('action-Action-Filter-submit-general-filter-form')).not.toBeVisible();
await expect(page.getByLabel('action-Action-Reset-general-filter-form')).not.toBeVisible(); await expect(page.getByLabel('action-Action-Reset-general-filter-form')).not.toBeVisible();

View File

@ -14,12 +14,7 @@ import {
} from '../../../../schema-initializer/buttons/FormItemInitializers'; } from '../../../../schema-initializer/buttons/FormItemInitializers';
import { gridRowColWrap, useFilterFormItemInitializerFields } from '../../../../schema-initializer/utils'; import { gridRowColWrap, useFilterFormItemInitializerFields } from '../../../../schema-initializer/utils';
/** const commonOptions = {
* @deprecated
* use `filterFormItemInitializers` instead
*/
export const filterFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'FilterFormItemInitializers',
wrap: gridRowColWrap, wrap: gridRowColWrap,
icon: 'SettingOutlined', icon: 'SettingOutlined',
title: '{{t("Configure fields")}}', title: '{{t("Configure fields")}}',
@ -48,39 +43,21 @@ export const filterFormItemInitializers_deprecated = new CompatibleSchemaInitial
name: 'addText', name: 'addText',
}, },
], ],
};
/**
* @deprecated
* use `filterFormItemInitializers` instead
*/
export const filterFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'FilterFormItemInitializers',
...commonOptions,
}); });
export const filterFormItemInitializers = new CompatibleSchemaInitializer( export const filterFormItemInitializers = new CompatibleSchemaInitializer(
{ {
name: 'filterForm:configureFields', name: 'filterForm:configureFields',
wrap: gridRowColWrap, ...commonOptions,
icon: 'SettingOutlined',
title: '{{t("Configure fields")}}',
items: [
{
type: 'itemGroup',
name: 'displayFields',
title: '{{t("Display fields")}}',
useChildren: useFilterFormItemInitializerFields,
},
{
name: 'parentCollectionFields',
Component: FilterParentCollectionFields,
},
{
name: 'associationFields',
Component: FilterAssociatedFields,
},
{
name: 'divider',
type: 'divider',
},
{
title: '{{t("Add text")}}',
Component: 'MarkdownFormItemInitializer',
name: 'addText',
},
],
}, },
filterFormItemInitializers_deprecated, filterFormItemInitializers_deprecated,
); );

View File

@ -10,12 +10,7 @@
import { CompatibleSchemaInitializer } from '../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../application/schema-initializer/CompatibleSchemaInitializer';
import { gridRowColWrap } from '../../schema-initializer/utils'; import { gridRowColWrap } from '../../schema-initializer/utils';
/** const commonOptions = {
* @deprecated
* use `blockInitializers` instead
*/
export const blockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BlockInitializers',
title: '{{t("Add block")}}', title: '{{t("Add block")}}',
icon: 'PlusOutlined', icon: 'PlusOutlined',
wrap: gridRowColWrap, wrap: gridRowColWrap,
@ -82,77 +77,21 @@ export const blockInitializers_deprecated = new CompatibleSchemaInitializer({
], ],
}, },
], ],
};
/**
* @deprecated
* use `blockInitializers` instead
*/
export const blockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BlockInitializers',
...commonOptions,
}); });
export const blockInitializers = new CompatibleSchemaInitializer( export const blockInitializers = new CompatibleSchemaInitializer(
{ {
name: 'page:addBlock', name: 'page:addBlock',
title: '{{t("Add block")}}', ...commonOptions,
icon: 'PlusOutlined',
wrap: gridRowColWrap,
items: [
{
name: 'dataBlocks',
title: '{{t("Data blocks")}}',
type: 'itemGroup',
children: [
{
name: 'table',
title: '{{t("Table")}}',
Component: 'TableBlockInitializer',
},
{
name: 'form',
title: '{{t("Form")}}',
Component: 'FormBlockInitializer',
},
{
name: 'details',
title: '{{t("Details")}}',
Component: 'DetailsBlockInitializer',
},
{
name: 'list',
title: '{{t("List")}}',
Component: 'ListBlockInitializer',
},
{
name: 'gridCard',
title: '{{t("Grid Card")}}',
Component: 'GridCardBlockInitializer',
},
],
},
{
name: 'filterBlocks',
title: '{{t("Filter blocks")}}',
type: 'itemGroup',
children: [
{
name: 'filterForm',
title: '{{t("Form")}}',
Component: 'FilterFormBlockInitializer',
},
{
name: 'filterCollapse',
title: '{{t("Collapse")}}',
Component: 'FilterCollapseBlockInitializer',
},
],
},
{
name: 'otherBlocks',
type: 'itemGroup',
title: '{{t("Other blocks")}}',
children: [
{
name: 'markdown',
title: '{{t("Markdown")}}',
Component: 'MarkdownBlockInitializer',
},
],
},
],
}, },
blockInitializers_deprecated, blockInitializers_deprecated,
); );

View File

@ -33,8 +33,9 @@ test.describe('where to open a popup and what can be added to it', () => {
// add blocks // add blocks
await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-general').hover(); await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-general').hover();
await page.getByText('Form').click();
await page.getByText('Markdown').click(); await page.getByText('Markdown').click();
await page.getByText('Form').hover();
await page.getByRole('menuitem', { name: 'Current collection' }).click();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);

View File

@ -14,7 +14,7 @@ import { SchemaComponentContext, createDesignable } from '../..';
import { useAPIClient } from '../../../api-client'; import { useAPIClient } from '../../../api-client';
import { useBlockRequestContext } from '../../../block-provider'; import { useBlockRequestContext } from '../../../block-provider';
import { mergeFilter } from '../../../filter-provider/utils'; import { mergeFilter } from '../../../filter-provider/utils';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer'; import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
/** /**
* @deprecated * @deprecated
@ -58,5 +58,5 @@ export const ActionBarAssociationFilterAction = (props) => {
wrap: (s) => s, wrap: (s) => s,
}; };
return <ActionInitializer {...newProps} schema={schema} />; return <ActionInitializerItem {...newProps} schema={schema} />;
}; };

View File

@ -33,12 +33,7 @@ const ParentCollectionFields = () => {
return <SchemaInitializerChildren>{res}</SchemaInitializerChildren>; return <SchemaInitializerChildren>{res}</SchemaInitializerChildren>;
}; };
/** const commonOptions = {
* @deprecated
* use `customFormItemInitializers` instead
*/
export const customFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CustomFormItemInitializers',
wrap: gridRowColWrap, wrap: gridRowColWrap,
icon: 'SettingOutlined', icon: 'SettingOutlined',
title: '{{t("Configure fields")}}', title: '{{t("Configure fields")}}',
@ -54,26 +49,21 @@ export const customFormItemInitializers_deprecated = new CompatibleSchemaInitial
Component: ParentCollectionFields, Component: ParentCollectionFields,
}, },
], ],
};
/**
* @deprecated
* use `customFormItemInitializers` instead
*/
export const customFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CustomFormItemInitializers',
...commonOptions,
}); });
export const customFormItemInitializers = new CompatibleSchemaInitializer( export const customFormItemInitializers = new CompatibleSchemaInitializer(
{ {
name: 'assignFieldValuesForm:configureFields', name: 'assignFieldValuesForm:configureFields',
wrap: gridRowColWrap, ...commonOptions,
icon: 'SettingOutlined',
title: '{{t("Configure fields")}}',
items: [
{
type: 'itemGroup',
title: '{{t("Configure fields")}}',
name: 'configureFields',
useChildren: useCustomFormItemInitializerFields,
},
{
name: 'parentCollectionFields',
Component: ParentCollectionFields,
},
],
}, },
customFormItemInitializers_deprecated, customFormItemInitializers_deprecated,
); );

View File

@ -170,13 +170,13 @@ function useRecordBlocks() {
componentType: 'FormItem', componentType: 'FormItem',
createBlockSchema: ({ item, fromOthersInPopup }) => { createBlockSchema: ({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) { if (fromOthersInPopup) {
return createFormBlock({ item }); return createFormBlock({ item, fromOthersInPopup });
} }
createAssociationFormBlock({ item }); createAssociationFormBlock({ item });
}, },
templateWrap: (templateSchema, { item, fromOthersInPopup }) => { templateWrap: (templateSchema, { item, fromOthersInPopup }) => {
if (fromOthersInPopup) { if (fromOthersInPopup) {
return templateWrapCollection(templateSchema, { item }); return templateWrapCollection(templateSchema, { item, fromOthersInPopup });
} }
templateWrap(templateSchema, { item }); templateWrap(templateSchema, { item });
}, },

View File

@ -9,13 +9,7 @@
import { CompatibleSchemaInitializer } from '../../application/schema-initializer/CompatibleSchemaInitializer'; import { CompatibleSchemaInitializer } from '../../application/schema-initializer/CompatibleSchemaInitializer';
/** const commonOptions = {
* @deprecated
* use `subTableActionInitializers` instead
*
*/
export const subTableActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'SubTableActionInitializers',
title: "{{t('Configure actions')}}", title: "{{t('Configure actions')}}",
icon: 'SettingOutlined', icon: 'SettingOutlined',
style: { style: {
@ -46,41 +40,22 @@ export const subTableActionInitializers_deprecated = new CompatibleSchemaInitial
], ],
}, },
], ],
};
/**
* @deprecated
* use `subTableActionInitializers` instead
*
*/
export const subTableActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'SubTableActionInitializers',
...commonOptions,
}); });
export const subTableActionInitializers = new CompatibleSchemaInitializer( export const subTableActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'subTable:configureActions', name: 'subTable:configureActions',
title: "{{t('Configure actions')}}", ...commonOptions,
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'itemGroup',
title: "{{t('Enable actions')}}",
name: 'enableActions',
children: [
{
name: 'addNew',
title: "{{t('Add new')}}",
Component: 'CreateActionInitializer',
schema: {
'x-align': 'right',
},
},
{
name: 'delete',
title: "{{t('Delete')}}",
Component: 'BulkDestroyActionInitializer',
schema: {
'x-align': 'right',
},
},
],
},
],
}, },
subTableActionInitializers_deprecated, subTableActionInitializers_deprecated,
); );

View File

@ -14,7 +14,6 @@ import {
createFormBlockInitializers, createFormBlockInitializers,
createFormBlockInitializers_deprecated, createFormBlockInitializers_deprecated,
} from '../modules/actions/add-new/createFormBlockInitializers'; } from '../modules/actions/add-new/createFormBlockInitializers';
import { CustomizeAddRecordActionInitializer } from '../modules/actions/add-record/CustomizeAddRecordActionInitializer';
import { import {
customizeCreateFormBlockInitializers, customizeCreateFormBlockInitializers,
customizeCreateFormBlockInitializers_deprecated, customizeCreateFormBlockInitializers_deprecated,
@ -25,7 +24,6 @@ import { DisassociateActionInitializer } from '../modules/actions/disassociate/D
import { ExpandableActionInitializer } from '../modules/actions/expand-collapse/ExpandableActionInitializer'; import { ExpandableActionInitializer } from '../modules/actions/expand-collapse/ExpandableActionInitializer';
import { FilterActionInitializer } from '../modules/actions/filter/FilterActionInitializer'; import { FilterActionInitializer } from '../modules/actions/filter/FilterActionInitializer';
import { RefreshActionInitializer } from '../modules/actions/refresh/RefreshActionInitializer'; import { RefreshActionInitializer } from '../modules/actions/refresh/RefreshActionInitializer';
import { SaveRecordActionInitializer } from '../modules/actions/save-record/SaveRecordActionInitializer';
import { CreateSubmitActionInitializer } from '../modules/actions/submit/CreateSubmitActionInitializer'; import { CreateSubmitActionInitializer } from '../modules/actions/submit/CreateSubmitActionInitializer';
import { UpdateSubmitActionInitializer } from '../modules/actions/submit/UpdateSubmitActionInitializer'; import { UpdateSubmitActionInitializer } from '../modules/actions/submit/UpdateSubmitActionInitializer';
import { UpdateRecordActionInitializer } from '../modules/actions/update-record/UpdateRecordActionInitializer'; import { UpdateRecordActionInitializer } from '../modules/actions/update-record/UpdateRecordActionInitializer';
@ -47,7 +45,6 @@ import {
readPrettyFormItemInitializers_deprecated, readPrettyFormItemInitializers_deprecated,
} from '../modules/blocks/data-blocks/details-single/ReadPrettyFormItemInitializers'; } from '../modules/blocks/data-blocks/details-single/ReadPrettyFormItemInitializers';
import { RecordReadPrettyFormBlockInitializer } from '../modules/blocks/data-blocks/details-single/RecordReadPrettyFormBlockInitializer'; import { RecordReadPrettyFormBlockInitializer } from '../modules/blocks/data-blocks/details-single/RecordReadPrettyFormBlockInitializer';
import { CreateFormBlockInitializer } from '../modules/blocks/data-blocks/form/CreateFormBlockInitializer';
import { FormBlockInitializer } from '../modules/blocks/data-blocks/form/FormBlockInitializer'; import { FormBlockInitializer } from '../modules/blocks/data-blocks/form/FormBlockInitializer';
import { RecordFormBlockInitializer } from '../modules/blocks/data-blocks/form/RecordFormBlockInitializer'; import { RecordFormBlockInitializer } from '../modules/blocks/data-blocks/form/RecordFormBlockInitializer';
import { import {
@ -155,7 +152,6 @@ export class SchemaInitializerPlugin extends Plugin {
...initializerComponents, ...initializerComponents,
...items, ...items,
DestroyActionInitializer, DestroyActionInitializer,
CreateFormBlockInitializer,
FormBlockInitializer, FormBlockInitializer,
RecordFormBlockInitializer, RecordFormBlockInitializer,
TableBlockInitializer, TableBlockInitializer,
@ -171,12 +167,10 @@ export class SchemaInitializerPlugin extends Plugin {
TableCollectionFieldInitializer, TableCollectionFieldInitializer,
CollectionFieldInitializer, CollectionFieldInitializer,
CreateActionInitializer, CreateActionInitializer,
CustomizeAddRecordActionInitializer,
CreateChildInitializer, CreateChildInitializer,
ViewActionInitializer, ViewActionInitializer,
UpdateActionInitializer, UpdateActionInitializer,
PopupActionInitializer, PopupActionInitializer,
SaveRecordActionInitializer,
UpdateRecordActionInitializer, UpdateRecordActionInitializer,
CreateSubmitActionInitializer, CreateSubmitActionInitializer,
UpdateSubmitActionInitializer, UpdateSubmitActionInitializer,

View File

@ -9,9 +9,15 @@
import React from 'react'; import React from 'react';
import { InitializerWithSwitch } from './InitializerWithSwitch';
import { useSchemaInitializerItem } from '../../application'; import { useSchemaInitializerItem } from '../../application';
import { InitializerWithSwitch } from './InitializerWithSwitch';
/**
* @deprecated
* use ActionInitializerItem instead
* @param props
* @returns
*/
export const ActionInitializer = (props) => { export const ActionInitializer = (props) => {
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
return <InitializerWithSwitch {...itemConfig} {...props} item={itemConfig} type={'x-action'} />; return <InitializerWithSwitch {...itemConfig} {...props} item={itemConfig} type={'x-action'} />;

View File

@ -0,0 +1,29 @@
/**
* 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 { merge } from '@formily/shared';
import React from 'react';
import { SchemaInitializerItem, useSchemaInitializer, useSchemaInitializerItem } from '../../application';
export const ActionInitializerItem = (props) => {
const itemConfig = useSchemaInitializerItem();
const { insert } = useSchemaInitializer();
return (
<SchemaInitializerItem
title={itemConfig.title}
onClick={() => {
const s = merge(props.schema || {}, itemConfig.schema || {});
itemConfig?.schemaInitialize?.(s);
insert(s);
}}
/>
);
};

View File

@ -8,7 +8,6 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializer } from './ActionInitializer'; import { ActionInitializer } from './ActionInitializer';
export const CreateFilterActionInitializer = (props) => { export const CreateFilterActionInitializer = (props) => {

View File

@ -8,7 +8,6 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializer } from './ActionInitializer'; import { ActionInitializer } from './ActionInitializer';
export const CreateResetActionInitializer = (props) => { export const CreateResetActionInitializer = (props) => {

View File

@ -301,6 +301,10 @@ export interface DataBlockInitializerProps {
*/ */
hideOtherRecordsInPopup?: boolean; hideOtherRecordsInPopup?: boolean;
onClick?: (args: any) => void; onClick?: (args: any) => void;
/** 用于更改 Current record 的文案 */
currentText?: string;
/** 用于更改 Other records 的文案 */
otherText?: string;
} }
export const DataBlockInitializer = (props: DataBlockInitializerProps) => { export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
@ -321,6 +325,8 @@ export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
hideOtherRecordsInPopup, hideOtherRecordsInPopup,
onClick: propsOnClick, onClick: propsOnClick,
filterOtherRecordsCollection, filterOtherRecordsCollection,
currentText,
otherText,
} = props; } = props;
const { insert, setVisible } = useSchemaInitializer(); const { insert, setVisible } = useSchemaInitializer();
const compile = useCompile(); const compile = useCompile();
@ -358,6 +364,8 @@ export const DataBlockInitializer = (props: DataBlockInitializerProps) => {
dataBlockInitializerProps: props, dataBlockInitializerProps: props,
hideOtherRecordsInPopup, hideOtherRecordsInPopup,
onClick, onClick,
currentText,
otherText,
}); });
const getMenuItems = useGetSchemaInitializerMenuItems(onClick); const getMenuItems = useGetSchemaInitializerMenuItems(onClick);
const childItems = useMemo(() => { const childItems = useMemo(() => {

View File

@ -8,8 +8,7 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializerItem } from './ActionInitializerItem';
import { ActionInitializer } from './ActionInitializer';
export const DeleteEventActionInitializer = (props) => { export const DeleteEventActionInitializer = (props) => {
const schema = { const schema = {
@ -26,5 +25,5 @@ export const DeleteEventActionInitializer = (props) => {
}, },
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -8,7 +8,7 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializer } from './ActionInitializer'; import { ActionInitializerItem } from './ActionInitializerItem';
export const SelectActionInitializer = (props) => { export const SelectActionInitializer = (props) => {
const schema = { const schema = {
@ -65,5 +65,5 @@ export const SelectActionInitializer = (props) => {
}, },
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -8,8 +8,7 @@
*/ */
import React from 'react'; import React from 'react';
import { ActionInitializerItem } from './ActionInitializerItem';
import { ActionInitializer } from './ActionInitializer';
export const SubmitActionInitializer = (props) => { export const SubmitActionInitializer = (props) => {
const schema = { const schema = {
@ -24,5 +23,5 @@ export const SubmitActionInitializer = (props) => {
htmlType: 'submit', htmlType: 'submit',
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -13,6 +13,7 @@ export * from '../../schema-component/antd/association-filter/AssociationFilter'
export * from '../../schema-component/antd/association-filter/AssociationFilterDesignerDelete'; export * from '../../schema-component/antd/association-filter/AssociationFilterDesignerDelete';
export * from '../../schema-component/antd/association-filter/AssociationFilterDesignerDisplayField'; export * from '../../schema-component/antd/association-filter/AssociationFilterDesignerDisplayField';
export * from './ActionInitializer'; export * from './ActionInitializer';
export * from './ActionInitializerItem';
export * from './BlockInitializer'; export * from './BlockInitializer';
export * from './CreateFilterActionInitializer'; export * from './CreateFilterActionInitializer';
export * from './CreateResetActionInitializer'; export * from './CreateResetActionInitializer';

View File

@ -857,6 +857,8 @@ export const useCollectionDataSourceItems = ({
hideOtherRecordsInPopup, hideOtherRecordsInPopup,
onClick, onClick,
filterOtherRecordsCollection, filterOtherRecordsCollection,
currentText,
otherText,
}: { }: {
componentName; componentName;
filter?: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean; filter?: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean;
@ -873,6 +875,8 @@ export const useCollectionDataSourceItems = ({
* Other records * Other records
*/ */
filterOtherRecordsCollection?: (collection: Collection) => boolean; filterOtherRecordsCollection?: (collection: Collection) => boolean;
currentText?: string;
otherText?: string;
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const dm = useDataSourceManager(); const dm = useDataSourceManager();
@ -932,7 +936,7 @@ export const useCollectionDataSourceItems = ({
componentProps: { componentProps: {
...dataBlockInitializerProps, ...dataBlockInitializerProps,
icon: null, icon: null,
title: t('Current record'), title: currentText || t('Current record'),
name: 'currentRecord', name: 'currentRecord',
hideSearch: false, hideSearch: false,
hideChildrenIfSingleCollection: true, hideChildrenIfSingleCollection: true,
@ -970,7 +974,7 @@ export const useCollectionDataSourceItems = ({
onClick() {}, onClick() {},
componentProps: { componentProps: {
icon: null, icon: null,
title: t('Other records'), title: otherText || t('Other records'),
name: 'otherRecords', name: 'otherRecords',
showAssociationFields: false, showAssociationFields: false,
onlyCurrentDataSource: false, onlyCurrentDataSource: false,
@ -1031,6 +1035,7 @@ export const useCollectionDataSourceItems = ({
collection.name, collection.name,
componentName, componentName,
dataBlockInitializerProps, dataBlockInitializerProps,
filterOtherRecordsCollection,
hideOtherRecordsInPopup, hideOtherRecordsInPopup,
noAssociationMenu, noAssociationMenu,
onClick, onClick,

View File

@ -47,12 +47,7 @@ export const CreateFormBulkEditBlockInitializers: SchemaInitializer = new Schema
], ],
}); });
/** const commonOptions = {
* @deprecated
* use `bulkEditBlockInitializers` instead
*/
export const BulkEditBlockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BulkEditBlockInitializers',
wrap: gridRowColWrap, wrap: gridRowColWrap,
title: '{{t("Add block")}}', title: '{{t("Add block")}}',
icon: 'PlusOutlined', icon: 'PlusOutlined',
@ -82,40 +77,21 @@ export const BulkEditBlockInitializers_deprecated = new CompatibleSchemaInitiali
], ],
}, },
], ],
};
/**
* @deprecated
* use `bulkEditBlockInitializers` instead
*/
export const BulkEditBlockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BulkEditBlockInitializers',
...commonOptions,
}); });
export const bulkEditBlockInitializers = new CompatibleSchemaInitializer( export const bulkEditBlockInitializers = new CompatibleSchemaInitializer(
{ {
name: 'popup:bulkEdit:addBlock', name: 'popup:bulkEdit:addBlock',
wrap: gridRowColWrap, ...commonOptions,
title: '{{t("Add block")}}',
icon: 'PlusOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Data blocks")}}',
name: 'dataBlocks',
children: [
{
name: 'form',
title: '{{t("Form")}}',
Component: CreateFormBulkEditBlockInitializer,
},
],
},
{
type: 'itemGroup',
title: '{{t("Other blocks")}}',
name: 'otherBlocks',
children: [
{
name: 'markdown',
title: '{{t("Markdown")}}',
Component: 'MarkdownBlockInitializer',
},
],
},
],
}, },
BulkEditBlockInitializers_deprecated, BulkEditBlockInitializers_deprecated,
); );

View File

@ -10,12 +10,7 @@
import { CompatibleSchemaInitializer } from '@nocobase/client'; import { CompatibleSchemaInitializer } from '@nocobase/client';
import { BulkEditSubmitActionInitializer } from './BulkEditSubmitActionInitializer'; import { BulkEditSubmitActionInitializer } from './BulkEditSubmitActionInitializer';
/** const commonOptions = {
* @deprecated
* use `bulkEditFormActionInitializers` instead
*/
export const BulkEditFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BulkEditFormActionInitializers',
title: '{{t("Configure actions")}}', title: '{{t("Configure actions")}}',
icon: 'SettingOutlined', icon: 'SettingOutlined',
items: [ items: [
@ -35,30 +30,21 @@ export const BulkEditFormActionInitializers_deprecated = new CompatibleSchemaIni
], ],
}, },
], ],
};
/**
* @deprecated
* use `bulkEditFormActionInitializers` instead
*/
export const BulkEditFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BulkEditFormActionInitializers',
...commonOptions,
}); });
export const bulkEditFormActionInitializers = new CompatibleSchemaInitializer( export const bulkEditFormActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'bulkEditForm:configureActions', name: 'bulkEditForm:configureActions',
title: '{{t("Configure actions")}}', ...commonOptions,
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
title: '{{t("Enable actions")}}',
name: 'enableActions',
children: [
{
name: 'submit',
title: '{{t("Submit")}}',
Component: BulkEditSubmitActionInitializer,
schema: {
'x-action-settings': {},
},
},
],
},
],
}, },
BulkEditFormActionInitializers_deprecated, BulkEditFormActionInitializers_deprecated,
); );

View File

@ -10,12 +10,7 @@
import { CompatibleSchemaInitializer, gridRowColWrap } from '@nocobase/client'; import { CompatibleSchemaInitializer, gridRowColWrap } from '@nocobase/client';
import { useCustomBulkEditFormItemInitializerFields } from './utils'; import { useCustomBulkEditFormItemInitializerFields } from './utils';
/** const commonOptions = {
* @deprecated
* use `bulkEditFormItemInitializers` instead
*/
export const BulkEditFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BulkEditFormItemInitializers',
wrap: gridRowColWrap, wrap: gridRowColWrap,
icon: 'SettingOutlined', icon: 'SettingOutlined',
title: '{{t("Configure fields")}}', title: '{{t("Configure fields")}}',
@ -48,43 +43,21 @@ export const BulkEditFormItemInitializers_deprecated = new CompatibleSchemaIniti
}, },
}, },
], ],
};
/**
* @deprecated
* use `bulkEditFormItemInitializers` instead
*/
export const BulkEditFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BulkEditFormItemInitializers',
...commonOptions,
}); });
export const bulkEditFormItemInitializers = new CompatibleSchemaInitializer( export const bulkEditFormItemInitializers = new CompatibleSchemaInitializer(
{ {
name: 'bulkEditForm:configureFields', name: 'bulkEditForm:configureFields',
wrap: gridRowColWrap, ...commonOptions,
icon: 'SettingOutlined',
title: '{{t("Configure fields")}}',
items: [
{
name: 'displayFields',
type: 'itemGroup',
title: '{{t("Display fields")}}',
useChildren: useCustomBulkEditFormItemInitializerFields,
},
{
name: 'divider',
type: 'divider',
},
{
name: 'addText',
title: '{{t("Add text")}}',
Component: 'BlockItemInitializer',
schema: {
type: 'void',
'x-editable': false,
'x-decorator': 'FormItem',
// 'x-designer': 'Markdown.Void.Designer',
'x-toolbar': 'FormItemSchemaToolbar',
'x-settings': 'blockSettings:markdown',
'x-component': 'Markdown.Void',
'x-component-props': {
content: '{{t("This is a demo text, **supports Markdown syntax**.")}}',
},
},
},
],
}, },
BulkEditFormItemInitializers_deprecated, BulkEditFormItemInitializers_deprecated,
); );

View File

@ -7,8 +7,8 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { ActionInitializerItem } from '@nocobase/client';
import React from 'react'; import React from 'react';
import { ActionInitializer } from '@nocobase/client';
export const BulkEditSubmitActionInitializer = (props) => { export const BulkEditSubmitActionInitializer = (props) => {
const schema = { const schema = {
@ -24,5 +24,5 @@ export const BulkEditSubmitActionInitializer = (props) => {
htmlType: 'submit', htmlType: 'submit',
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -14,7 +14,6 @@ test.describe('TableActionInitializers & GanttActionInitializers & MapActionInit
test('bulk edit in TableActionInitializers', async ({ page, mockPage }) => { test('bulk edit in TableActionInitializers', async ({ page, mockPage }) => {
await mockPage(oneEmptyTableBlockWithActions).goto(); await mockPage(oneEmptyTableBlockWithActions).goto();
await page.getByLabel('schema-initializer-ActionBar-table:configureActions-general').hover(); await page.getByLabel('schema-initializer-ActionBar-table:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Customize right' }).click();
await page.getByRole('menuitem', { name: 'Bulk edit' }).click(); await page.getByRole('menuitem', { name: 'Bulk edit' }).click();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByLabel('Bulk edit')).toBeVisible(); await expect(page.getByLabel('Bulk edit')).toBeVisible();
@ -24,7 +23,6 @@ test.describe('TableActionInitializers & GanttActionInitializers & MapActionInit
await mockRecords('general', 3); await mockRecords('general', 3);
await nocoPage.goto(); await nocoPage.goto();
await page.getByLabel('schema-initializer-ActionBar-gantt:configureActions-general').hover(); await page.getByLabel('schema-initializer-ActionBar-gantt:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Customize right' }).click();
await page.getByRole('menuitem', { name: 'Bulk edit' }).click(); await page.getByRole('menuitem', { name: 'Bulk edit' }).click();
await expect(page.getByLabel('Bulk edit')).toBeVisible(); await expect(page.getByLabel('Bulk edit')).toBeVisible();
}); });

View File

@ -14,7 +14,6 @@ test.describe('TableActionInitializers & GanttActionInitializers & MapActionInit
test('TableActionInitializers should add bulk update', async ({ page, mockPage }) => { test('TableActionInitializers should add bulk update', async ({ page, mockPage }) => {
await mockPage(oneEmptyTableBlockWithCustomizeActions).goto(); await mockPage(oneEmptyTableBlockWithCustomizeActions).goto();
await page.getByLabel('schema-initializer-ActionBar-table:configureActions-general').hover(); await page.getByLabel('schema-initializer-ActionBar-table:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Customize right' }).click();
await page.getByRole('menuitem', { name: 'Bulk update' }).click(); await page.getByRole('menuitem', { name: 'Bulk update' }).click();
await expect(page.getByLabel('action-Action-Bulk update-customize:bulkUpdate-general-table')).toBeVisible(); await expect(page.getByLabel('action-Action-Bulk update-customize:bulkUpdate-general-table')).toBeVisible();
}); });
@ -23,7 +22,6 @@ test.describe('TableActionInitializers & GanttActionInitializers & MapActionInit
await mockRecords('general', 3); await mockRecords('general', 3);
await nocoPage.goto(); await nocoPage.goto();
await page.getByLabel('schema-initializer-ActionBar-gantt:configureActions-general').hover(); await page.getByLabel('schema-initializer-ActionBar-gantt:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Customize right' }).click();
await page.getByRole('menuitem', { name: 'Bulk update' }).click(); await page.getByRole('menuitem', { name: 'Bulk update' }).click();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Bulk update' })).toBeVisible(); await expect(page.getByRole('button', { name: 'Bulk update' })).toBeVisible();

View File

@ -18,7 +18,6 @@ test.describe('custom request action', () => {
// 新建一个 custom request action // 新建一个 custom request action
await page.getByRole('button', { name: 'Actions', exact: true }).hover(); await page.getByRole('button', { name: 'Actions', exact: true }).hover();
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-').hover(); await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-').hover();
await page.getByRole('menuitem', { name: 'Customize right' }).hover();
await page.getByRole('menuitem', { name: 'Custom request' }).click(); await page.getByRole('menuitem', { name: 'Custom request' }).click();
// 打开编辑按钮弹窗 // 打开编辑按钮弹窗
@ -37,7 +36,6 @@ test.describe('custom request action', () => {
// 1. 新建一个 custom request action // 1. 新建一个 custom request action
await page.getByLabel('schema-initializer-ActionBar-').hover(); await page.getByLabel('schema-initializer-ActionBar-').hover();
await page.getByRole('menuitem', { name: 'Customize' }).hover();
await page.getByRole('menuitem', { name: 'Custom request' }).click(); await page.getByRole('menuitem', { name: 'Custom request' }).click();
// 2. 打开编辑按钮弹窗 // 2. 打开编辑按钮弹窗

View File

@ -7,7 +7,7 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { ActionInitializer } from '@nocobase/client'; import { ActionInitializerItem } from '@nocobase/client';
import React from 'react'; import React from 'react';
export const DuplicateActionInitializer = (props) => { export const DuplicateActionInitializer = (props) => {
@ -58,5 +58,5 @@ export const DuplicateActionInitializer = (props) => {
}, },
}, },
}; };
return <ActionInitializer {...props} schema={schema} />; return <ActionInitializerItem {...props} schema={schema} />;
}; };

View File

@ -45,7 +45,8 @@ test.describe('direct duplicate & copy into the form and continue to fill in', (
await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').click(); await page.getByLabel('action-Action.Link-Duplicate-duplicate-general-table-0').click();
await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-general').hover(); await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-general').hover();
//配置表单区块 //配置表单区块
await page.getByRole('menuitem', { name: 'form Form' }).click(); await page.getByRole('menuitem', { name: 'form Form' }).hover();
await page.getByRole('menuitem', { name: 'Current collection' }).click();
await page.mouse.move(300, 0); await page.mouse.move(300, 0);
await page.getByLabel('schema-initializer-Grid-form:configureFields-general').hover(); await page.getByLabel('schema-initializer-Grid-form:configureFields-general').hover();
await page.getByRole('menuitem', { name: 'singleLineText' }).click(); await page.getByRole('menuitem', { name: 'singleLineText' }).click();

View File

@ -7,12 +7,11 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { Schema, useFieldSchema } from '@formily/react'; import { Schema } from '@formily/react';
import { merge } from '@formily/shared'; import { merge } from '@formily/shared';
import { import {
SchemaInitializerSwitch, SchemaInitializerItem,
useCollection_deprecated, useCollection_deprecated,
useDesignable,
useSchemaInitializer, useSchemaInitializer,
useSchemaInitializerItem, useSchemaInitializerItem,
} from '@nocobase/client'; } from '@nocobase/client';
@ -31,21 +30,6 @@ const findSchema = (schema: Schema, key: string, action: string) => {
return buf; return buf;
}); });
}; };
const removeSchema = (schema, cb) => {
return cb(schema);
};
export const useCurrentSchema = (action: string, key: string, find = findSchema, rm = removeSchema) => {
const fieldSchema = useFieldSchema();
const { remove } = useDesignable();
const schema = find(fieldSchema, key, action);
return {
schema,
exists: !!schema,
remove() {
schema && rm(schema, remove);
},
};
};
const initExportSettings = (fields) => { const initExportSettings = (fields) => {
const exportSettings = fields?.filter((f) => !f.children).map((f) => ({ dataIndex: [f.name] })); const exportSettings = fields?.filter((f) => !f.children).map((f) => ({ dataIndex: [f.name] }));
@ -55,7 +39,6 @@ const initExportSettings = (fields) => {
export const ExportActionInitializer = () => { export const ExportActionInitializer = () => {
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
const { insert } = useSchemaInitializer(); const { insert } = useSchemaInitializer();
const { exists, remove } = useCurrentSchema('export', 'x-action', itemConfig.find, itemConfig.remove);
const { name } = useCollection_deprecated(); const { name } = useCollection_deprecated();
const fields = useFields(name); const fields = useFields(name);
@ -75,15 +58,11 @@ export const ExportActionInitializer = () => {
icon: 'clouddownloadoutlined', icon: 'clouddownloadoutlined',
}, },
}; };
return ( return (
<SchemaInitializerSwitch <SchemaInitializerItem
{...itemConfig}
checked={exists}
title={itemConfig.title} title={itemConfig.title}
onClick={() => { onClick={() => {
if (exists) {
return remove();
}
schema['x-action-settings']['exportSettings'] = initExportSettings(fields); schema['x-action-settings']['exportSettings'] = initExportSettings(fields);
const s = merge(schema || {}, itemConfig.schema || {}); const s = merge(schema || {}, itemConfig.schema || {});
itemConfig?.schemaInitialize?.(s); itemConfig?.schemaInitialize?.(s);

View File

@ -8,21 +8,20 @@
*/ */
import type { ISchema } from '@formily/react'; import type { ISchema } from '@formily/react';
import { Schema, useFieldSchema } from '@formily/react'; import { Schema } from '@formily/react';
import { merge } from '@formily/shared'; import { merge } from '@formily/shared';
import { import {
SchemaInitializerSwitch, SchemaInitializerItem,
css, css,
useCollection_deprecated, useCollection_deprecated,
useDesignable,
useSchemaInitializer, useSchemaInitializer,
useSchemaInitializerItem, useSchemaInitializerItem,
} from '@nocobase/client'; } from '@nocobase/client';
import { Alert } from 'antd';
import React from 'react'; import React from 'react';
import { NAMESPACE } from './constants'; import { NAMESPACE } from './constants';
import { useFields } from './useFields';
import { Alert } from 'antd';
import { useImportTranslation } from './locale'; import { useImportTranslation } from './locale';
import { useFields } from './useFields';
const findSchema = (schema: Schema, key: string, action: string) => { const findSchema = (schema: Schema, key: string, action: string) => {
return schema.reduceProperties((buf, s) => { return schema.reduceProperties((buf, s) => {
@ -36,21 +35,6 @@ const findSchema = (schema: Schema, key: string, action: string) => {
return buf; return buf;
}); });
}; };
const removeSchema = (schema, cb) => {
return cb(schema);
};
export const useCurrentSchema = (action: string, key: string, find = findSchema, rm = removeSchema) => {
const fieldSchema = useFieldSchema();
const { remove } = useDesignable();
const schema = find(fieldSchema, key, action);
return {
schema,
exists: !!schema,
remove() {
schema && rm(schema, remove);
},
};
};
const initImportSettings = (fields) => { const initImportSettings = (fields) => {
const importColumns = fields?.filter((f) => !f.children).map((f) => ({ dataIndex: [f.name] })); const importColumns = fields?.filter((f) => !f.children).map((f) => ({ dataIndex: [f.name] }));
@ -65,7 +49,6 @@ export const ImportWarning = () => {
export const ImportActionInitializer = () => { export const ImportActionInitializer = () => {
const itemConfig = useSchemaInitializerItem(); const itemConfig = useSchemaInitializerItem();
const { insert } = useSchemaInitializer(); const { insert } = useSchemaInitializer();
const { exists, remove } = useCurrentSchema('importXlsx', 'x-action', itemConfig.find, itemConfig.remove);
const { name } = useCollection_deprecated(); const { name } = useCollection_deprecated();
const fields = useFields(name); const fields = useFields(name);
const schema: ISchema = { const schema: ISchema = {
@ -196,15 +179,11 @@ export const ImportActionInitializer = () => {
}, },
}, },
}; };
return ( return (
<SchemaInitializerSwitch <SchemaInitializerItem
{...itemConfig}
checked={exists}
title={itemConfig.title} title={itemConfig.title}
onClick={() => { onClick={() => {
if (exists) {
return remove();
}
schema['x-action-settings']['importSettings'] = initImportSettings(fields); schema['x-action-settings']['importSettings'] = initImportSettings(fields);
const s = merge(schema || {}, itemConfig.schema || {}); const s = merge(schema || {}, itemConfig.schema || {});
itemConfig?.schemaInitialize?.(s); itemConfig?.schemaInitialize?.(s);

View File

@ -7,9 +7,8 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import React from 'react';
import { ActionInitializer } from '@nocobase/client'; import { ActionInitializer } from '@nocobase/client';
import React from 'react';
export const PrintActionInitializer = (props) => { export const PrintActionInitializer = (props) => {
const schema = { const schema = {

View File

@ -7,7 +7,7 @@
* For more information, please refer to: https://www.nocobase.com/agreement. * For more information, please refer to: https://www.nocobase.com/agreement.
*/ */
import { ActionInitializer } from '@nocobase/client'; import { ActionInitializerItem } from '@nocobase/client';
import React from 'react'; import React from 'react';
export const AuditLogsViewActionInitializer = () => { export const AuditLogsViewActionInitializer = () => {
@ -346,5 +346,5 @@ export const AuditLogsViewActionInitializer = () => {
}, },
}, },
}; };
return <ActionInitializer schema={schema} />; return <ActionInitializerItem schema={schema} />;
}; };

View File

@ -19,12 +19,7 @@ import {
import React from 'react'; import React from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
/** const commonOptions = {
* @deprecated
* use `auditLogsTableActionColumnInitializers` instead
*/
export const auditLogsTableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'AuditLogsTableActionColumnInitializers',
insertPosition: 'beforeEnd', insertPosition: 'beforeEnd',
Component: (props: any) => <MenuOutlined {...props} style={{ cursor: 'pointer' }} />, Component: (props: any) => <MenuOutlined {...props} style={{ cursor: 'pointer' }} />,
useInsert() { useInsert() {
@ -83,69 +78,21 @@ export const auditLogsTableActionColumnInitializers_deprecated = new CompatibleS
Component: Resizable, Component: Resizable,
}, },
], ],
};
/**
* @deprecated
* use `auditLogsTableActionColumnInitializers` instead
*/
export const auditLogsTableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'AuditLogsTableActionColumnInitializers',
...commonOptions,
}); });
export const auditLogsTableActionColumnInitializers = new CompatibleSchemaInitializer( export const auditLogsTableActionColumnInitializers = new CompatibleSchemaInitializer(
{ {
name: 'auditLogsTable:configureItemActions', name: 'auditLogsTable:configureItemActions',
insertPosition: 'beforeEnd', ...commonOptions,
Component: (props: any) => <MenuOutlined {...props} style={{ cursor: 'pointer' }} />,
useInsert() {
const fieldSchema = useFieldSchema();
const api = useAPIClient();
const { refresh } = useDesignable();
const { t } = useTranslation();
return (schema) => {
const spaceSchema = fieldSchema.reduceProperties((buf, schema) => {
if (schema['x-component'] === 'Space') {
return schema;
}
return buf;
}, null);
if (!spaceSchema) {
return;
}
const dn = createDesignable({
t,
api,
refresh,
current: spaceSchema,
});
dn.loadAPIClientEvents();
dn.insertBeforeEnd(schema);
};
},
items: [
{
name: 'enableActions',
type: 'itemGroup',
title: '{{t("Enable actions")}}',
children: [
{
name: 'view',
type: 'item',
title: '{{t("View")}}',
Component: 'AuditLogsViewActionInitializer',
schema: {
'x-component': 'Action.Link',
'x-action': 'view',
'x-decorator': 'ACLActionProvider',
},
},
],
},
{
name: 'divider',
type: 'divider',
},
{
name: 'columnWidth',
type: 'item',
title: '{{t("Column width")}}',
Component: Resizable,
},
],
}, },
auditLogsTableActionColumnInitializers_deprecated, auditLogsTableActionColumnInitializers_deprecated,
); );

View File

@ -9,13 +9,7 @@
import { CompatibleSchemaInitializer } from '@nocobase/client'; import { CompatibleSchemaInitializer } from '@nocobase/client';
/** const commonOptions = {
* @deprecated
* use `auditLogsTableActionInitializers` instead
*
*/
export const auditLogsTableActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'AuditLogsTableActionInitializers',
title: "{{t('Configure actions')}}", title: "{{t('Configure actions')}}",
icon: 'SettingOutlined', icon: 'SettingOutlined',
style: { style: {
@ -46,41 +40,22 @@ export const auditLogsTableActionInitializers_deprecated = new CompatibleSchemaI
], ],
}, },
], ],
};
/**
* @deprecated
* use `auditLogsTableActionInitializers` instead
*
*/
export const auditLogsTableActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'AuditLogsTableActionInitializers',
...commonOptions,
}); });
export const auditLogsTableActionInitializers = new CompatibleSchemaInitializer( export const auditLogsTableActionInitializers = new CompatibleSchemaInitializer(
{ {
name: 'auditLogsTable:configureActions', name: 'auditLogsTable:configureActions',
title: "{{t('Configure actions')}}", ...commonOptions,
icon: 'SettingOutlined',
style: {
marginLeft: 8,
},
items: [
{
type: 'itemGroup',
title: "{{t('Enable actions')}}",
name: 'enableActions',
children: [
{
name: 'filter',
title: "{{t('Filter')}}",
Component: 'FilterActionInitializer',
schema: {
'x-align': 'left',
},
},
{
name: 'refresh',
title: "{{t('Refresh')}}",
Component: 'RefreshActionInitializer',
schema: {
'x-align': 'right',
},
},
],
},
],
}, },
auditLogsTableActionInitializers_deprecated, auditLogsTableActionInitializers_deprecated,
); );

Some files were not shown because too many files have changed in this diff Show More