feat(variable): add a new variable named 'Parent popup record' (#4748)

* refactor: extract CurrentPopupRecordProvider component

* refactor: rename

* feat(variable): add a new variable named 'Parent popup record'

* chore: add translation

* fix: fix known issues

* test: add e2e tests
This commit is contained in:
Zeke Zhang 2024-06-26 08:59:01 +08:00 committed by GitHub
parent 8a971dcbbb
commit 99a0fcae1c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
55 changed files with 1062 additions and 229 deletions

View File

@ -70,4 +70,4 @@ export * from './modules/blocks/data-blocks/table-selector';
export * from './modules/blocks/index';
export * from './modules/blocks/useParentRecordCommon';
export { DeclareVariable } from './modules/variable/DeclareVariable';
export { VariablePopupRecordProvider } from './modules/variable/variablesProvider/VariablePopupRecordProvider';

View File

@ -631,6 +631,7 @@
"Current collection": "Current collection",
"Other collections": "Other collections",
"Current popup record": "Current popup record",
"Parent popup record": "Parent popup record",
"Associated records": "Associated records",
"Parent record": "Parent record",
"Current time": "Current time",

View File

@ -620,6 +620,7 @@
"Current collection": "Colección actual",
"Other collections": "Otras colecciones",
"Current popup record": "Registro actual del popup",
"Parent popup record": "Registro padre del popup",
"Associated records": "Registros asociados",
"Parent record": "Registro padre",
"Current time": "Hora actual",

View File

@ -617,6 +617,7 @@
"Current collection": "Collection actuelle",
"Other collections": "Autres collections",
"Current popup record": "Enregistrement popup actuel",
"Parent popup record": "Enregistrement popup parent",
"Associated records": "Enregistrements associés",
"Parent record": "Enregistrement parent",
"Current time": "Heure actuelle",

View File

@ -520,6 +520,7 @@
"Current collection": "現在のコレクション",
"Other collections": "他のコレクション",
"Current popup record": "現在のポップアップレコード",
"Parent popup record": "親ポップアップレコード",
"Associated records": "関連付けられたレコード",
"Popup close method": "ポップアップを閉じる方法",
"Automatic close": "自動で閉じる",

View File

@ -645,6 +645,7 @@
"Current collection": "현재 데이터 테이블",
"Other collections": "기타 데이터 테이블",
"Current popup record": "현재 팝업 레코드",
"Parent popup record": "상위 팝업 레코드",
"Associated records": "관련 레코드",
"Parent record": "상위 레코드",
"Current time": "현재 시간",

View File

@ -737,5 +737,7 @@
"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",
"The value of this variable is derived from the query string of the page URL. This variable can only be used normally when the page has a query string.": "O valor desta variável é derivado da string de consulta da URL da página. Esta variável só pode ser usada normalmente quando a página tem uma string de consulta.",
"URL search params": "Parâmetros de pesquisa de URL",
"Expand All": "Expandir tudo"
"Expand All": "Expandir tudo",
"Parent popup record": "Registro pop-up pai",
"Current popup record": "Registro pop-up atual"
}

View File

@ -455,6 +455,7 @@
"Current collection": "Текущая коллекция",
"Other collections": "Другие коллекции",
"Current popup record": "Текущая запись всплывающего окна",
"Parent popup record": "Родительская запись всплывающего окна",
"Associated records": "Связанные записи",
"Parent record": "Родительская запись",
"Popup close method": "Метод закрытия всплывающего окна",

View File

@ -455,6 +455,7 @@
"Current collection": "Seçili koleksiyon",
"Other collections": "Diğer koleksiyonlar",
"Current popup record": "Açılır pencere kaydı",
"Parent popup record": "Üst açılır pencere kaydı",
"Associated records": "İlişkili kayıtlar",
"Parent record": "Üst kayıt",
"Popup close method": "Açılır pencere kapatma metodu",

View File

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

View File

@ -649,6 +649,7 @@
"Current collection": "当前数据表",
"Other collections": "其他数据表",
"Current popup record": "当前弹窗记录",
"Parent popup record": "上级弹窗记录",
"Associated records": "关联记录",
"Parent record": "上级记录",
"Current time": "当前时间",

View File

@ -645,6 +645,7 @@
"Current collection": "當前資料表",
"Other collections": "其他資料表",
"Current popup record": "當前彈窗記錄",
"Parent popup record": "上級彈窗記錄",
"Associated records": "關聯記錄",
"Parent record": "上級記錄",
"Current time": "當前時間",

View File

