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', () => {
initializer.add('parent', { title: 'parent title' });
initializer.add('parent.item1', { title: 'title' });

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@
*/
import React from 'react';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
export const CreateChildInitializer = (props) => {
const schema = {
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 { useSchemaInitializerItem } from '../../../application';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
export const CreateActionInitializer = () => {
const schema = {
@ -67,5 +67,5 @@ export const CreateActionInitializer = () => {
},
};
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.
*/
import { useTranslation } from 'react-i18next';
import { CompatibleSchemaInitializer } from '../../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCollection } from '../../../data-source/collection/CollectionProvider';
import { gridRowColWrap } from '../../../schema-initializer/utils';
/**
* @deprecated
* use `createFormBlockInitializers` instead
*/
export const createFormBlockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CreateFormBlockInitializers',
const commonOptions = {
wrap: gridRowColWrap,
title: '{{t("Add block")}}',
icon: 'PlusOutlined',
@ -24,13 +21,36 @@ export const createFormBlockInitializers_deprecated = new CompatibleSchemaInitia
type: 'itemGroup',
title: '{{t("Data blocks")}}',
name: 'dataBlocks',
children: [
{
name: 'form',
title: '{{t("Form")}}',
Component: 'CreateFormBlockInitializer',
},
],
useChildren() {
const currentCollection = useCollection();
const { t } = useTranslation();
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',
@ -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(
{
name: 'popup:addNew:addBlock',
wrap: gridRowColWrap,
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',
},
],
},
],
...commonOptions,
},
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 { gridRowColWrap } from '../../../schema-initializer/utils';
/**
* @deprecated
* use `customizeCreateFormBlockInitializers` instead
*/
export const customizeCreateFormBlockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CusomeizeCreateFormBlockInitializers',
const commonOptions = {
wrap: gridRowColWrap,
title: '{{t("Add block")}}',
icon: 'PlusOutlined',
@ -29,6 +24,7 @@ export const customizeCreateFormBlockInitializers_deprecated = new CompatibleSch
name: 'form',
title: '{{t("Form")}}',
Component: 'FormBlockInitializer',
/** 表示是通过 Other collections 选项创建的区块(由于历史遗留问题,这里的命名暂不做更改) */
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(
{
name: 'popup:addRecord:addBlock',
wrap: gridRowColWrap,
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',
},
],
},
],
...commonOptions,
},
customizeCreateFormBlockInitializers_deprecated,
);

View File

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

View File

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

View File

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

View File

