From fd4c9cb2882d61fe6324b2884c78100412d19a29 Mon Sep 17 00:00:00 2001 From: Zeke Zhang <958414905@qq.com> Date: Tue, 23 Apr 2024 21:18:27 +0800 Subject: [PATCH] chore: deprecate the current record variable from the form (#4063) * chore: remove the current record variable from the form * chore: fix failed e2e * refactor(VariableInput): support for setting the react node for label * feat: support to show tooltip * chore: stash * chore: add translation * chore: add translation * chore: fix expresion * test: add e2e for deprecated variables * refactor: migrate file * chore: make e2e pass * chore: make e2e pass * chore: make e2e pass * chore: adjust * chore: natch * chore: revert match --- .../src/block-provider/BlockProvider.tsx | 2 +- packages/core/client/src/locale/en_US.json | 3 +- packages/core/client/src/locale/es_ES.json | 3 +- packages/core/client/src/locale/fr_FR.json | 3 +- packages/core/client/src/locale/ja_JP.json | 3 +- packages/core/client/src/locale/ko_KR.json | 3 +- packages/core/client/src/locale/pt_BR.json | 3 +- packages/core/client/src/locale/ru_RU.json | 3 +- packages/core/client/src/locale/tr_TR.json | 3 +- packages/core/client/src/locale/uk_UA.json | 3 +- packages/core/client/src/locale/zh-CN.json | 3 +- packages/core/client/src/locale/zh-TW.json | 3 +- .../__e2e__/form-create/templatesOfBug.ts | 408 ++++++++++++++++++ .../form-edit/deprecatedVariables.test.ts | 59 +++ .../grid-card/__e2e__/schemaSettings.test.ts | 4 +- .../table/__e2e__/schemaSettings.test.ts | 8 +- .../popup/__e2e__/schemaSettings.test.ts | 4 +- .../src/modules/popup/__e2e__/zIndex.test.ts | 2 +- .../schema-component/antd/variable/Input.tsx | 23 +- .../antd/variable/TextArea.tsx | 25 +- .../src/schema-settings/SchemaSettings.tsx | 107 ++--- .../VariableInput/VariableInput.tsx | 2 +- .../VariableInput/hooks/useBaseVariable.tsx | 52 ++- .../VariableInput/hooks/useRecordVariable.ts | 4 + .../src/schema-settings/VariableInput/type.ts | 1 + .../fields/richText/schemaSettings.test.ts | 2 +- .../singleLineText/schemaSettings.test.ts | 6 +- 27 files changed, 647 insertions(+), 95 deletions(-) create mode 100644 packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/deprecatedVariables.test.ts diff --git a/packages/core/client/src/block-provider/BlockProvider.tsx b/packages/core/client/src/block-provider/BlockProvider.tsx index fd4de45d66..a69fcb0f5f 100644 --- a/packages/core/client/src/block-provider/BlockProvider.tsx +++ b/packages/core/client/src/block-provider/BlockProvider.tsx @@ -194,7 +194,7 @@ export const RenderChildrenWithAssociationFilter: React.FC = (props) => { /** * @internal */ -const BlockContext = createContext<{ +export const BlockContext = createContext<{ /** 用以区分区块的标识 */ name: string; }>(null); diff --git a/packages/core/client/src/locale/en_US.json b/packages/core/client/src/locale/en_US.json index fa9525fa6e..d60dee5fa1 100644 --- a/packages/core/client/src/locale/en_US.json +++ b/packages/core/client/src/locale/en_US.json @@ -822,5 +822,6 @@ "Owners": "Owners", "Plugin settings": "Plugin settings", "Menu": "Menu", - "Drag and drop sorting field": "Drag and drop sorting field" + "Drag and drop sorting field": "Drag and drop sorting field", + "This variable has been deprecated and can be replaced with \"Current form\"": "This variable has been deprecated and can be replaced with \"Current form\"" } diff --git a/packages/core/client/src/locale/es_ES.json b/packages/core/client/src/locale/es_ES.json index 2cba59cc6d..97be495420 100644 --- a/packages/core/client/src/locale/es_ES.json +++ b/packages/core/client/src/locale/es_ES.json @@ -755,5 +755,6 @@ "DataSource": "Fuente de datos", "Home page": "Página de inicio", "Handbook": "Manual de usuario", - "License": "Licencia" + "License": "Licencia", + "This variable has been deprecated and can be replaced with \"Current form\"": "La variable ha sido obsoleta; \"Formulario actual\" puede ser utilizada como sustituto" } diff --git a/packages/core/client/src/locale/fr_FR.json b/packages/core/client/src/locale/fr_FR.json index e5eac54eef..134978feed 100644 --- a/packages/core/client/src/locale/fr_FR.json +++ b/packages/core/client/src/locale/fr_FR.json @@ -775,5 +775,6 @@ "Allow selection of existing records":"Permet de sélectionner des données existantes", "Home page": "Page d'accueil", "Handbook": "Manuel de l'utilisateur", - "License": "Licence" + "License": "Licence", + "This variable has been deprecated and can be replaced with \"Current form\"": "La variable a été obsolète ; \"Formulaire actuel\" peut être utilisé comme substitut" } diff --git a/packages/core/client/src/locale/ja_JP.json b/packages/core/client/src/locale/ja_JP.json index c0ae050d24..dd3c7d84fd 100644 --- a/packages/core/client/src/locale/ja_JP.json +++ b/packages/core/client/src/locale/ja_JP.json @@ -694,5 +694,6 @@ "The {{type}} \"{{name}}\" may have been deleted. Please remove this {{blockType}}.": "{{type}} \"{{name}}\" は削除されている可能性があります。この {{blockType}} を削除してください。", "Home page": "ホームページ", "Handbook": "ユーザーマニュアル", - "License": "ライセンス" + "License": "ライセンス", + "This variable has been deprecated and can be replaced with \"Current form\"": "この変数は非推奨です。代わりに「現在のフォーム」を使用してください" } diff --git a/packages/core/client/src/locale/ko_KR.json b/packages/core/client/src/locale/ko_KR.json index 093f0c7acc..150c484ae5 100644 --- a/packages/core/client/src/locale/ko_KR.json +++ b/packages/core/client/src/locale/ko_KR.json @@ -866,5 +866,6 @@ "The {{type}} \"{{name}}\" may have been deleted. Please remove this {{blockType}}.": "{{type}} \"{{name}}\"이(가) 삭제되었을 수 있습니다. 이 {{blockType}}을(를) 제거하십시오.", "Home page": "홈페이지", "Handbook": "사용자 매뉴얼", - "License": "라이선스" + "License": "라이선스", + "This variable has been deprecated and can be replaced with \"Current form\"": "변수가 폐기되었습니다. \"현재 폼\"을 대체로 사용할 수 있습니다" } diff --git a/packages/core/client/src/locale/pt_BR.json b/packages/core/client/src/locale/pt_BR.json index a24cc333fa..662c0a5591 100644 --- a/packages/core/client/src/locale/pt_BR.json +++ b/packages/core/client/src/locale/pt_BR.json @@ -733,5 +733,6 @@ "Allow selection of existing records":"Permitir a selecção dos registos existentes", "Home page": "Página inicial", "Handbook": "Manual do usuário", - "License": "Licença" + "License": "Licença", + "This variable has been deprecated and can be replaced with \"Current form\"": "A variável foi descontinuada; \"Formulário atual\" pode ser usada como substituto" } diff --git a/packages/core/client/src/locale/ru_RU.json b/packages/core/client/src/locale/ru_RU.json index e82aa15cd2..9dc67214c8 100644 --- a/packages/core/client/src/locale/ru_RU.json +++ b/packages/core/client/src/locale/ru_RU.json @@ -569,5 +569,6 @@ "DataSource": "Источник данных", "Home page": "Домашняя страница", "Handbook": "Руководство пользователя", - "License": "Лицензия" + "License": "Лицензия", + "This variable has been deprecated and can be replaced with \"Current form\"": "Переменная устарела; \"Текущая форма\" может быть использована в качестве замены" } diff --git a/packages/core/client/src/locale/tr_TR.json b/packages/core/client/src/locale/tr_TR.json index 46d4eb7149..9aa15333bb 100644 --- a/packages/core/client/src/locale/tr_TR.json +++ b/packages/core/client/src/locale/tr_TR.json @@ -567,5 +567,6 @@ "The {{type}} \"{{name}}\" may have been deleted. Please remove this {{blockType}}.": "{{type}} \"{{name}}\" silinmiş olabilir. Lütfen bu {{blockType}}'yi kaldırın.", "Home page": "Anasayfa", "Handbook": "Kullanıcı kılavuzu", - "License": "Lisans" + "License": "Lisans", + "This variable has been deprecated and can be replaced with \"Current form\"": "Değişken kullanımdan kaldırıldı; \"Geçerli form\" yerine kullanılabilir" } diff --git a/packages/core/client/src/locale/uk_UA.json b/packages/core/client/src/locale/uk_UA.json index 892f398777..e5cf5b94e5 100644 --- a/packages/core/client/src/locale/uk_UA.json +++ b/packages/core/client/src/locale/uk_UA.json @@ -775,5 +775,6 @@ "The {{type}} \"{{name}}\" may have been deleted. Please remove this {{blockType}}.": "{{type}} \"{{name}}\" може бути видалено. Будь ласка, видаліть цей {{blockType}}.", "Home page": "Домашня сторінка", "Handbook": "Посібник користувача", - "License": "Ліцензія" + "License": "Ліцензія", + "This variable has been deprecated and can be replaced with \"Current form\"": "Змінна була застарілою; \"Поточна форма\" може бути використана як заміна" } diff --git a/packages/core/client/src/locale/zh-CN.json b/packages/core/client/src/locale/zh-CN.json index 3dc7541106..3f97e27403 100644 --- a/packages/core/client/src/locale/zh-CN.json +++ b/packages/core/client/src/locale/zh-CN.json @@ -928,5 +928,6 @@ "Normal": "常规", "Automatically generate default values": "随机生成默认值", "Refresh data on close": "关闭后刷新数据", - "Refresh data on action": "执行后刷新数据" + "Refresh data on action": "执行后刷新数据", + "This variable has been deprecated and can be replaced with \"Current form\"": "该变量已被弃用,可以使用“当前表单”替代" } diff --git a/packages/core/client/src/locale/zh-TW.json b/packages/core/client/src/locale/zh-TW.json index 896fb6a33b..e224b10c7d 100644 --- a/packages/core/client/src/locale/zh-TW.json +++ b/packages/core/client/src/locale/zh-TW.json @@ -864,5 +864,6 @@ "Allow selection of existing records":"允許選擇已有資料", "Home page": "主頁", "Handbook": "使用手冊", - "License": "許可證" + "License": "許可證", + "This variable has been deprecated and can be replaced with \"Current form\"": "該變數已被棄用,可以使用“當前表單”作為替代" } diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/templatesOfBug.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/templatesOfBug.ts index d1c98e5f0f..5567a54826 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/templatesOfBug.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-create/templatesOfBug.ts @@ -8472,3 +8472,411 @@ export const T3979: PageConfig = { 'x-index': 1, }, }; +export const oneTableWithUsersForDeprecatedVariables = { + pageSchema: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Page', + properties: { + '0kf7f0ilx5p': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'page:addBlock', + properties: { + '7nkrwaiut3c': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '0.21.0-alpha.12', + properties: { + okrwqoxd83x: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '0.21.0-alpha.12', + properties: { + h00mdakub1n: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'users:list', + 'x-use-decorator-props': 'useTableBlockDecoratorProps', + 'x-decorator-props': { + collection: 'users', + dataSource: 'main', + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + showIndex: true, + dragSort: false, + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:table', + 'x-component': 'CardItem', + 'x-filter-targets': [], + 'x-app-version': '0.21.0-alpha.12', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'table:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + 'x-app-version': '0.21.0-alpha.12', + 'x-uid': 'esse5o4398b', + 'x-async': false, + 'x-index': 1, + }, + '630zp06en3b': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'array', + 'x-initializer': 'table:configureColumns', + 'x-component': 'TableV2', + 'x-use-component-props': 'useTableBlockProps', + 'x-component-props': { + rowKey: 'id', + rowSelection: { + type: 'checkbox', + }, + }, + 'x-app-version': '0.21.0-alpha.12', + properties: { + actions: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Actions") }}', + 'x-action-column': 'actions', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-component': 'TableV2.Column', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-initializer': 'table:configureItemActions', + 'x-app-version': '0.21.0-alpha.12', + properties: { + '1my2j5tqtvu': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-decorator': 'DndContext', + 'x-component': 'Space', + 'x-component-props': { + split: '|', + }, + 'x-app-version': '0.21.0-alpha.12', + properties: { + d0bwrtz9f7j: { + 'x-uid': '7mzammd9sbg', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: 'Edit record', + 'x-action': 'update', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:edit', + 'x-component': 'Action.Link', + 'x-component-props': { + openMode: 'drawer', + danger: false, + }, + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + properties: { + drawer: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{ t("Edit record") }}', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + properties: { + tabs: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Tabs', + 'x-component-props': {}, + 'x-initializer': 'popup:addTab', + properties: { + tab1: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + title: '{{t("Edit")}}', + 'x-component': 'Tabs.TabPane', + 'x-designer': 'Tabs.Designer', + 'x-component-props': {}, + properties: { + grid: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'popup:common:addBlock', + properties: { + dq07f3u2u30: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '0.21.0-alpha.12', + properties: { + nxs6wg3n41c: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '0.21.0-alpha.12', + properties: { + mhk7rm0fw12: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-acl-action-props': { + skipScopeCheck: false, + }, + 'x-acl-action': 'users:update', + 'x-decorator': 'FormBlockProvider', + 'x-use-decorator-props': + 'useEditFormBlockDecoratorProps', + 'x-decorator-props': { + action: 'get', + dataSource: 'main', + collection: 'users', + }, + 'x-toolbar': 'BlockSchemaToolbar', + 'x-settings': 'blockSettings:editForm', + 'x-component': 'CardItem', + 'x-app-version': '0.21.0-alpha.12', + properties: { + '54b22mqfpmx': { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'FormV2', + 'x-use-component-props': 'useEditFormBlockProps', + 'x-app-version': '0.21.0-alpha.12', + properties: { + grid: { + 'x-uid': 'ufdkfceoidc', + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid', + 'x-initializer': 'form:configureFields', + 'x-app-version': '0.21.0-alpha.12', + 'x-linkage-rules': [ + { + condition: { + $and: [ + { + nickname: { + $includes: '{{$nRecord.nickname}}', + }, + }, + ], + }, + actions: [ + { + targetFields: ['nickname'], + operator: 'value', + value: { + mode: 'express', + value: '{{$nRecord.username}}', + result: '{{$nRecord.username}}', + }, + }, + ], + }, + ], + properties: { + g5r0oap3utr: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Row', + 'x-app-version': '0.21.0-alpha.12', + properties: { + lsugzv7lefq: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-component': 'Grid.Col', + 'x-app-version': '0.21.0-alpha.12', + properties: { + nickname: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'string', + 'x-toolbar': + 'FormItemSchemaToolbar', + 'x-settings': + 'fieldSettings:FormItem', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-collection-field': + 'users.nickname', + 'x-component-props': {}, + 'x-app-version': '0.21.0-alpha.12', + 'x-uid': '96ztt5zwj94', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'bx1yby02otk', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ov7zgdkgw75', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + iia8azf8515: { + _isJSONSchemaObject: true, + version: '2.0', + type: 'void', + 'x-initializer': 'editForm:configureActions', + 'x-component': 'ActionBar', + 'x-component-props': { + layout: 'one-column', + style: { + marginTop: 24, + }, + }, + 'x-app-version': '0.21.0-alpha.12', + properties: { + m2ya2utojyv: { + _isJSONSchemaObject: true, + version: '2.0', + title: '{{ t("Submit") }}', + 'x-action': 'submit', + 'x-component': 'Action', + 'x-use-component-props': + 'useUpdateActionProps', + 'x-toolbar': 'ActionSchemaToolbar', + 'x-settings': 'actionSettings:updateSubmit', + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + }, + 'x-action-settings': { + triggerWorkflows: [], + }, + type: 'void', + 'x-app-version': '0.21.0-alpha.12', + 'x-uid': 'bk42qy23o72', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '7l3e8eg5twd', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'hd2ivxz2yab', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'q66c3ygx762', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6lc4ohi2dro', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'e8wspaxavfr', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ra8agi0pvsa', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'yos0bp0yikg', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '45maugqwh7b', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ksrayq74oxe', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'o0u2aidtwdw', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '14wmkjgx19j', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5bzwy79fbvz', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'qehg70dxj8b', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1f9ilr6t1yn', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fcvb1l15gv9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '2ahlv6ydwlp', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8uggi2e1r5s', + 'x-async': true, + 'x-index': 1, + }, +}; diff --git a/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/deprecatedVariables.test.ts b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/deprecatedVariables.test.ts new file mode 100644 index 0000000000..920b3b94ff --- /dev/null +++ b/packages/core/client/src/modules/blocks/data-blocks/form/__e2e__/form-edit/deprecatedVariables.test.ts @@ -0,0 +1,59 @@ +import { expect, test } from '@nocobase/test/e2e'; +import { oneTableWithUsersForDeprecatedVariables } from '../form-create/templatesOfBug'; + +test.describe('deprecated variables', () => { + test('current record', async ({ page, mockPage, mockRecord }) => { + await mockPage(oneTableWithUsersForDeprecatedVariables).goto(); + + // 1. 已设置过 Current record 的变量依然能正常显示 + await page.getByLabel('action-Action.Link-Edit').click(); + await page.getByLabel('block-item-CardItem-users-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-blockSettings:editForm-users').hover(); + await page.getByRole('menuitem', { name: 'Linkage rules' }).click(); + await expect(page.getByLabel('variable-tag').getByText('Current record / Nickname')).toBeVisible(); + + // 2. 但是变量列表中是禁用状态 + await page.locator('button').filter({ hasText: /^x$/ }).click(); + await page.getByRole('menuitemcheckbox', { name: 'Current record right' }).hover({ position: { x: 40, y: 12 } }); + await expect(page.getByRole('tooltip', { name: 'This variable has been deprecated' })).toBeVisible(); + await expect(page.getByRole('menuitemcheckbox', { name: 'Current record right' })).toHaveClass( + new RegExp('ant-cascader-menu-item-disabled'), + ); + await page.mouse.move(0, 300); + // 使下拉菜单消失 + await page.getByLabel('Linkage rules').getByText('Linkage rules').click(); + + // 表达式输入框也是一样 + await page.getByText('xSelect a variable').click(); + await page.getByRole('menuitemcheckbox', { name: 'Current record right' }).hover({ position: { x: 40, y: 12 } }); + await expect(page.getByRole('tooltip', { name: 'This variable has been deprecated' })).toBeVisible(); + await expect(page.getByRole('menuitemcheckbox', { name: 'Current record right' })).toHaveClass( + new RegExp('ant-cascader-menu-item-disabled'), + ); + await page.mouse.move(0, 300); + // 使下拉菜单消失 + await page.getByLabel('Linkage rules').getByText('Linkage rules').click(); + + // 3. 当设置为其它变量后,再次打开,变量列表中的弃用变量不再显示 + await page.locator('button').filter({ hasText: /^x$/ }).click(); + await page.getByRole('menuitemcheckbox', { name: 'Current form right' }).click(); + await page.getByRole('menuitemcheckbox', { name: 'Nickname' }).click(); + await expect(page.getByLabel('variable-tag').getByText('Current form / Nickname')).toBeVisible(); + // 清空表达式 + await page.getByLabel('textbox').clear(); + await page.getByRole('button', { name: 'OK', exact: true }).click(); + + // 4. 再次打开弹窗,变量列表中的弃用变量不再显示 + await page.getByLabel('block-item-CardItem-users-form').hover(); + await page.getByLabel('designer-schema-settings-CardItem-blockSettings:editForm-users').hover(); + await page.getByRole('menuitem', { name: 'Linkage rules' }).click(); + await page.locator('button').filter({ hasText: /^x$/ }).click(); + await expect(page.getByRole('menuitemcheckbox', { name: 'Current record right' })).toBeHidden(); + // 使下拉菜单消失 + await page.getByLabel('Linkage rules').getByText('Linkage rules').click(); + + // 表达式也是一样 + await page.getByText('xSelect a variable').click(); + await expect(page.getByRole('menuitemcheckbox', { name: 'Current record right' })).toBeHidden(); + }); +}); diff --git a/packages/core/client/src/modules/blocks/data-blocks/grid-card/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/blocks/data-blocks/grid-card/__e2e__/schemaSettings.test.ts index 56a192820f..9b33c7e509 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/grid-card/__e2e__/schemaSettings.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/grid-card/__e2e__/schemaSettings.test.ts @@ -37,7 +37,7 @@ test.describe('grid card block schema settings', () => { await page.getByLabel('block-item-BlockItem-general-grid-card').hover(); await page.getByLabel('designer-schema-settings-BlockItem-GridCard.Designer-general').hover(); await page.getByRole('menuitem', { name: 'Set the count of columns displayed in a row' }).click(); - await page.getByLabel('block-item-Slider-general-Desktop device').getByText('2', { exact: true }).click(); + await page.getByLabel('block-item-Slider-general-grid-card-Desktop device').getByText('2', { exact: true }).click(); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 需要刷新页面才会生效 @@ -64,7 +64,7 @@ test.describe('grid card block schema settings', () => { await page.getByLabel('block-item-BlockItem-general-').hover(); await page.getByLabel('designer-schema-settings-BlockItem-blockSettings:gridCard-general').hover(); await page.getByRole('menuitem', { name: 'Set the count of columns displayed in a row' }).click(); - await page.getByLabel('block-item-Slider-general-Desktop device').getByText('2', { exact: true }).click(); + await page.getByLabel('block-item-Slider-general-grid-card-Desktop device').getByText('2', { exact: true }).click(); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 需要刷新页面才会生效 diff --git a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts index 61f8567966..985ac77ebf 100644 --- a/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts +++ b/packages/core/client/src/modules/blocks/data-blocks/table/__e2e__/schemaSettings.test.ts @@ -438,8 +438,8 @@ test.describe('actions schema settings', () => { await showMenu(page); await page.getByRole('menuitem', { name: 'Edit button' }).click(); - await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').click(); - await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').fill('1234'); + await page.getByLabel('block-item-Input-general-').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-general-').getByRole('textbox').fill('1234'); await page.getByRole('button', { name: 'OK', exact: true }).click(); await expect(page.getByRole('button', { name: '1234' })).toBeVisible(); @@ -569,8 +569,8 @@ test.describe('actions schema settings', () => { await showMenu(page); await page.getByRole('menuitem', { name: 'Edit button' }).click(); - await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').click(); - await page.getByLabel('block-item-Input-general-Button title').getByRole('textbox').fill('Delete record'); + await page.getByLabel('block-item-Input-general-').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-general-').getByRole('textbox').fill('Delete record'); await page.getByRole('button', { name: 'OK', exact: true }).click(); await expect(page.getByLabel('action-Action.Link-Delete record-destroy-general-table-0')).toBeVisible(); diff --git a/packages/core/client/src/modules/popup/__e2e__/schemaSettings.test.ts b/packages/core/client/src/modules/popup/__e2e__/schemaSettings.test.ts index 5c34992262..8326b44310 100644 --- a/packages/core/client/src/modules/popup/__e2e__/schemaSettings.test.ts +++ b/packages/core/client/src/modules/popup/__e2e__/schemaSettings.test.ts @@ -25,8 +25,8 @@ test.describe('tabs schema settings', () => { await showSettings(page); await page.getByRole('menuitem', { name: 'Edit', exact: true }).click(); await page.mouse.move(300, 0); - await page.getByLabel('block-item-Input-general-Tab name').getByRole('textbox').click(); - await page.getByLabel('block-item-Input-general-Tab name').getByRole('textbox').fill('Add new with new name'); + await page.getByLabel('block-item-Input-general-').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-general-').getByRole('textbox').fill('Add new with new name'); await page.getByRole('button', { name: 'Select icon' }).click(); await page.getByLabel('account-book').locator('svg').click(); await page.getByRole('button', { name: 'OK', exact: true }).click(); diff --git a/packages/core/client/src/modules/popup/__e2e__/zIndex.test.ts b/packages/core/client/src/modules/popup/__e2e__/zIndex.test.ts index 61512c6b2f..fab8a75611 100644 --- a/packages/core/client/src/modules/popup/__e2e__/zIndex.test.ts +++ b/packages/core/client/src/modules/popup/__e2e__/zIndex.test.ts @@ -12,7 +12,7 @@ test.describe('z-index of dialog', () => { await page.getByRole('button', { name: 'designer-schema-settings-' }).hover(); await page.getByRole('menuitem', { name: 'Edit block title' }).click(); - await expect(page.getByLabel('block-item-Input-users-Block')).toBeVisible(); + await expect(page.getByLabel('block-item-Input-users-form-')).toBeVisible(); await page.getByRole('button', { name: 'OK', exact: true }).click(); await expect(page.getByLabel('block-item-Input-users-Block')).not.toBeVisible(); }); diff --git a/packages/core/client/src/schema-component/antd/variable/Input.tsx b/packages/core/client/src/schema-component/antd/variable/Input.tsx index 818290add2..3b3c9d35aa 100644 --- a/packages/core/client/src/schema-component/antd/variable/Input.tsx +++ b/packages/core/client/src/schema-component/antd/variable/Input.tsx @@ -7,7 +7,6 @@ import useAntdInputStyle from 'antd/es/input/style'; import type { DefaultOptionType } from 'antd/lib/cascader'; import classNames from 'classnames'; import dayjs from 'dayjs'; -import { cloneDeep } from 'lodash'; import React, { useCallback, useEffect, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import { useCompile } from '../../hooks'; @@ -151,7 +150,7 @@ export function Input(props) { const { t } = useTranslation(); const form = useForm(); const [options, setOptions] = React.useState([]); - const [variableText, setVariableText] = React.useState(''); + const [variableText, setVariableText] = React.useState([]); const parsed = useMemo(() => parseValue(value), [value]); const isConstant = typeof parsed === 'string'; @@ -189,8 +188,12 @@ export function Input(props) { }, [type, useTypedConstant]); useEffect(() => { - setOptions([compile(constantOption), ...(scope ? cloneDeep(scope) : [])]); - }, [scope]); + const options = [compile(constantOption), ...(scope ? [...scope] : [])].filter((item) => { + return !item.deprecated || variable?.[0] === item[names.value]; + }); + + setOptions(options); + }, [scope, variable]); const loadData = async (selectedOptions: DefaultOptionType[]) => { const option = selectedOptions[selectedOptions.length - 1]; @@ -251,7 +254,7 @@ export function Input(props) { } } setOptions([...options]); - setVariableText(labels.join(' / ')); + setVariableText([...labels]); }; run(); @@ -296,6 +299,7 @@ export function Input(props) {
e.preventDefault()} onKeyDown={(e) => { if (e.key !== 'Backspace') { @@ -309,7 +313,14 @@ export function Input(props) { suppressContentEditableWarning > - {variableText} + {variableText.map((item, index) => { + return ( + <> + {index ? ' / ' : ''} + {item} + + ); + })}
{!disabled ? ( diff --git a/packages/core/client/src/schema-component/antd/variable/TextArea.tsx b/packages/core/client/src/schema-component/antd/variable/TextArea.tsx index 4b17afbf20..0e90d593b0 100644 --- a/packages/core/client/src/schema-component/antd/variable/TextArea.tsx +++ b/packages/core/client/src/schema-component/antd/variable/TextArea.tsx @@ -1,12 +1,13 @@ import { css, cx } from '@emotion/css'; import { useForm } from '@formily/react'; -import { Input, Space } from 'antd'; -import { cloneDeep } from 'lodash'; +import { Space } from 'antd'; import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'; +import { renderToString } from 'react-dom/server'; import sanitizeHTML from 'sanitize-html'; import { error } from '@nocobase/utils/client'; +import { isReactElement } from '@formily/shared'; import { EllipsisWithTooltip } from '../..'; import { VariableSelect } from './VariableSelect'; import { useStyles } from './style'; @@ -114,7 +115,17 @@ function createOptionsValueLabelMap(options: any[]) { } function createVariableTagHTML(variable, keyLabelMap) { - const labels = keyLabelMap.get(variable); + let labels = keyLabelMap.get(variable); + + if (labels) { + labels = labels.map((label) => { + if (isReactElement(label)) { + return renderToString(label); + } + return label; + }); + } + return `${ labels ? labels.join(' / ') : '...' }`; @@ -428,8 +439,12 @@ export function TextArea(props) { ); } -async function preloadOptions(scope, value) { - const options = cloneDeep(scope ?? []); +async function preloadOptions(scope, value: string) { + let options = [...(scope ?? [])]; + + options = options.filter((item) => { + return !item.deprecated || value?.includes(item.value); + }); // 重置正则的匹配位置 VARIABLE_RE.lastIndex = 0; diff --git a/packages/core/client/src/schema-settings/SchemaSettings.tsx b/packages/core/client/src/schema-settings/SchemaSettings.tsx index f5429074d2..8c0179d008 100644 --- a/packages/core/client/src/schema-settings/SchemaSettings.tsx +++ b/packages/core/client/src/schema-settings/SchemaSettings.tsx @@ -68,8 +68,10 @@ import { useSortFields, } from '..'; import { + BlockContext, BlockRequestContext_deprecated, FormBlockContext, + useBlockContext, useFormBlockContext, useFormBlockType, useTableBlockContext, @@ -975,6 +977,7 @@ export const SchemaSettingsModalItem: FC = (props) const record = useCollectionRecord(); const { association } = useDataBlockProps() || {}; const formCtx = useFormBlockContext(); + const blockOptions = useBlockContext(); // 解决变量`当前对象`值在弹窗中丢失的问题 const { formValue: subFormValue, collection: subFormCollection } = useSubFormValue(); @@ -996,58 +999,60 @@ export const SchemaSettingsModalItem: FC = (props) { title: schema.title || title, width }, () => { return ( - - - - - - - - - - - 576px - @media (min-width: 576px) { - min-width: 520px; - } + + + + + + + + + + + + 576px + @media (min-width: 576px) { + min-width: 520px; + } - // screen <= 576px - @media (max-width: 576px) { - min-width: 320px; - } - `} - > - - - - - - - - - - - - - - - - + // screen <= 576px + @media (max-width: 576px) { + min-width: 320px; + } + `} + > + + + + + + + + + + + + + + + + + ); }, theme, diff --git a/packages/core/client/src/schema-settings/VariableInput/VariableInput.tsx b/packages/core/client/src/schema-settings/VariableInput/VariableInput.tsx index 647eb16554..0ad70b8176 100644 --- a/packages/core/client/src/schema-settings/VariableInput/VariableInput.tsx +++ b/packages/core/client/src/schema-settings/VariableInput/VariableInput.tsx @@ -248,7 +248,7 @@ export function useCompatOldVariables(props: { return variables; } - variables = _.cloneDeep(variables); + variables = [...variables]; const systemVariable: Option = { value: '$system', diff --git a/packages/core/client/src/schema-settings/VariableInput/hooks/useBaseVariable.tsx b/packages/core/client/src/schema-settings/VariableInput/hooks/useBaseVariable.tsx index 937a399f28..b920015de4 100644 --- a/packages/core/client/src/schema-settings/VariableInput/hooks/useBaseVariable.tsx +++ b/packages/core/client/src/schema-settings/VariableInput/hooks/useBaseVariable.tsx @@ -1,4 +1,5 @@ import { ISchema, Schema } from '@formily/json-schema'; +import { Tooltip } from 'antd'; import React, { useContext, useMemo } from 'react'; import { CollectionFieldOptions_deprecated, useCollectionManager_deprecated } from '../../../collection-manager'; import { useCompile, useGetFilterOptions } from '../../../schema-component'; @@ -29,6 +30,10 @@ interface GetOptionsParams { compile: (value: string) => any; isDisabled?: (params: IsDisabledParams) => boolean; getCollectionField?: (name: string) => CollectionFieldOptions_deprecated; + /** + * 如果为 true 则表示该变量已被弃用 + */ + deprecated?: boolean; } interface BaseProps { @@ -60,6 +65,11 @@ interface BaseProps { */ returnFields?(fields: FieldOption[], option: Option): FieldOption[]; dataSource?: string; + /** + * 如果为 true 则表示该变量已被弃用 + */ + deprecated?: boolean; + tooltip?: string; } interface BaseVariableProviderProps { @@ -89,6 +99,7 @@ const getChildren = ( isDisabled, targetFieldSchema, getCollectionField, + deprecated, }: GetOptionsParams, ): Option[] => { const result = options @@ -98,9 +109,11 @@ const getChildren = ( key: option.name, value: option.name, label: compile(option.title), - disabled: noDisabled - ? false - : isDisabled({ option, collectionField, uiSchema, targetFieldSchema, getCollectionField }), + disabled: + deprecated || + (noDisabled + ? false + : isDisabled({ option, collectionField, uiSchema, targetFieldSchema, getCollectionField })), isLeaf: true, depth, }; @@ -117,9 +130,11 @@ const getChildren = ( isLeaf: false, field: option, depth, - disabled: noDisabled - ? false - : isDisabled({ option, collectionField, uiSchema, targetFieldSchema, getCollectionField }), + disabled: + deprecated || + (noDisabled + ? false + : isDisabled({ option, collectionField, uiSchema, targetFieldSchema, getCollectionField })), loadChildren, }; }) @@ -141,6 +156,8 @@ export const useBaseVariable = ({ noDisabled = true, dataSource, returnFields = (fields) => fields, + deprecated, + tooltip, }: BaseProps) => { const compile = useCompile(); const getFilterOptions = useGetFilterOptions(); @@ -167,6 +184,7 @@ export const useBaseVariable = ({ compile, isDisabled: isDisabled || isDisabledDefault, getCollectionField, + deprecated, }) || [] ) // 将叶子节点排列在上面,方便用户选择 @@ -206,7 +224,25 @@ export const useBaseVariable = ({ const result = useMemo(() => { return { - label: title, + label: tooltip ? ( + + + {title} + + + ) : ( + title + ), value: name, key: name, isLeaf: noChildren, @@ -216,6 +252,8 @@ export const useBaseVariable = ({ depth: 0, loadChildren, children: [], + disabled: !!deprecated, + deprecated, } as Option; }, [uiSchema?.['x-component']]); diff --git a/packages/core/client/src/schema-settings/VariableInput/hooks/useRecordVariable.ts b/packages/core/client/src/schema-settings/VariableInput/hooks/useRecordVariable.ts index 4192cc62cd..9678bddd1b 100644 --- a/packages/core/client/src/schema-settings/VariableInput/hooks/useRecordVariable.ts +++ b/packages/core/client/src/schema-settings/VariableInput/hooks/useRecordVariable.ts @@ -1,6 +1,7 @@ import { Schema } from '@formily/json-schema'; import _ from 'lodash'; import { useTranslation } from 'react-i18next'; +import { useBlockContext } from '../../../block-provider/BlockProvider'; import { useFormBlockContext } from '../../../block-provider/FormBlockProvider'; import { CollectionFieldOptions_deprecated } from '../../../collection-manager'; import { useCollection, useCollectionRecordData } from '../../../data-source'; @@ -46,6 +47,7 @@ export const useRecordVariable = (props: Props) => { */ export const useCurrentRecordVariable = (props: Props = {}) => { const { t } = useTranslation(); + const { name: blockType } = useBlockContext() || {}; const collection = useCollection(); const recordData = useCollectionRecordData(); const { formRecord, collectionName } = useFormBlockContext(); @@ -58,6 +60,8 @@ export const useCurrentRecordVariable = (props: Props = {}) => { collectionName: realCollectionName, noDisabled: props.noDisabled, targetFieldSchema: props.targetFieldSchema, + deprecated: blockType === 'form', + tooltip: blockType === 'form' ? t('This variable has been deprecated and can be replaced with "Current form"') : '', }); return { diff --git a/packages/core/client/src/schema-settings/VariableInput/type.ts b/packages/core/client/src/schema-settings/VariableInput/type.ts index 77e9ad145c..4dce386d2c 100644 --- a/packages/core/client/src/schema-settings/VariableInput/type.ts +++ b/packages/core/client/src/schema-settings/VariableInput/type.ts @@ -14,6 +14,7 @@ export interface Option extends DefaultOptionType { loadChildren?(option: Option): Promise; field?: FieldOption; depth?: number; + deprecated?: boolean; } export interface FieldOption { diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/richText/schemaSettings.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/richText/schemaSettings.test.ts index d4293ce270..d731c1a6cf 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/richText/schemaSettings.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/richText/schemaSettings.test.ts @@ -55,7 +55,7 @@ test.describe('form item & create form', () => { }, supportVariables: ['Constant', 'Current user', 'Date variables', 'Current form'], inputConstantValue: async () => { - await page.getByLabel('block-item-CollectionField-general-general.richText').locator('.ql-editor').click(); + await page.getByLabel('block-item-VariableInput-').locator('.ql-editor').click(); await page.keyboard.type('test rich text'); }, expectConstantValue: async () => { diff --git a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/singleLineText/schemaSettings.test.ts b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/singleLineText/schemaSettings.test.ts index 6a10e6b985..41b27b7570 100644 --- a/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/singleLineText/schemaSettings.test.ts +++ b/packages/plugins/@nocobase/plugin-collection-manager/src/client/__e2e__/fields/singleLineText/schemaSettings.test.ts @@ -303,8 +303,8 @@ test.describe('table column & table', () => { // 显示出原字段名称 await expect(page.getByRole('dialog').getByText('Original field title: singleLineText')).toBeVisible(); // 输入新字段名称 - await page.getByLabel('block-item-Input-general-column title').getByRole('textbox').click(); - await page.getByLabel('block-item-Input-general-column title').getByRole('textbox').fill('new column title'); + await page.getByLabel('block-item-Input-general-').getByRole('textbox').click(); + await page.getByLabel('block-item-Input-general-').getByRole('textbox').fill('new column title'); await page.getByRole('button', { name: 'OK', exact: true }).click(); // 新名称应该显示出来 @@ -415,7 +415,7 @@ test.describe('table column & sub-table in edit form', () => { 'Current role', 'Current form', 'Current object', - 'Current record', + // 'Current record', ], variableValue: ['Current user', 'Nickname'], expectVariableValue: async () => {