@ -17,7 +17,7 @@ import {
test,
} from '@nocobase/test/e2e';
import { oneEmptyTableWithUsers } from '../../../details-multi/__e2e__/templatesOfBug';
import { T2174, T3871, oneFormAndOneTableWithUsers } from './templatesOfBug';
import { T2174, T3871, oneFormAndOneTableWithUsers, oneTableWithNestPopups } from './templatesOfBug';
test.describe('set default value', () => {
test('basic fields', async ({ page, mockPage }) => {
@ -362,6 +362,111 @@ test.describe('set default value', () => {
.getByRole('button', { name: 'Super Admin' }),
).toBeVisible();
});
test('Parent popup record', async ({ page, mockPage }) => {
await mockPage(oneTableWithNestPopups).goto();
// 1. 表单字段默认值中使用 `Parent popup record`
await page.getByLabel('action-Action.Link-View').click();
await page.getByLabel('action-Action.Link-View in popup').click();
await page.getByLabel('schema-initializer-Grid-popup').nth(1).hover();
await page.getByRole('menuitem', { name: 'form Form (Add new) right' }).hover();
await page.getByRole('menuitem', { name: 'Other records right' }).hover();
await page.getByRole('menuitem', { name: 'Users' }).click();
await page.mouse.move(300, 0);
await page.getByLabel('schema-initializer-Grid-form:').hover();
await page.getByRole('menuitem', { name: 'Nickname' }).click();
await page.getByLabel('block-item-CollectionField-').hover();
await page.getByLabel('designer-schema-settings-CollectionField-fieldSettings:FormItem-users-users.').hover();
await page.getByRole('menuitem', { name: 'Set default value' }).click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Parent popup record right' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Nickname' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByLabel('block-item-CollectionField-').getByRole('textbox')).toHaveValue('Super Admin');
// 2. 表单联动规则中使用 `Parent popup record`
// 创建 Username 字段
await page.getByLabel('schema-initializer-Grid-form:').hover();
await page.getByRole('menuitem', { name: 'Username' }).click();
// 设置联动规则
await page.getByLabel('block-item-CardItem-users-form').hover();
await page.getByLabel('designer-schema-settings-CardItem-blockSettings:createForm-users').hover();
await page.getByRole('menuitem', { name: 'Linkage rules' }).click();
await page.mouse.move(300, 0);
await page.getByRole('button', { name: 'plus Add linkage rule' }).click();
await page.getByText('Add property').click();
await page.getByTestId('select-linkage-property-field').click();
await page.getByTitle('Username').click();
await page.getByTestId('select-linkage-action-field').click();
await page.getByRole('option', { name: 'Value', exact: true }).click();
await page.getByTestId('select-linkage-value-type').click();
await page.getByTitle('Expression').click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Parent popup record right' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Username' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
// 需正确显示变量的值
await expect(
page.getByLabel('block-item-CollectionField-users-form-users.username-Username').getByRole('textbox'),
).toHaveValue('nocobase');
// 3. Table 数据选择器中使用 `Parent popup record`
// 创建 Table 区块
await page.getByLabel('schema-initializer-Grid-popup').nth(1).hover();
await page.getByRole('menuitem', { name: 'table Table right' }).hover();
await page.getByRole('menuitem', { name: 'Other records right' }).hover();
await page.getByRole('menuitem', { name: 'Users' }).click();
await page.mouse.move(300, 0);
// 显示 Nickname 字段
await page
.getByTestId('drawer-Action.Container-users-View record')
.getByLabel('schema-initializer-TableV2-')
.nth(1)
.hover();
await page.getByRole('menuitem', { name: 'Nickname' }).click();
await page.mouse.move(300, 0);
// 设置数据范围(使用 `Parent popup record` 变量)
await page
.getByTestId('drawer-Action.Container-users-View record')
.getByLabel('block-item-CardItem-users-table')
.nth(1)
.hover();
await page
.getByTestId('drawer-Action.Container-users-View record')
.getByLabel('designer-schema-settings-CardItem-blockSettings:table-users')
.nth(1)
.hover();
await page.getByRole('menuitem', { name: 'Set the data scope' }).click();
await page.getByText('Add condition', { exact: true }).click();
await page.getByTestId('select-filter-field').click();
await page.getByRole('menuitemcheckbox', { name: 'Nickname' }).click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Parent popup record right' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Nickname' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
// 数据需显示正确
await expect(
page
.getByTestId('drawer-Action.Container-users-View record')
.getByLabel('block-item-CardItem-users-table')
.getByRole('button', { name: 'Super Admin' }),
).toBeVisible();
// 4. 退出二级弹窗,在第一级弹窗中点击 Add new 按钮
await page.getByLabel('drawer-Action.Container-users').nth(2).click();
await page.getByLabel('action-Action-Add new-create-').click();
// 5. 在新增表单中使用 `Parent popup record`
await page.getByLabel('block-item-CollectionField-').hover();
await page.getByLabel('designer-schema-settings-CollectionField-fieldSettings:FormItem-users-users.').hover();
await page.getByRole('menuitem', { name: 'Set default value' }).click();
await page.getByLabel('variable-button').click();
await page.getByRole('menuitemcheckbox', { name: 'Parent popup record right' }).click();
await page.getByRole('menuitemcheckbox', { name: 'Nickname' }).click();
await page.getByRole('button', { name: 'OK', exact: true }).click();
await expect(page.getByLabel('block-item-CollectionField-').getByRole('textbox')).toHaveValue('Super Admin');
});
});
test.describe('actions schema settings', () => {

View File

@ -10150,3 +10150,728 @@ export const T4596 = {
'x-async': true,
},
};
export const oneTableWithNestPopups = {
pageSchema: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Page',
'x-index': 1,
properties: {
zvj8cbqvt05: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'page:addBlock',
'x-index': 1,
properties: {
j0zzcf3k2vc: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '0.21.0-alpha.6',
'x-index': 1,
properties: {
pn0pgjxjlz2: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '0.21.0-alpha.6',
'x-index': 1,
properties: {
o9zor60xpvi: {
_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.6',
'x-index': 1,
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.6',
'x-index': 1,
'x-uid': 'w9pvdbikqg3',
'x-async': false,
},
'3rr559rnt6k': {
_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.6',
'x-index': 2,
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.6',
'x-index': 1,
properties: {
cf7dj1iffh3: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-decorator': 'DndContext',
'x-component': 'Space',
'x-component-props': {
split: '|',
},
'x-app-version': '0.21.0-alpha.6',
'x-index': 1,
properties: {
oealnj6s2rw: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: 'View record',
'x-action': 'view',
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:view',
'x-component': 'Action.Link',
'x-component-props': {
openMode: 'drawer',
danger: false,
},
'x-decorator': 'ACLActionProvider',
'x-designer-props': {
linkageAction: true,
},
'x-index': 1,
properties: {
drawer: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{ t("View record") }}',
'x-component': 'Action.Container',
'x-component-props': {
className: 'nb-action-popup',
},
'x-index': 1,
properties: {
tabs: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Tabs',
'x-component-props': {},
'x-initializer': 'popup:addTab',
'x-index': 1,
properties: {
tab1: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{t("Details")}}',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
'x-index': 1,
properties: {
grid: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer': 'popup:common:addBlock',
'x-index': 1,
properties: {
o3az953k64s: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version': '1.2.7-alpha',
properties: {
'09c7dcvslhi': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Col',
'x-app-version': '1.2.7-alpha',
properties: {
xv84k1hns7x: {
_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': '1.2.7-alpha',
properties: {
actions: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-initializer': 'table:configureActions',
'x-component': 'ActionBar',
'x-component-props': {
style: {
marginBottom: 'var(--nb-spacing)',
},
},
'x-app-version': '1.2.7-alpha',
properties: {
h6qhcp7es4z: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-action': 'create',
'x-acl-action': 'create',
title: "{{t('Add new')}}",
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:addNew',
'x-component': 'Action',
'x-decorator': 'ACLActionProvider',
'x-component-props': {
openMode: 'drawer',
type: 'primary',
component: 'CreateRecordAction',
icon: 'PlusOutlined',
},
'x-align': 'right',
'x-acl-action-props': {
skipScopeCheck: true,
},
'x-app-version': '1.2.7-alpha',
properties: {
drawer: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{ t("Add record") }}',
'x-component': 'Action.Container',
'x-component-props': {
className: 'nb-action-popup',
},
'x-app-version': '1.2.7-alpha',
properties: {
tabs: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Tabs',
'x-component-props': {},
'x-initializer': 'popup:addTab',
'x-initializer-props': {
gridInitializer:
'popup:addNew:addBlock',
},
'x-app-version': '1.2.7-alpha',
properties: {
tab1: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{t("Add new")}}',
'x-component': 'Tabs.TabPane',
'x-designer': 'Tabs.Designer',
'x-component-props': {},
'x-app-version': '1.2.7-alpha',
properties: {
grid: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid',
'x-initializer':
'popup:addNew:addBlock',
'x-app-version': '1.2.7-alpha',
properties: {
'84oe9zbk4i3': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-component': 'Grid.Row',
'x-app-version':
'1.2.7-alpha',
properties: {
g1ye1zczjy0: {
_isJSONSchemaObject:
true,
version: '2.0',
type: 'void',
'x-component':
'Grid.Col',
'x-app-version':
'1.2.7-alpha',
properties: {
'9boifjys3jn': {
_isJSONSchemaObject:
true,
version: '2.0',
type: 'void',
'x-acl-action-props':
{
skipScopeCheck:
true,
},
'x-acl-action':
'users:create',
'x-decorator':
'FormBlockProvider',
'x-use-decorator-props':
'useCreateFormBlockDecoratorProps',
'x-decorator-props':
{
dataSource:
'main',
collection:
'users',
},
'x-toolbar':
'BlockSchemaToolbar',
'x-settings':
'blockSettings:createForm',
'x-component':
'CardItem',
'x-app-version':
'1.2.7-alpha',
properties: {
rmsurarncfw: {
_isJSONSchemaObject:
true,
version: '2.0',
type: 'void',
'x-component':
'FormV2',
'x-use-component-props':
'useCreateFormBlockProps',
'x-app-version':
'1.2.7-alpha',
properties: {
grid: {
_isJSONSchemaObject:
true,
version:
'2.0',
type: 'void',
'x-component':
'Grid',
'x-initializer':
'form:configureFields',
'x-app-version':
'1.2.7-alpha',
properties:
{
akmulvncf99:
{
_isJSONSchemaObject:
true,
version:
'2.0',
type: 'void',
'x-component':
'Grid.Row',
'x-app-version':
'1.2.7-alpha',
properties:
{
nmmv2oujq4y:
{
_isJSONSchemaObject:
true,
version:
'2.0',
type: 'void',
'x-component':
'Grid.Col',
'x-app-version':
'1.2.7-alpha',
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':
'1.2.7-alpha',
'x-uid':
'owh5563gdur',
'x-async':
false,
'x-index': 1,
},
},
'x-uid':
'bneikj8s65s',
'x-async':
false,
'x-index': 1,
},
},
'x-uid':
'6dq0qny7x7y',
'x-async':
false,
'x-index': 1,
},
},
'x-uid':
'c6fz7t7skty',
'x-async':
false,
'x-index': 1,
},
'6b7iqambrl7':
{
_isJSONSchemaObject:
true,
version:
'2.0',
type: 'void',
'x-initializer':
'createForm:configureActions',
'x-component':
'ActionBar',
'x-component-props':
{
layout:
'one-column',
style:
{
marginTop:
'var(--nb-spacing)',
},
},
'x-app-version':
'1.2.7-alpha',
'x-uid':
'iz5qh7pzfdl',
'x-async':
false,
'x-index': 2,
},
},
'x-uid':
'6e80ocej2vr',
'x-async':
false,
'x-index': 1,
},
},
'x-uid':
'nh98trp6j1i',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'q6q5sei1mky',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'xysmldkaxai',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'x0zp27tscd1',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'mv1hedy02o5',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'jip3zywfel2',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'cweynnfbl16',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'jt5ud7f96h6',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'j9sx8xma2r0',
'x-async': false,
'x-index': 1,
},
gjshpj169w3: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'array',
'x-initializer': 'table:configureColumns',
'x-component': 'TableV2',
'x-use-component-props': 'useTableBlockProps',
'x-component-props': {
rowKey: 'id',
rowSelection: {
type: 'checkbox',
},
},
'x-app-version': '1.2.7-alpha',
properties: {
actions: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{ t("Actions") }}',
'x-action-column': 'actions',
'x-decorator': 'TableV2.Column.ActionBar',
'x-component': 'TableV2.Column',
'x-toolbar': 'TableColumnSchemaToolbar',
'x-initializer': 'table:configureItemActions',
'x-settings': 'fieldSettings:TableColumn',
'x-toolbar-props': {
initializer: 'table:configureItemActions',
},
'x-app-version': '1.2.7-alpha',
properties: {
'6s1te9svg45': {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
'x-decorator': 'DndContext',
'x-component': 'Space',
'x-component-props': {
split: '|',
},
'x-app-version': '1.2.7-alpha',
properties: {
v2uyliqmu3s: {
'x-uid': 'e2csion4yer',
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: 'View in popup',
'x-action': 'view',
'x-toolbar': 'ActionSchemaToolbar',
'x-settings': 'actionSettings:view',
'x-component': 'Action.Link',
'x-component-props': {
openMode: 'drawer',
iconColor: '#1677FF',
danger: false,
},
'x-decorator': 'ACLActionProvider',
'x-designer-props': {
linkageAction: true,
},
properties: {
drawer: {
_isJSONSchemaObject: true,
version: '2.0',
type: 'void',
title: '{{ t("View 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("Details")}}',
'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',
'x-uid': 'qjvstlh8c3g',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'ast4jmympse',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'qc6nkjh7up0',
'x-async': false,
'x-index': 1,
},
},
'x-uid': '33plknkxxgp',
'x-async': false,
'x-index': 1,
},
},
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'hx4i3ofxpax',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'yaowlbjo9nr',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'ezac62lon2k',
'x-async': false,
'x-index': 2,
},
},
'x-uid': 'wh2b478biqn',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'npfxqga5wq5',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 'w9rvitjqfoc',
'x-async': false,
'x-index': 1,
},
},
'x-uid': 't3bzhtqt5vv',
'x-async': false,
},
},
'x-uid': 'n4rxef48z1x',
'x-async': false,
},
},
'x-uid': '56g3vhrv95f',
'x-async': false,
},
},
'x-uid': '9qq5b6kk5n3',
'x-async': false,
},
},
'x-uid': 'ae3e37qq83w',
'x-async': false,
},
},
'x-uid': '92lehcparox',
'x-async': false,
},
},
'x-uid': 'jek9wwqyz9m',
'x-async': false,
},
},
'x-uid': 'qw71i20y4ue',
'x-async': false,
},
},
'x-uid': 'kark3jk4bcl',
'x-async': false,
},
},
'x-uid': 'l4t5ymt09we',
'x-async': false,
},
},
'x-uid': 'puem6lfk26i',
'x-async': false,
},
},
'x-uid': 's3u70jb1bmr',
'x-async': false,
},
},
'x-uid': 'faokuf0k8lx',
'x-async': true,
},
};