@ -8,7 +8,6 @@
*/
import React from 'react';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
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,
AssignedFieldValues,
ButtonEditor,
RefreshDataBlockRequest,
RemoveButton,
SecondConFirm,
SkipValidation,
WorkflowConfig,
RefreshDataBlockRequest,
} from '../../../schema-component/antd/action/Action.Designer';
/**
* @deprecated
* Schema
*/
export const customizeSaveRecordActionSettings = new SchemaSettings({
name: 'actionSettings:saveRecord',
items: [

View File

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

View File

@ -8,8 +8,7 @@
*/
import React from 'react';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
export const UpdateSubmitActionInitializer = (props) => {
const schema = {
@ -28,5 +27,5 @@ export const UpdateSubmitActionInitializer = (props) => {
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.
*/
import { useFieldSchema, useField, connect, mapProps, ISchema } from '@formily/react';
import { ISchema, connect, mapProps, useField, useFieldSchema } from '@formily/react';
import { isValid } from '@formily/shared';
import React, { useEffect, useState } from 'react';
import { Tree as AntdTree } from 'antd';
import React, { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useSchemaToolbar } from '../../../application';
import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings';
import { useCollection_deprecated } from '../../../collection-manager';
import { useDesignable } from '../../../schema-component';
import {
AfterSuccess,
AssignedFieldValues,
ButtonEditor,
RefreshDataBlockRequest,
RemoveButton,
SecondConFirm,
SkipValidation,
WorkflowConfig,
} 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 { useCollection_deprecated } from '../../../collection-manager';
import { SchemaSettingsModalItem } from '../../../schema-settings/SchemaSettings';
const Tree = connect(
@ -132,6 +136,7 @@ export function SaveMode() {
/>
);
}
export const createSubmitActionSettings = new SchemaSettings({
name: 'actionSettings:createSubmit',
items: [
@ -159,6 +164,31 @@ export const createSubmitActionSettings = new SchemaSettings({
name: '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',
sort: 100,

View File

@ -12,9 +12,13 @@ import { isValid } from '@formily/shared';
import { isInitializersSame, useSchemaToolbar } from '../../../application';
import { SchemaSettings } from '../../../application/schema-settings/SchemaSettings';
import {
AfterSuccess,
AssignedFieldValues,
ButtonEditor,
RefreshDataBlockRequest,
RemoveButton,
SecondConFirm,
SkipValidation,
WorkflowConfig,
} from '../../../schema-component/antd/action/Action.Designer';
import { SaveMode } from './createSubmitActionSettings';
@ -42,6 +46,31 @@ export const updateSubmitActionSettings = new SchemaSettings({
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',
sort: 100,

View File

@ -8,8 +8,7 @@
*/
import React from 'react';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
export const UpdateActionInitializer = (props) => {
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 { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
export const ViewActionInitializer = (props) => {
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';
/**
* @deprecated
* use `detailsActionInitializers` instead
*
*/
export const detailsActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'DetailsActionInitializers',
const commonOptions = {
title: '{{t("Configure actions")}}',
icon: 'SettingOutlined',
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(
{
name: 'detailsWithPaging:configureActions',
title: '{{t("Configure actions")}}',
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',
},
},
],
},
],
...commonOptions,
},
detailsActionInitializers_deprecated,
);

View File

@ -7,9 +7,16 @@
* 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';
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('page', async ({ page, mockPage }) => {
await mockPage().goto();
@ -109,20 +116,13 @@ test.describe('configure actions', () => {
await page.getByRole('menuitem', { name: 'Edit' }).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 expect(page.getByRole('button', { name: 'Edit' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Delete' })).toBeVisible();
// delete buttons
await page.getByLabel('schema-initializer-ActionBar-detailsWithPaging:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Edit' }).click();
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 deleteButton(page, 'Edit');
await deleteButton(page, 'Delete');
await page.mouse.move(300, 0);
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';
};
/**
* @deprecated
* use `readPrettyFormActionInitializers` instead
*
*/
export const readPrettyFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ReadPrettyFormActionInitializers',
const commonOptions = {
title: '{{t("Configure actions")}}',
icon: 'SettingOutlined',
style: {
@ -29,154 +23,72 @@ export const readPrettyFormActionInitializers_deprecated = new CompatibleSchemaI
},
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("Edit")}}',
name: 'edit',
Component: 'UpdateActionInitializer',
schema: {
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
'x-component-props': {
type: 'primary',
},
{
title: '{{t("Delete")}}',
name: 'delete',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
},
useVisible: useVisibleCollection,
},
],
},
useVisible: useVisibleCollection,
},
{
name: 'divider',
type: 'divider',
title: '{{t("Delete")}}',
name: 'delete',
Component: 'DestroyActionInitializer',
schema: {
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
},
useVisible: useVisibleCollection,
},
{
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,
},
],
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,
},
],
};
/**
* @deprecated
* use `readPrettyFormActionInitializers` instead
*
*/
export const readPrettyFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ReadPrettyFormActionInitializers',
...commonOptions,
});
export const readPrettyFormActionInitializers = new CompatibleSchemaInitializer(
{
name: 'details:configureActions',
title: '{{t("Configure actions")}}',
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,
},
],
},
],
...commonOptions,
},
readPrettyFormActionInitializers_deprecated,
);

View File

@ -54,12 +54,7 @@ const AssociatedFields = () => {
return <SchemaInitializerChildren>{schema}</SchemaInitializerChildren>;
};
/**
* @deprecated
* use `readPrettyFormItemInitializers` instead
*/
export const readPrettyFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ReadPrettyFormItemInitializers',
const commonOptions = {
wrap: gridRowColWrap,
icon: 'SettingOutlined',
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(
{
name: 'details:configureFields',
wrap: gridRowColWrap,
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**.")}}',
},
},
},
],
...commonOptions,
},
readPrettyFormItemInitializers_deprecated,
);

View File

@ -143,13 +143,11 @@ test.describe('configure fields', () => {});
async function createAction(page: Page, name: string) {
await page.getByLabel('schema-initializer-ActionBar-details:configureActions-general').hover();
await page.getByRole('menuitem', { name: name }).click();
await expect(page.getByRole('menuitem', { name: name }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0);
}
async function createCustomAction(page: Page, name: string) {
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.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 React, { useCallback } from 'react';
import { useSchemaInitializer, useSchemaInitializerItem } from '../../../../application';
import { useAssociationName } from '../../../../data-source/collection/AssociationProvider';
import { Collection, CollectionFieldOptions } from '../../../../data-source/collection/Collection';
import { DataBlockInitializer } from '../../../../schema-initializer/items/DataBlockInitializer';
import { createCreateFormBlockUISchema } from './createCreateFormBlockUISchema';
@ -24,6 +25,8 @@ export const FormBlockInitializer = ({
showAssociationFields,
hideChildrenIfSingleCollection,
hideOtherRecordsInPopup,
currentText,
otherText,
}: {
filterCollections: (options: { collection?: Collection; associationField?: CollectionFieldOptions }) => boolean;
onlyCurrentDataSource: boolean;
@ -47,6 +50,10 @@ export const FormBlockInitializer = ({
* Other records
*/
hideOtherRecordsInPopup?: boolean;
/** 用于更改 Current record 的文案 */
currentText?: string;
/** 用于更改 Other records 的文案 */
otherText?: string;
}) => {
const itemConfig = useSchemaInitializerItem();
const { createFormBlock, templateWrap } = useCreateFormBlock();
@ -84,42 +91,84 @@ export const FormBlockInitializer = ({
showAssociationFields={showAssociationFields}
hideChildrenIfSingleCollection={hideChildrenIfSingleCollection}
hideOtherRecordsInPopup={hideOtherRecordsInPopup}
currentText={currentText}
otherText={otherText}
/>
);
};
export const useCreateFormBlock = () => {
const { insert } = useSchemaInitializer();
const itemConfig = useSchemaInitializerItem();
const { isCusomeizeCreate: isCustomizeCreate } = itemConfig;
const association = useAssociationName();
const { isCusomeizeCreate: isCustomizeCreate } = useSchemaInitializerItem();
const createFormBlock = useCallback(
({ item }) => {
insert(
createCreateFormBlockUISchema({
collectionName: item.collectionName || item.name,
dataSource: item.dataSource,
isCusomeizeCreate: isCustomizeCreate,
}),
);
({ item, fromOthersInPopup }) => {
if (fromOthersInPopup) {
insert(
createCreateFormBlockUISchema({
collectionName: item.collectionName || item.name,
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(
(templateSchema, { item }) => {
const schema = createCreateFormBlockUISchema({
isCusomeizeCreate: isCustomizeCreate,
dataSource: item.dataSource,
templateSchema: templateSchema,
collectionName: item.name,
});
(templateSchema, { item, fromOthersInPopup }) => {
let schema;
if (fromOthersInPopup) {
schema = createCreateFormBlockUISchema({
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') {
schema['x-template-key'] = item.template.key;
}
return schema;
},
[isCustomizeCreate],
[association, isCustomizeCreate],
);
return {

View File

@ -62,7 +62,8 @@ test.describe('association form block', () => {
.getByLabel('schema-initializer-Grid-popup')
.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();
});
});

View File

@ -8,10 +8,17 @@
*/
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 { 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('page', async ({ page, mockPage }) => {
await mockPage().goto();
@ -111,16 +118,11 @@ test.describe('configure actions', () => {
// add button
await page.getByRole('menuitem', { name: 'Submit' }).click();
await expect(page.getByRole('menuitem', { name: 'Submit' }).getByRole('switch')).toBeChecked();
await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Submit' })).toBeVisible();
// delete button
await page.getByLabel('schema-initializer-ActionBar-createForm:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Submit' }).click();
await expect(page.getByRole('menuitem', { name: 'Submit' }).getByRole('switch')).not.toBeChecked();
await deleteButton(page, 'Submit');
await page.mouse.move(300, 0);
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'),
).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();
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.getByRole('menuitem', { name: 'Customize right' }).hover();
await page.getByRole('menuitem', { name: 'Save record' }).click();
await page.getByRole('menuitem', { name: 'Submit' }).click();
}
await page.getByLabel('action-Action-Save record-').hover();
await page.getByLabel('designer-schema-settings-Action-actionSettings:saveRecord-users').hover();
await page.getByLabel('action-Action-Submit-').hover();
await page.getByLabel('designer-schema-settings-Action-actionSettings:createSubmit-users').hover();
await page.getByRole('menuitem', { name: 'Assign field values' }).click();
await page.waitForTimeout(500);
if (!(await page.getByLabel('block-item-AssignedField-').getByRole('textbox').isVisible())) {
await page.getByLabel('schema-initializer-Grid-assignFieldValuesForm:configureFields-users').hover();
await page.getByRole('menuitem', { name: 'Nickname' }).click();
@ -419,8 +419,7 @@ test.describe('actions schema settings', () => {
};
const expectNewValue = async (value: string) => {
await page.getByLabel('action-Action-Save record-').click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await page.getByLabel('action-Action-Submit-').click();
await page.getByLabel('action-Action-Refresh-refresh').click();
await expect(page.getByLabel('block-item-CardItem-users-table').getByText(value)).toBeVisible();
};
@ -431,9 +430,9 @@ test.describe('actions schema settings', () => {
// 2. 将 Nickname 字段的值设置为 `123456`
await page.getByLabel('block-item-AssignedField-').getByRole('textbox').click();
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');
// 4. 再次打开 Assign field values 配置弹窗,这次为 Nickname 设置一个变量值Current role
@ -447,9 +446,9 @@ test.describe('actions schema settings', () => {
'Current form',
]);
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');
});
});

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('schema-initializer-Grid-popup:addNew:addBlock-users').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: 'Users_Form (Fields only)' }).first().click();
await page.mouse.move(300, 0);

View File

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

View File

@ -9,97 +9,39 @@
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
* use `createFormActionInitializers` instead
*/
export const createFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CreateFormActionInitializers',
title: '{{t("Configure actions")}}',
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',
},
],
},
],
...commonOptions,
});
export const createFormActionInitializers = new CompatibleSchemaInitializer(
{
name: 'createForm:configureActions',
title: '{{t("Configure actions")}}',
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',
},
],
},
],
...commonOptions,
},
createFormActionInitializers_deprecated,
);

View File

@ -19,40 +19,17 @@ export const formActionInitializers = new SchemaInitializer({
icon: 'SettingOutlined',
items: [
{
type: 'itemGroup',
name: 'enableActions',
title: '{{t("Enable actions")}}',
children: [
{
name: 'submit',
title: '{{t("Submit")}}',
Component: 'CreateSubmitActionInitializer',
schema: {
'x-action-settings': {},
},
},
],
name: 'submit',
title: '{{t("Submit")}}',
Component: 'CreateSubmitActionInitializer',
schema: {
'x-action-settings': {},
},
},
{
name: 'divider',
type: 'divider',
},
{
name: 'customize',
type: 'subMenu',
title: '{{t("Customize")}}',
children: [
{
name: 'saveRecord',
title: '{{t("Save record")}}',
Component: 'SaveRecordActionInitializer',
},
{
name: 'customRequest',
title: '{{t("Custom request")}}',
Component: 'CustomRequestInitializer',
},
],
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 { gridRowColWrap, useFormItemInitializerFields } from '../../../../schema-initializer/utils';
/**
* @deprecated
* use `formItemInitializers` instead
*
*/
export const formItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'FormItemInitializers',
const commonOptions = {
wrap: gridRowColWrap,
icon: 'SettingOutlined',
title: '{{t("Configure fields")}}',
@ -46,39 +40,22 @@ export const formItemInitializers_deprecated = new CompatibleSchemaInitializer({
Component: 'MarkdownFormItemInitializer',
},
],
};
/**
* @deprecated
* use `formItemInitializers` instead
*
*/
export const formItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'FormItemInitializers',
...commonOptions,
});
export const formItemInitializers = new CompatibleSchemaInitializer(
{
name: 'form:configureFields',
wrap: gridRowColWrap,
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',
},
],
...commonOptions,
},
formItemInitializers_deprecated,
);

View File

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

View File

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

View File

@ -9,119 +9,50 @@
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
* use `updateFormActionInitializers` instead
*/
export const updateFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'UpdateFormActionInitializers',
title: '{{t("Configure actions")}}',
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',
},
],
},
],
...commonOptions,
});
export const updateFormActionInitializers = new CompatibleSchemaInitializer(
{
name: 'editForm:configureActions',
title: '{{t("Configure actions")}}',
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',
},
],
},
],
...commonOptions,
},
updateFormActionInitializers_deprecated,
);