View File

@ -1,36 +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, { FC, createContext } from 'react';
import { Collection } from '../../data-source';
interface DeclareVariableProps {
/* 变量名称 */
name: string;
/** 变量值 */
value: any;
/** 显示给用户的名字 */
title?: string;
/** 变量对应的数据表信息 */
collection?: Collection;
}
export const DeclareVariableContext = createContext<DeclareVariableProps>(null);
/**
*
*/
export const DeclareVariable: FC<DeclareVariableProps> = (props) => {
const { name, value, title, collection } = props;
return (
<DeclareVariableContext.Provider value={{ name, value, title, collection }}>
{props.children}
</DeclareVariableContext.Provider>
);
};

View File

@ -1,62 +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 { renderHook } from '@nocobase/test/client';
import React from 'react';
import { Collection } from '../../../data-source';
import { DeclareVariable } from '../DeclareVariable';
import { useVariable } from '../useVariable';
describe('useVariable', () => {
it('should return the variable value, title, and collection when the variable name matches', () => {
const variableName = 'testVariable';
const value = 'testValue';
const title = 'Test Variable';
const collection: Collection = new Collection(
{
name: 'testCollection',
title: 'Test Collection',
},
null,
);
const wrapper = ({ children }: { children: React.ReactNode }) => (
<DeclareVariable name={variableName} value={value} title={title} collection={collection}>
{children}
</DeclareVariable>
);
const { result } = renderHook(() => useVariable(variableName), { wrapper });
expect(result.current).toEqual({ value, title, collection });
});
it('should return an empty object when the variable name does not match', () => {
const variableName = 'testVariable';
const value = 'testValue';
const title = 'Test Variable';
const collection = new Collection(
{
name: 'testCollection',
title: 'Test Collection',
},
null,
);
const wrapper = ({ children }: { children: React.ReactNode }) => (
<DeclareVariable name={variableName} value={value} title={title} collection={collection}>
{children}
</DeclareVariable>
);
const { result } = renderHook(() => useVariable('otherVariable'), { wrapper });
expect(result.current).toEqual({});
});
});