View File

@ -10,12 +10,7 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCollection_deprecated } from '../../../../collection-manager';
/**
* @deprecated
* use `gridCardActionInitializers` instead
*/
export const gridCardActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'GridCardActionInitializers',
const commonOptions = {
title: "{{t('Configure actions')}}",
icon: 'SettingOutlined',
style: {
@ -23,154 +18,82 @@ export const gridCardActionInitializers_deprecated = new CompatibleSchemaInitial
},
items: [
{
type: 'itemGroup',
title: "{{t('Enable actions')}}",
name: 'enableActions',
children: [
{
name: 'filter',
title: "{{t('Filter')}}",
Component: 'FilterActionInitializer',
schema: {
'x-align': 'left',
},
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,
},
{
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;
},
},
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,
},
{
name: 'refresh',
title: "{{t('Refresh')}}",
Component: 'RefreshActionInitializer',
schema: {
'x-align': 'right',
},
},
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,
},
{
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(
{
name: 'gridCard:configureActions',
title: "{{t('Configure actions')}}",
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,
},
},
},
],
},
],
...commonOptions,
},
gridCardActionInitializers_deprecated,
);

View File

@ -7,10 +7,17 @@
* 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 { 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('page', async ({ page, mockPage }) => {
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: '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 expect(page.getByRole('button', { name: 'Filter' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible();
// delete buttons
await page.getByLabel('schema-initializer-ActionBar-gridCard:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Filter' }).click();
await page.getByRole('menuitem', { name: 'Add new' }).click();
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 deleteButton(page, 'Filter');
await deleteButton(page, 'Add new');
await deleteButton(page, 'Refresh');
await page.mouse.move(300, 0);
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: '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 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-Delete-destroy-general-grid-card').first()).toBeVisible();
// delete buttons
await page.getByLabel('schema-initializer-ActionBar-gridCard:configureItemActions-general').first().hover();
await page.getByRole('menuitem', { name: 'View' }).click();
await page.getByRole('menuitem', { name: 'Edit' }).click();
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 deleteButton(page, 'View');
await deleteButton(page, 'Edit');
await deleteButton(page, 'Delete');
await page.mouse.move(300, 0);
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 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: 'Update record' }).click();

View File

@ -10,205 +10,98 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
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
* use `gridCardItemActionInitializers` instead
*/
export const gridCardItemActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'GridCardItemActionInitializers',
title: '{{t("Configure actions")}}',
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';
},
},
],
},
],
...commonOptions,
});
export const gridCardItemActionInitializers = new CompatibleSchemaInitializer(
{
name: 'gridCard:configureItemActions',
title: '{{t("Configure actions")}}',
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';
},
},
],
},
],
...commonOptions,
},
gridCardItemActionInitializers_deprecated,
);

View File

@ -10,13 +10,7 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCollection_deprecated } from '../../../../collection-manager';
/**
* @deprecated
* use `listActionInitializers` instead
*
*/
export const listActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ListActionInitializers',
const commonOptions = {
title: "{{t('Configure actions')}}",
icon: 'SettingOutlined',
style: {
@ -24,162 +18,87 @@ export const listActionInitializers_deprecated = new CompatibleSchemaInitializer
},
items: [
{
type: 'itemGroup',
name: 'enableActions',
title: "{{t('Enable actions')}}",
children: [
{
name: 'filter',
title: "{{t('Filter')}}",
Component: 'FilterActionInitializer',
schema: {
'x-align': 'left',
},
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,
},
{
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'
);
},
},
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,
},
{
name: 'refresh',
title: "{{t('Refresh')}}",
Component: 'RefreshActionInitializer',
schema: {
'x-align': 'right',
},
},
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,
},
{
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(
{
name: 'list:configureActions',
title: "{{t('Configure actions')}}",
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,
},
},
},
],
},
],
...commonOptions,
},
listActionInitializers_deprecated,
);

View File

@ -7,9 +7,16 @@
* 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';
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('page', async ({ page, mockPage }) => {
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: '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 expect(page.getByRole('button', { name: 'Filter' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Add new' })).toBeVisible();
await expect(page.getByRole('button', { name: 'Refresh' })).toBeVisible();
// delete buttons
await page.getByLabel('schema-initializer-ActionBar-list:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Filter' }).click();
await page.getByRole('menuitem', { name: 'Add new' }).click();
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 deleteButton(page, 'Filter');
await deleteButton(page, 'Add new');
await deleteButton(page, 'Refresh');
await page.mouse.move(300, 0);
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: '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 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-Delete-destroy-general-list').first()).toBeVisible();
// delete buttons
await page.getByLabel('schema-initializer-ActionBar-list:configureItemActions-general').first().hover();
await page.getByRole('menuitem', { name: 'View' }).click();
await page.getByRole('menuitem', { name: 'Edit' }).click();
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 deleteButton(page, 'View');
await deleteButton(page, 'Edit');
await deleteButton(page, 'Delete');
await page.mouse.move(300, 0);
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 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: 'Update record' }).click();

View File

@ -10,205 +10,98 @@
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
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
* use `listItemActionInitializers` instead
*/
export const listItemActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'ListItemActionInitializers',
title: '{{t("Configure actions")}}',
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';
},
},
],
},
],
...commonOptions,
});
export const listItemActionInitializers = new CompatibleSchemaInitializer(
{
name: 'list:configureItemActions',
title: '{{t("Configure actions")}}',
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';
},
},
],
},
],
...commonOptions,
},
listItemActionInitializers_deprecated,
);

View File

@ -10,6 +10,13 @@
import { Page, expect, test } from '@nocobase/test/e2e';
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('popup', async ({ page, mockPage }) => {
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: '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 expect(page.getByRole('button', { name: 'Filter' })).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();
// delete buttons
await page.getByLabel('schema-initializer-ActionBar-table:configureActions-users').hover();
await page.getByRole('menuitem', { name: 'Filter' }).click();
await page.getByRole('menuitem', { name: 'Add new' }).click();
await page.getByRole('menuitem', { name: 'Delete' }).click();
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 deleteButton(page, 'Filter');
await deleteButton(page, 'Add new');
await deleteButton(page, 'Delete');
await deleteButton(page, 'Refresh');
await page.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Filter' })).not.toBeVisible();
@ -69,7 +65,6 @@ test.describe('configure actions', () => {
await createTable({ page, mockPage, fieldName: 'manyToOne' });
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.mouse.move(300, 0);

View File

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

View File

@ -11,13 +11,7 @@ import { useFieldSchema } from '@formily/react';
import { CompatibleSchemaInitializer } from '../../../../application/schema-initializer/CompatibleSchemaInitializer';
import { useCollection_deprecated } from '../../../../collection-manager/hooks/useCollection_deprecated';
/**
* @deprecated
* use `tableActionInitializers` instead
*
*/
export const tableActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'TableActionInitializers',
const commonOptions = {
title: "{{t('Configure actions')}}",
icon: 'SettingOutlined',
style: {
@ -25,224 +19,85 @@ export const tableActionInitializers_deprecated = new CompatibleSchemaInitialize
},
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;
},
},
],
type: 'item',
name: 'filter',
title: "{{t('Filter')}}",
Component: 'FilterActionInitializer',
schema: {
'x-align': 'left',
},
},
{
name: 'divider',
type: 'divider',
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: '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,
},
},
},
],
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();
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(
{
name: 'table:configureActions',
title: "{{t('Configure actions')}}",
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;
},
},
],
...commonOptions,
},
tableActionInitializers_deprecated,
);

View File