View File

@ -0,0 +1,21 @@
/**
* 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 { Collection } from '../../data-source/collection/Collection';
export interface DeclareVariableProps {
/* 变量名称 */
name: string;
/** 变量值 */
value: any;
/** 显示给用户的名字 */
title?: string;
/** 变量对应的数据表信息 */
collection?: Collection;
}

View File

@ -1,24 +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 { useContext } from 'react';
import { DeclareVariableContext } from './DeclareVariable';
/**
*
* @param variableName
* @returns
*/
export const useVariable = (variableName: string) => {
const { name, value, title, collection } = useContext(DeclareVariableContext) || {};
if (name === variableName) {
return { value, title, collection };
}
return {};
};

View File

@ -0,0 +1,62 @@
/**
* 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, { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { useCollectionRecordData } from '../../../data-source/collection-record/CollectionRecordProvider';
import { Collection } from '../../../data-source/collection/Collection';
import { useCollection } from '../../../data-source/collection/CollectionProvider';
import { DeclareVariableProps } from '../types';
const CurrentPopupRecordContext = React.createContext<DeclareVariableProps>(null);
const CurrentParentPopupRecordContext = React.createContext<DeclareVariableProps>(null);
export const VariablePopupRecordProvider: FC<{
recordData?: Record<string, any>;
collection?: Collection;
parent?: {
recordData?: Record<string, any>;
collection?: Collection;
};
}> = (props) => {
const { t } = useTranslation();
const recordData = useCollectionRecordData();
const collection = useCollection();
const parent = useCurrentPopupRecord();
return (
<CurrentParentPopupRecordContext.Provider
value={{
name: '$nParentPopupRecord',
title: t('Parent popup record'),
value: props.parent?.recordData || parent?.value,
collection: props.parent?.collection || parent?.collection,
}}
>
<CurrentPopupRecordContext.Provider
value={{
name: '$nPopupRecord',
title: t('Current popup record'),
value: props.recordData || recordData,
collection: props.collection || collection,
}}
>
{props.children}
</CurrentPopupRecordContext.Provider>
</CurrentParentPopupRecordContext.Provider>
);
};
export const useCurrentPopupRecord = () => {
return React.useContext(CurrentPopupRecordContext);
};
export const useParentPopupRecord = () => {
return React.useContext(CurrentParentPopupRecordContext);
};

View File

@ -13,20 +13,16 @@ import { App, Button } from 'antd';
import classnames from 'classnames';
import { default as lodash } from 'lodash';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { useTranslation } from 'react-i18next';
import { ErrorFallback, StablePopover, useActionContext } from '../..';
import { useDesignable } from '../../';
import { useACLActionParamsContext } from '../../../acl';
import {
useCollection,
useCollectionParentRecordData,
useCollectionRecordData,
useDataBlockRequest,
} from '../../../data-source';
import { useCollectionParentRecordData, useCollectionRecordData, useDataBlockRequest } from '../../../data-source';
import { withDynamicSchemaProps } from '../../../hoc/withDynamicSchemaProps';
import { Icon } from '../../../icon';
import { TreeRecordProvider } from '../../../modules/blocks/data-blocks/table/TreeRecordProvider';
import { DeclareVariable } from '../../../modules/variable/DeclareVariable';
import { VariablePopupRecordProvider } from '../../../modules/variable/variablesProvider/VariablePopupRecordProvider';
import { RecordProvider } from '../../../record-provider';
import { useLocalVariables, useVariables } from '../../../variables';
import { SortableItem } from '../../common';
@ -44,7 +40,6 @@ import { useA } from './hooks';
import { useGetAriaLabelOfAction } from './hooks/useGetAriaLabelOfAction';
import { ActionProps, ComposedAction } from './types';
import { linkageAction, setInitialActionState } from './utils';
import { ErrorBoundary } from 'react-error-boundary';
const handleError = (err) => console.log(err);
@ -85,7 +80,6 @@ export const Action: ComposedAction = withDynamicSchemaProps(
const form = useForm();
const recordData = useCollectionRecordData();
const parentRecordData = useCollectionParentRecordData();
const collection = useCollection();
const designerProps = fieldSchema['x-toolbar-props'] || fieldSchema['x-designer-props'];
const openMode = fieldSchema?.['x-component-props']?.['openMode'];
const openSize = fieldSchema?.['x-component-props']?.['openSize'];
@ -220,14 +214,7 @@ export const Action: ComposedAction = withDynamicSchemaProps(
>
{popover && <RecursionField basePath={field.address} onlyRenderProperties schema={fieldSchema} />}
{!popover && renderButton()}
<DeclareVariable
name="$nPopupRecord"
title={t('Current popup record')}
value={recordData}
collection={collection}
>
{!popover && props.children}
</DeclareVariable>
<VariablePopupRecordProvider>{!popover && props.children}</VariablePopupRecordProvider>
{element}
</ActionContextProvider>
);

View File

@ -15,7 +15,7 @@ import { useDesignable } from '../../';
import { BlockAssociationContext, WithoutTableFieldResource } from '../../../block-provider';
import { CollectionProvider_deprecated, useCollectionManager_deprecated } from '../../../collection-manager';
import { Collection } from '../../../data-source';
import { DeclareVariable } from '../../../modules/variable/DeclareVariable';
import { VariablePopupRecordProvider } from '../../../modules/variable/variablesProvider/VariablePopupRecordProvider';
import { RecordProvider, useRecord } from '../../../record-provider';
import { FormProvider } from '../../core';
import { useCompile } from '../../hooks';
@ -121,12 +121,7 @@ export const ReadPrettyInternalViewer: React.FC = observer(
return btnElement;
}
const renderWithoutTableFieldResourceProvider = () => (
<DeclareVariable
name="$nPopupRecord"
title={t('Current popup record')}
value={record}
collection={targetCollection as Collection}
>
<VariablePopupRecordProvider recordData={record} collection={targetCollection as Collection}>
<WithoutTableFieldResource.Provider value={true}>
<FormProvider>
<RecursionField
@ -139,7 +134,7 @@ export const ReadPrettyInternalViewer: React.FC = observer(
/>
</FormProvider>
</WithoutTableFieldResource.Provider>
</DeclareVariable>
</VariablePopupRecordProvider>
);
const renderRecordProvider = () => {

View File

@ -78,8 +78,11 @@ import { useFilterBlock } from '../filter-provider/FilterProvider';
import { FlagProvider } from '../flag-provider';
import { useGlobalTheme } from '../global-theme';
import { useCollectMenuItem, useCollectMenuItems, useMenuItem } from '../hooks/useMenuItem';
import { DeclareVariable } from '../modules/variable/DeclareVariable';
import { useVariable } from '../modules/variable/useVariable';
import {
VariablePopupRecordProvider,
useCurrentPopupRecord,
useParentPopupRecord,
} from '../modules/variable/variablesProvider/VariablePopupRecordProvider';
import { useRecord } from '../record-provider';
import { ActionContextProvider } from '../schema-component/antd/action/context';
import { SubFormProvider, useSubFormValue } from '../schema-component/antd/association-field/hooks';
@ -747,8 +750,9 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
// 解决变量`当前对象`值在弹窗中丢失的问题
const { formValue: subFormValue, collection: subFormCollection } = useSubFormValue();
// 解决变量`$nPopupRecord`值在弹窗中丢失的问题
const popupRecordVariable = useVariable('$nPopupRecord');
// 解决弹窗变量丢失的问题
const popupRecordVariable = useCurrentPopupRecord();
const parentPopupRecordVariable = useParentPopupRecord();
if (hidden) {
return null;
@ -765,11 +769,13 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
() => {
return (
<BlockContext.Provider value={blockOptions}>
<DeclareVariable
name="$nPopupRecord"
title={popupRecordVariable.title}
value={popupRecordVariable.value}
collection={popupRecordVariable.collection}
<VariablePopupRecordProvider
recordData={popupRecordVariable?.value}
collection={popupRecordVariable?.collection}
parent={{
recordData: parentPopupRecordVariable?.value,
collection: parentPopupRecordVariable?.collection,
}}
>
<CollectionRecordProvider record={noRecord ? null : record}>
<FormBlockContext.Provider value={formCtx}>
@ -818,7 +824,7 @@ export const SchemaSettingsModalItem: FC<SchemaSettingsModalItemProps> = (props)
</SubFormProvider>
</FormBlockContext.Provider>
</CollectionRecordProvider>
</DeclareVariable>
</VariablePopupRecordProvider>
</BlockContext.Provider>
);
},

View File

@ -0,0 +1,44 @@
/**
* 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 { useFlag } from '../../../flag-provider/hooks/useFlag';
import { useParentPopupRecord } from '../../../modules/variable/variablesProvider/VariablePopupRecordProvider';
import { useBaseVariable } from './useBaseVariable';
/**
* `Parent popup record`
* @param props
* @returns
*/
export const useParentPopupVariable = (props: any = {}) => {
const { value, title, collection } = useParentPopupRecord() || {};
const { isVariableParsedInOtherContext } = useFlag();
const settings = useBaseVariable({
collectionField: props.collectionField,
uiSchema: props.schema,
name: '$nParentPopupRecord',
title,
collectionName: collection?.name,
noDisabled: props.noDisabled,
targetFieldSchema: props.targetFieldSchema,
dataSource: collection?.dataSource,
});
return {
/** 变量配置 */
settings,
/** 变量值 */
parentPopupRecordCtx: value,
/** 用于判断是否需要显示配置项 */
shouldDisplayParentPopupRecord: !!value && !isVariableParsedInOtherContext,
/** 当前记录对应的 collection name */
collectionName: collection?.name,
dataSource: collection?.dataSource,
};
};