@ -7,9 +7,16 @@
* 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';
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', () => {
// 该用例在 CI 并发环境下容易报错,原因未知,通过增加重试次数可以解决
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: '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 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();
@ -147,17 +149,10 @@ test.describe('configure actions column', () => {
await expect(page.getByLabel('action-Action.Link-Duplicate-duplicate-t_unp4scqamw9-table-0')).toBeVisible();
// delete view & Edit & Delete & Duplicate ------------------------------------------------------------
await page.getByText('Actions', { exact: true }).hover();
await page.getByLabel('designer-schema-settings-TableV2.Column-TableV2.ActionColumnDesigner-t_unp4scqamw9').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();
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 deleteButton(page, 'View');
await deleteButton(page, 'Edit');
await deleteButton(page, 'Delete');
await deleteButton(page, 'Duplicate');
await page.mouse.move(300, 0);
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 ------------------------------------------------------------
await page.getByText('Actions', { exact: true }).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();
// 此时二级菜单,不应该关闭,可以继续点击?

View File

@ -7,9 +7,16 @@
* 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';
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('page', async ({ page, mockPage }) => {
await mockPage().goto();
@ -116,11 +123,6 @@ test.describe('configure actions', () => {
await page.getByRole('menuitem', { name: 'Delete' }).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 expect(page.getByRole('button', { name: 'Filter' })).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();
// delete buttons
await page.getByLabel('schema-initializer-ActionBar-table:configureActions-t_unp4scqamw9').hover();
await page.getByRole('menuitem', { name: 'Filter' }).click();
await page.getByRole('menuitem', { name: 'Add new' }).click();
await page.getByRole('menuitem', { name: 'Delete' }).click();
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 deleteButton(page, 'Filter');
await deleteButton(page, 'Add new');
await deleteButton(page, 'Delete');
await deleteButton(page, 'Refresh');
await page.mouse.move(300, 0);
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: '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';
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('add new', () => {
const showMenu = async (page: Page) => {
@ -295,21 +316,6 @@ test.describe('actions schema settings', () => {
});
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) => {
await page.getByLabel('action-Action.Link-Popup-customize:popup-general-table-0').hover();
await page
@ -352,21 +358,6 @@ test.describe('actions schema settings', () => {
});
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) => {
await page.getByLabel('action-Action.Link-Update record-customize:update-general-table-0').hover();
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())) {
await page.getByRole('button', { name: 'Actions', exact: true }).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();
}
@ -473,7 +463,8 @@ test.describe('actions schema settings', () => {
await page.getByRole('menuitem', { 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.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.getByLabel('schema-initializer-ActionBar-createForm:configureActions-treeCollection').hover();
await page.getByRole('menuitem', { name: 'Submit' }).click();
@ -500,7 +491,8 @@ test.describe('actions schema settings', () => {
position: { x: 5, y: 5 }, // 防止按钮被遮挡
});
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.getByLabel('schema-initializer-Grid-form:').hover();
await page.getByRole('menuitem', { name: 'Parent', exact: true }).click();

View File

@ -8,6 +8,28 @@
*/
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
@ -16,65 +38,13 @@ import { CompatibleSchemaInitializer } from '../../../../application/schema-init
*/
export const filterFormActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'FilterFormActionInitializers',
title: '{{t("Configure actions")}}',
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': {},
},
},
],
},
],
...commonOptions,
});
export const filterFormActionInitializers = new CompatibleSchemaInitializer(
{
name: 'filterForm:configureActions',
title: '{{t("Configure actions")}}',
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': {},
},
},
],
},
],
...commonOptions,
},
filterFormActionInitializers_deprecated,
);

View File

@ -7,9 +7,16 @@
* 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';
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('page', async ({ page, mockPage }) => {
await mockPage().goto();
@ -104,21 +111,13 @@ test.describe('configure actions', () => {
await page.getByRole('menuitem', { name: 'Filter' }).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 expect(page.getByLabel('action-Action-Filter-submit-general-filter-form')).toBeVisible();
await expect(page.getByLabel('action-Action-Reset-general-filter-form')).toBeVisible();
// delete buttons
await page.getByLabel('schema-initializer-ActionBar-filterForm:configureActions-general').hover();
await page.getByRole('menuitem', { name: 'Filter' }).click();
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 deleteButton(page, 'Filter');
await deleteButton(page, 'Reset');
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-Reset-general-filter-form')).not.toBeVisible();

View File

@ -14,12 +14,7 @@ import {
} from '../../../../schema-initializer/buttons/FormItemInitializers';
import { gridRowColWrap, useFilterFormItemInitializerFields } from '../../../../schema-initializer/utils';
/**
* @deprecated
* use `filterFormItemInitializers` instead
*/
export const filterFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'FilterFormItemInitializers',
const commonOptions = {
wrap: gridRowColWrap,
icon: 'SettingOutlined',
title: '{{t("Configure fields")}}',
@ -48,39 +43,21 @@ export const filterFormItemInitializers_deprecated = new CompatibleSchemaInitial
name: 'addText',
},
],
};
/**
* @deprecated
* use `filterFormItemInitializers` instead
*/
export const filterFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'FilterFormItemInitializers',
...commonOptions,
});
export const filterFormItemInitializers = new CompatibleSchemaInitializer(
{
name: 'filterForm:configureFields',
wrap: gridRowColWrap,
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',
},
],
...commonOptions,
},
filterFormItemInitializers_deprecated,
);

View File

@ -10,12 +10,7 @@
import { CompatibleSchemaInitializer } from '../../application/schema-initializer/CompatibleSchemaInitializer';
import { gridRowColWrap } from '../../schema-initializer/utils';
/**
* @deprecated
* use `blockInitializers` instead
*/
export const blockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BlockInitializers',
const commonOptions = {
title: '{{t("Add block")}}',
icon: 'PlusOutlined',
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(
{
name: 'page:addBlock',
title: '{{t("Add block")}}',
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',
},
],
},
],
...commonOptions,
},
blockInitializers_deprecated,
);

View File

@ -33,8 +33,9 @@ test.describe('where to open a popup and what can be added to it', () => {
// add blocks
await page.getByLabel('schema-initializer-Grid-popup:addNew:addBlock-general').hover();
await page.getByText('Form').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);

View File

@ -14,7 +14,7 @@ import { SchemaComponentContext, createDesignable } from '../..';
import { useAPIClient } from '../../../api-client';
import { useBlockRequestContext } from '../../../block-provider';
import { mergeFilter } from '../../../filter-provider/utils';
import { ActionInitializer } from '../../../schema-initializer/items/ActionInitializer';
import { ActionInitializerItem } from '../../../schema-initializer/items/ActionInitializerItem';
/**
* @deprecated
@ -58,5 +58,5 @@ export const ActionBarAssociationFilterAction = (props) => {
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>;
};
/**
* @deprecated
* use `customFormItemInitializers` instead
*/
export const customFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CustomFormItemInitializers',
const commonOptions = {
wrap: gridRowColWrap,
icon: 'SettingOutlined',
title: '{{t("Configure fields")}}',
@ -54,26 +49,21 @@ export const customFormItemInitializers_deprecated = new CompatibleSchemaInitial
Component: ParentCollectionFields,
},
],
};
/**
* @deprecated
* use `customFormItemInitializers` instead
*/
export const customFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'CustomFormItemInitializers',
...commonOptions,
});
export const customFormItemInitializers = new CompatibleSchemaInitializer(
{
name: 'assignFieldValuesForm:configureFields',
wrap: gridRowColWrap,
icon: 'SettingOutlined',
title: '{{t("Configure fields")}}',
items: [
{
type: 'itemGroup',
title: '{{t("Configure fields")}}',
name: 'configureFields',
useChildren: useCustomFormItemInitializerFields,
},
{
name: 'parentCollectionFields',
Component: ParentCollectionFields,
},
],
...commonOptions,
},
customFormItemInitializers_deprecated,
);

View File

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

View File

@ -9,13 +9,7 @@
import { CompatibleSchemaInitializer } from '../../application/schema-initializer/CompatibleSchemaInitializer';
/**
* @deprecated
* use `subTableActionInitializers` instead
*
*/
export const subTableActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'SubTableActionInitializers',
const commonOptions = {
title: "{{t('Configure actions')}}",
icon: 'SettingOutlined',
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(
{
name: 'subTable:configureActions',
title: "{{t('Configure actions')}}",
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',
},
},
],
},
],
...commonOptions,
},
subTableActionInitializers_deprecated,
);

View File

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

View File

@ -9,9 +9,15 @@
import React from 'react';
import { InitializerWithSwitch } from './InitializerWithSwitch';
import { useSchemaInitializerItem } from '../../application';
import { InitializerWithSwitch } from './InitializerWithSwitch';
/**
* @deprecated
* use ActionInitializerItem instead
* @param props
* @returns
*/
export const ActionInitializer = (props) => {
const itemConfig = useSchemaInitializerItem();
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 { ActionInitializer } from './ActionInitializer';
export const CreateFilterActionInitializer = (props) => {

View File

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

View File

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

View File

@ -8,8 +8,7 @@
*/
import React from 'react';
import { ActionInitializer } from './ActionInitializer';
import { ActionInitializerItem } from './ActionInitializerItem';
export const DeleteEventActionInitializer = (props) => {
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 { ActionInitializer } from './ActionInitializer';
import { ActionInitializerItem } from './ActionInitializerItem';
export const SelectActionInitializer = (props) => {
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 { ActionInitializer } from './ActionInitializer';
import { ActionInitializerItem } from './ActionInitializerItem';
export const SubmitActionInitializer = (props) => {
const schema = {
@ -24,5 +23,5 @@ export const SubmitActionInitializer = (props) => {
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/AssociationFilterDesignerDisplayField';
export * from './ActionInitializer';
export * from './ActionInitializerItem';
export * from './BlockInitializer';
export * from './CreateFilterActionInitializer';
export * from './CreateResetActionInitializer';

View File

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

View File

@ -47,12 +47,7 @@ export const CreateFormBulkEditBlockInitializers: SchemaInitializer = new Schema
],
});
/**
* @deprecated
* use `bulkEditBlockInitializers` instead
*/
export const BulkEditBlockInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BulkEditBlockInitializers',
const commonOptions = {
wrap: gridRowColWrap,
title: '{{t("Add block")}}',
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(
{
name: 'popup:bulkEdit:addBlock',
wrap: gridRowColWrap,
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',
},
],
},
],
...commonOptions,
},
BulkEditBlockInitializers_deprecated,
);

View File

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

View File

@ -10,12 +10,7 @@
import { CompatibleSchemaInitializer, gridRowColWrap } from '@nocobase/client';
import { useCustomBulkEditFormItemInitializerFields } from './utils';
/**
* @deprecated
* use `bulkEditFormItemInitializers` instead
*/
export const BulkEditFormItemInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'BulkEditFormItemInitializers',
const commonOptions = {
wrap: gridRowColWrap,
icon: 'SettingOutlined',
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(
{
name: 'bulkEditForm:configureFields',
wrap: gridRowColWrap,
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**.")}}',
},
},
},
],
...commonOptions,
},
BulkEditFormItemInitializers_deprecated,
);