View File

@ -8,7 +8,7 @@
*/
import { useFlag } from '../../../flag-provider/hooks/useFlag';
import { useVariable } from '../../../modules/variable/useVariable';
import { useCurrentPopupRecord } from '../../../modules/variable/variablesProvider/VariablePopupRecordProvider';
import { useBaseVariable } from './useBaseVariable';
/**
@ -17,7 +17,7 @@ import { useBaseVariable } from './useBaseVariable';
* @returns
*/
export const usePopupVariable = (props: any = {}) => {
const { value, title, collection } = useVariable('$nPopupRecord');
const { value, title, collection } = useCurrentPopupRecord() || {};
const { isVariableParsedInOtherContext } = useFlag();
const settings = useBaseVariable({
collectionField: props.collectionField,

View File

@ -14,6 +14,7 @@ import { CollectionFieldOptions_deprecated } from '../../../collection-manager';
import { useDatetimeVariable } from './useDateVariable';
import { useCurrentFormVariable } from './useFormVariable';
import { useCurrentObjectVariable } from './useIterationVariable';
import { useParentPopupVariable } from './useParentPopupVariable';
import { useCurrentParentRecordVariable } from './useParentRecordVariable';
import { usePopupVariable } from './usePopupVariable';
import { useCurrentRecordVariable } from './useRecordVariable';
@ -96,6 +97,12 @@ export const useVariableOptions = ({
noDisabled,
targetFieldSchema,
});
const { settings: parentPopupRecordSettings, shouldDisplayParentPopupRecord } = useParentPopupVariable({
schema: uiSchema,
collectionField,
noDisabled,
targetFieldSchema,
});
const { currentParentRecordSettings, shouldDisplayCurrentParentRecord } = useCurrentParentRecordVariable({
schema: uiSchema,
collectionName: blockParentCollectionName,
@ -115,6 +122,7 @@ export const useVariableOptions = ({
shouldDisplayCurrentRecord && currentRecordSettings,
shouldDisplayCurrentParentRecord && currentParentRecordSettings,
shouldDisplayPopupRecord && popupRecordSettings,
shouldDisplayParentPopupRecord && parentPopupRecordSettings,
shouldDisplayURLSearchParams && urlSearchParamsSettings,
].filter(Boolean);
}, [

View File

@ -14,6 +14,7 @@ import { useBlockCollection } from '../../schema-settings/VariableInput/hooks/us
import { useDatetimeVariable } from '../../schema-settings/VariableInput/hooks/useDateVariable';
import { useCurrentFormVariable } from '../../schema-settings/VariableInput/hooks/useFormVariable';
import { useCurrentObjectVariable } from '../../schema-settings/VariableInput/hooks/useIterationVariable';
import { useParentPopupVariable } from '../../schema-settings/VariableInput/hooks/useParentPopupVariable';
import { useCurrentParentRecordVariable } from '../../schema-settings/VariableInput/hooks/useParentRecordVariable';
import { usePopupVariable } from '../../schema-settings/VariableInput/hooks/usePopupVariable';
import { useCurrentRecordVariable } from '../../schema-settings/VariableInput/hooks/useRecordVariable';
@ -37,6 +38,11 @@ const useLocalVariables = (props?: Props) => {
collectionName: collectionNameOfPopupRecord,
dataSource: popupDataSource,
} = usePopupVariable();
const {
parentPopupRecordCtx,
collectionName: collectionNameOfParentPopupRecord,
dataSource: parentPopupDataSource,
} = useParentPopupVariable();
const { datetimeCtx } = useDatetimeVariable();
const { currentFormCtx } = useCurrentFormVariable({ form: props?.currentForm });
const { name: currentCollectionName } = useCollection_deprecated();
@ -93,6 +99,12 @@ const useLocalVariables = (props?: Props) => {
collectionName: collectionNameOfPopupRecord,
dataSource: popupDataSource,
},
{
name: '$nParentPopupRecord',
ctx: parentPopupRecordCtx,
collectionName: collectionNameOfParentPopupRecord,
dataSource: parentPopupDataSource,
},
{
name: '$nForm',
ctx: currentFormCtx,

View File

@ -11,13 +11,13 @@ import { LeftOutlined, RightOutlined } from '@ant-design/icons';
import { RecursionField, Schema, observer, useFieldSchema } from '@formily/react';
import {
ActionContextProvider,
DeclareVariable,
RecordProvider,
VariablePopupRecordProvider,
getLabelFormatValue,
useCollection,
useCollectionParentRecordData,
useProps,
withDynamicSchemaProps,
getLabelFormatValue,
} from '@nocobase/client';
import { parseExpression } from 'cron-parser';
import type { Dayjs } from 'dayjs';
@ -186,14 +186,9 @@ const CalendarRecordViewer = (props) => {
<DeleteEventContext.Provider value={{ close }}>
<ActionContextProvider value={{ visible, setVisible }}>
<RecordProvider record={record} parent={parentRecordData}>
<DeclareVariable
name="$nPopupRecord"
title={t('Current popup record')}
value={record}
collection={collection}
>
<VariablePopupRecordProvider recordData={record} collection={collection}>
<RecursionField schema={eventSchema} name={eventSchema.name} />
</DeclareVariable>
</VariablePopupRecordProvider>
</RecordProvider>
</ActionContextProvider>
</DeleteEventContext.Provider>

View File

@ -65,7 +65,7 @@ test.describe('form item & create form', () => {
.hover();
},
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
// 默认应该是没有被选中的,点击后应该被选中
await page.getByLabel('block-item-VariableInput-').getByRole('checkbox').click();

View File

@ -67,7 +67,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'checkboxGroup'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').getByLabel('Option1').click();
},

View File

@ -67,7 +67,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'chinaRegion'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').click();
await page.getByRole('menuitemcheckbox', { name: '北京市' }).click();

View File

@ -65,7 +65,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'datetime'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').getByPlaceholder('Select date').click();
await page.getByText('Today').click();

View File

@ -63,7 +63,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'email'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
constantValue: 'test@nocobase.com',
variableValue: ['Current user', 'Email'],
expectConstantValue: () =>

View File

@ -63,7 +63,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'icon'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').getByRole('button', { name: 'Select icon' }).click();
await page.getByLabel('account-book').locator('svg').click();

View File

@ -64,7 +64,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'integer'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
variableValue: ['Current user', 'ID'], // 值为 1
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').getByRole('spinbutton').click();

View File

@ -66,7 +66,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'longText'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
constantValue: 'test long text',
variableValue: ['Current user', 'Email'], // 值为 admin@nocobase.com
expectConstantValue: async () => {

View File

@ -77,7 +77,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'manyToMany'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').getByTestId('select-object-multiple').click();
await page.getByRole('option', { name: String(recordsOfUser[0].id), exact: true }).click();

View File

@ -76,7 +76,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'manyToOne'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page
.getByLabel('block-item-VariableInput-')

View File

@ -63,7 +63,7 @@ test.describe('form item & create form', () => {
.hover();
},
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
constantValue: 'test markdown',
expectConstantValue: async () => {
await expect(

View File

@ -67,7 +67,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'multipleSelect'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').getByTestId('select-multiple').click();
await page.getByRole('option', { name: 'Option1' }).click();

View File

@ -64,7 +64,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'number'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').getByRole('spinbutton').click();
await page.getByLabel('block-item-VariableInput-').getByRole('spinbutton').fill('11.22');

View File

@ -64,7 +64,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'password'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
constantValue: 'test112233password',
variableValue: ['Current user', 'Email'], // 值为 admin@nocobase.com
expectConstantValue: async () => {

View File

@ -64,7 +64,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'percent'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').getByRole('spinbutton').click();
await page.getByLabel('block-item-VariableInput-').getByRole('spinbutton').fill('11.22');

View File

@ -63,7 +63,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'phone'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
constantValue: '17777777777',
variableValue: ['Current user', 'ID'], // 值为 1
expectConstantValue: async () => {

View File

@ -67,7 +67,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'radioGroup'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').getByLabel('Option2').click();
},

View File

@ -63,7 +63,7 @@ test.describe('form item & create form', () => {
.hover();
},
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').locator('.ql-editor').click();
await page.keyboard.type('test rich text');

View File

@ -50,6 +50,7 @@ test.describe('form item & sub form', () => {
'Current object',
'Current popup record',
],
unsupportedVariables: ['Parent popup record'],
variableValue: ['Current user', 'Nickname'],
expectVariableValue: async () => {
await page
@ -132,6 +133,7 @@ test.describe('table column & sub-table in edit form', () => {
'Current object',
'Current popup record',
],
unsupportedVariables: ['Parent popup record'],
variableValue: ['Current user', 'Nickname'],
expectVariableValue: async () => {
await page.getByRole('button', { name: 'Add new' }).click();

View File

@ -61,7 +61,7 @@ test.describe('form item & create form', () => {
.hover();
},
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
constantValue: 'test single line text',
variableValue: ['Current user', 'Email'], // 值为 admin@nocobase.com
expectConstantValue: async () => {

View File

@ -67,7 +67,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'singleSelect'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').click();
await page.getByRole('option', { name: 'Option1' }).click();

View File

@ -62,7 +62,7 @@ test.describe('form item & create form', () => {
.hover();
},
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
inputConstantValue: async () => {
await page.getByLabel('block-item-VariableInput-').getByPlaceholder('Select time').click();
await page.getByText('Now').click();

View File

@ -63,7 +63,7 @@ test.describe('form item & create form', () => {
.hover();
})(page, 'url'),
supportedVariables: ['Constant', 'Current user', 'Current role', 'Date variables', 'Current form'],
unsupportedVariables: ['Current popup record'],
unsupportedVariables: ['Current popup record', 'Parent popup record'],
constantValue: 'https://nocobase.com',
variableValue: ['Current user', 'Email'], // 值为 admin@nocobase.com
expectConstantValue: async () => {

View File

@ -39,5 +39,6 @@ test.describe('data scope in action permission', () => {
await expect(page.getByRole('menuitemcheckbox', { name: 'Current role' })).toBeVisible();
await expect(page.getByRole('menuitemcheckbox', { name: 'Current form' })).not.toBeVisible();
await expect(page.getByRole('menuitemcheckbox', { name: 'Current popup record' })).not.toBeVisible();
await expect(page.getByRole('menuitemcheckbox', { name: 'Parent popup record' })).not.toBeVisible();
});
});

View File

@ -11,20 +11,20 @@ import { css, cx } from '@emotion/css';
import { RecursionField, Schema, useFieldSchema } from '@formily/react';
import {
ActionContextProvider,
DeclareVariable,
RecordProvider,
VariablePopupRecordProvider,
useAPIClient,
useBlockRequestContext,
useCollection,
useCollectionParentRecordData,
useCurrentAppInfo,
useDesignable,
useProps,
useTableBlockContext,
useToken,
withDynamicSchemaProps,
useDesignable,
} from '@nocobase/client';
import { message, Spin } from 'antd';
import { Spin, message } from 'antd';
import { debounce } from 'lodash';
import React, { SyntheticEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
@ -68,14 +68,9 @@ const GanttRecordViewer = (props) => {
<DeleteEventContext.Provider value={{ close }}>
<ActionContextProvider value={{ visible, setVisible }}>
<RecordProvider record={record} parent={parentRecordData}>
<DeclareVariable
name="$nPopupRecord"
title={t('Current popup record')}
value={record}
collection={collection}
>
<VariablePopupRecordProvider recordData={record} collection={collection}>
<RecursionField schema={eventSchema} name={eventSchema.name} />
</DeclareVariable>
</VariablePopupRecordProvider>
</RecordProvider>
</ActionContextProvider>
</DeleteEventContext.Provider>

View File

@ -12,11 +12,11 @@ import { FormLayout } from '@formily/antd-v5';
import { observer, RecursionField, useFieldSchema } from '@formily/react';
import {
ActionContextProvider,
DeclareVariable,
DndContext,
RecordProvider,
useCollection,
useCollectionParentRecordData,
VariablePopupRecordProvider,
} from '@nocobase/client';
import { Card } from 'antd';
import React, { useCallback, useContext, useMemo, useState } from 'react';
@ -133,14 +133,9 @@ export const KanbanCard: any = observer(
{cardViewerSchema && (
<ActionContextProvider value={actionContextValue}>
<RecordProvider record={card} parent={parentRecordData}>
<DeclareVariable
name="$nPopupRecord"
title={t('Current popup record')}
value={card}
collection={collection}
>
<VariablePopupRecordProvider recordData={card} collection={collection}>
<MemorizedRecursionField basePath={cardViewerBasePath} schema={cardViewerSchema} onlyRenderProperties />
</DeclareVariable>
</VariablePopupRecordProvider>
</RecordProvider>
</ActionContextProvider>
)}

View File

@ -11,9 +11,10 @@ import { CheckOutlined, EnvironmentOutlined, ExpandOutlined } from '@ant-design/
import { RecursionField, useFieldSchema } from '@formily/react';
import {
ActionContextProvider,
DeclareVariable,
RecordProvider,
VariablePopupRecordProvider,
css,
getLabelFormatValue,
useCollection,
useCollectionManager_deprecated,
useCollectionParentRecordData,
@ -21,7 +22,6 @@ import {
useCompile,
useFilterAPI,
useProps,
getLabelFormatValue,
} from '@nocobase/client';
import { useMemoizedFn } from 'ahooks';
import { Button, Space } from 'antd';
@ -345,14 +345,9 @@ const MapBlockDrawer = (props) => {
schema && (
<ActionContextProvider value={{ visible: !!record, setVisible }}>
<RecordProvider record={record} parent={parentRecordData}>
<DeclareVariable
name="$nPopupRecord"
title={t('Current popup record')}
value={record}
collection={collection}
>
<VariablePopupRecordProvider recordData={record} collection={collection}>
<RecursionField schema={schema} name={schema.name} />
</DeclareVariable>
</VariablePopupRecordProvider>
</RecordProvider>
</ActionContextProvider>
)

View File

@ -11,9 +11,10 @@ import { CheckOutlined, EnvironmentOutlined, ExpandOutlined } from '@ant-design/
import { RecursionField, Schema, useFieldSchema } from '@formily/react';
import {
ActionContextProvider,
DeclareVariable,
RecordProvider,
VariablePopupRecordProvider,
css,
getLabelFormatValue,
useCollection,
useCollectionManager_deprecated,
useCollectionParentRecordData,
@ -21,7 +22,6 @@ import {
useCompile,
useFilterAPI,
useProps,
getLabelFormatValue,
} from '@nocobase/client';
import { useMemoizedFn } from 'ahooks';
import { Button, Space } from 'antd';
@ -394,14 +394,9 @@ const MapBlockDrawer = (props) => {
schema && (
<ActionContextProvider value={{ visible: !!record, setVisible }}>
<RecordProvider record={record} parent={parentRecordData}>
<DeclareVariable
name="$nPopupRecord"
title={t('Current popup record')}
value={record}
collection={collection}
>
<VariablePopupRecordProvider recordData={record} collection={collection}>
<RecursionField schema={schema} name={schema.name} />
</DeclareVariable>
</VariablePopupRecordProvider>
</RecordProvider>
</ActionContextProvider>
)