View File

@ -7,8 +7,8 @@
* For more information, please refer to: https://www.nocobase.com/agreement.
*/
import { ActionInitializerItem } from '@nocobase/client';
import React from 'react';
import { ActionInitializer } from '@nocobase/client';
export const BulkEditSubmitActionInitializer = (props) => {
const schema = {
@ -24,5 +24,5 @@ export const BulkEditSubmitActionInitializer = (props) => {
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 }) => {
await mockPage(oneEmptyTableBlockWithActions).goto();
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.mouse.move(300, 0);
await expect(page.getByLabel('Bulk edit')).toBeVisible();
@ -24,7 +23,6 @@ test.describe('TableActionInitializers & GanttActionInitializers & MapActionInit
await mockRecords('general', 3);
await nocoPage.goto();
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 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 }) => {
await mockPage(oneEmptyTableBlockWithCustomizeActions).goto();
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 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 nocoPage.goto();
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.mouse.move(300, 0);
await expect(page.getByRole('button', { name: 'Bulk update' })).toBeVisible();

View File

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

View File

@ -7,7 +7,7 @@
* 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';
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('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.getByLabel('schema-initializer-Grid-form:configureFields-general').hover();
await page.getByRole('menuitem', { name: 'singleLineText' }).click();

View File

@ -7,12 +7,11 @@
* 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 {
SchemaInitializerSwitch,
SchemaInitializerItem,
useCollection_deprecated,
useDesignable,
useSchemaInitializer,
useSchemaInitializerItem,
} from '@nocobase/client';
@ -31,21 +30,6 @@ const findSchema = (schema: Schema, key: string, action: string) => {
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 exportSettings = fields?.filter((f) => !f.children).map((f) => ({ dataIndex: [f.name] }));
@ -55,7 +39,6 @@ const initExportSettings = (fields) => {
export const ExportActionInitializer = () => {
const itemConfig = useSchemaInitializerItem();
const { insert } = useSchemaInitializer();
const { exists, remove } = useCurrentSchema('export', 'x-action', itemConfig.find, itemConfig.remove);
const { name } = useCollection_deprecated();
const fields = useFields(name);
@ -75,15 +58,11 @@ export const ExportActionInitializer = () => {
icon: 'clouddownloadoutlined',
},
};
return (
<SchemaInitializerSwitch
{...itemConfig}
checked={exists}
<SchemaInitializerItem
title={itemConfig.title}
onClick={() => {
if (exists) {
return remove();
}
schema['x-action-settings']['exportSettings'] = initExportSettings(fields);
const s = merge(schema || {}, itemConfig.schema || {});
itemConfig?.schemaInitialize?.(s);

View File

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

View File

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

View File

@ -7,7 +7,7 @@
* 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';
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 { useTranslation } from 'react-i18next';
/**
* @deprecated
* use `auditLogsTableActionColumnInitializers` instead
*/
export const auditLogsTableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'AuditLogsTableActionColumnInitializers',
const commonOptions = {
insertPosition: 'beforeEnd',
Component: (props: any) => <MenuOutlined {...props} style={{ cursor: 'pointer' }} />,
useInsert() {
@ -83,69 +78,21 @@ export const auditLogsTableActionColumnInitializers_deprecated = new CompatibleS
Component: Resizable,
},
],
};
/**
* @deprecated
* use `auditLogsTableActionColumnInitializers` instead
*/
export const auditLogsTableActionColumnInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'AuditLogsTableActionColumnInitializers',
...commonOptions,
});
export const auditLogsTableActionColumnInitializers = new CompatibleSchemaInitializer(
{
name: 'auditLogsTable:configureItemActions',
insertPosition: 'beforeEnd',
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,
},
],
...commonOptions,
},
auditLogsTableActionColumnInitializers_deprecated,
);

View File

@ -9,13 +9,7 @@
import { CompatibleSchemaInitializer } from '@nocobase/client';
/**
* @deprecated
* use `auditLogsTableActionInitializers` instead
*
*/
export const auditLogsTableActionInitializers_deprecated = new CompatibleSchemaInitializer({
name: 'AuditLogsTableActionInitializers',
const commonOptions = {
title: "{{t('Configure actions')}}",
icon: 'SettingOutlined',
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(
{
name: 'auditLogsTable:configureActions',
title: "{{t('Configure actions')}}",
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',
},
},
],
},
],
...commonOptions,
},
auditLogsTableActionInitializers_deprecated,
);

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