diff --git a/packages/core/client/src/acl/Configuration/RolesResourcesActions.tsx b/packages/core/client/src/acl/Configuration/RolesResourcesActions.tsx index 1c9616db2..07d4ce2e5 100644 --- a/packages/core/client/src/acl/Configuration/RolesResourcesActions.tsx +++ b/packages/core/client/src/acl/Configuration/RolesResourcesActions.tsx @@ -193,6 +193,7 @@ export const RolesResourcesActions = connect((props) => { render: (checked, field) => ( { const item = actionMap[action.name] || { name: action.name, diff --git a/packages/core/client/src/acl/Configuration/StrategyActions.tsx b/packages/core/client/src/acl/Configuration/StrategyActions.tsx index 1590a31ec..8dc9cbc88 100644 --- a/packages/core/client/src/acl/Configuration/StrategyActions.tsx +++ b/packages/core/client/src/acl/Configuration/StrategyActions.tsx @@ -67,6 +67,7 @@ export const StrategyActions = connect((props) => { render: (enabled, action) => ( { if (enabled) { delete scopes[action.name]; diff --git a/packages/core/client/src/schema-component/antd/action/Action.Designer.tsx b/packages/core/client/src/schema-component/antd/action/Action.Designer.tsx index 4329b5f22..24b106521 100644 --- a/packages/core/client/src/schema-component/antd/action/Action.Designer.tsx +++ b/packages/core/client/src/schema-component/antd/action/Action.Designer.tsx @@ -100,8 +100,8 @@ function ButtonEditor(props) { default: fieldSchema?.['x-component-props']?.danger ? 'danger' : fieldSchema?.['x-component-props']?.type === 'primary' - ? 'primary' - : 'default', + ? 'primary' + : 'default', enum: [ { value: 'default', label: '{{t("Default")}}' }, { value: 'primary', label: '{{t("Highlight")}}' }, diff --git a/packages/core/test/src/e2e/e2eUtils.ts b/packages/core/test/src/e2e/e2eUtils.ts index 50c8bc854..80fa2cdaf 100644 --- a/packages/core/test/src/e2e/e2eUtils.ts +++ b/packages/core/test/src/e2e/e2eUtils.ts @@ -89,6 +89,38 @@ export interface CollectionSetting { }>; } +interface AclActionsSetting { + name: string; //操作标识,如cretae + fields?: any[]; //有该操作权限的字段 + scope?: any; // 数据范围 +} +interface AclResourcesSetting { + name: string; //数据表标识 + usingActionsConfig: boolean; //是否开启单独配置 + actions?: AclActionsSetting[]; +} +interface AclRoleSetting { + name?: string; + title?: string; + /** + * @default true + */ + allowNewMenu?: boolean; + //配置权限,如 ["app", "pm", "pm.*", "ui.*"] + snippets?: string[]; + //操作权限策略 + strategy?: any; + //数据表单独操作权限配置 + resources?: AclResourcesSetting[]; + /** + * @default false + */ + default?: boolean; + key?: string; + //菜单权限配置 + menuUiSchemas?: string[]; +} + export interface PageConfig { /** * 页面类型 @@ -188,6 +220,14 @@ interface ExtendUtils { * @returns */ deletePage: (pageName: string) => Promise; + /** + * 生成一个新的角色,并和admin关联上 + */ + mockRole: (roleSetting: AclRoleSetting) => Promise; + /** + * 更新角色权限配置 + */ + updateRole: (roleSetting: AclRoleSetting) => Promise; } const PORT = process.env.APP_PORT || 20000; @@ -232,7 +272,10 @@ export class NocoPage { await this._waitForInit; return this.url; } - + async getUid() { + await this._waitForInit; + return this.uid; + } async waitForInit(this: NocoPage) { await this._waitForInit; return this; @@ -267,6 +310,7 @@ const _test = base.extend({ // 测试运行完自动销毁页面 for (const nocoPage of nocoPages) { await nocoPage.destroy(); + await setDefaultRole('root'); } }, mockManualDestroyPage: async ({ browser }, use) => { @@ -378,6 +422,20 @@ const _test = base.extend({ ]; await Promise.all(deletePromises); }, + mockRole: async ({ page }, use) => { + const mockRole = async (roleSetting: AclRoleSetting) => { + return createRole(roleSetting); + }; + + await use(mockRole); + }, + updateRole: async ({ page }, use) => { + async (roleSetting: AclRoleSetting) => { + return updateRole(roleSetting); + }; + + await use(updateRole); + }, }); export const test = Object.assign(_test, { @@ -592,6 +650,76 @@ const createCollections = async (collectionSettings: CollectionSetting | Collect return (await result.json()).data; }; +/** + * 根据配置创建一个角色并将角色关联给superAdmin且切换到新角色 + * @param page 运行测试的 page 实例 + * @param AclRoleSetting + * @returns + */ +const createRole = async (roleSetting: AclRoleSetting) => { + const api = await request.newContext({ + storageState: process.env.PLAYWRIGHT_AUTH_FILE, + }); + + const state = await api.storageState(); + const headers = getHeaders(state); + const name = roleSetting.name || uid(); + + const result = await api.post(`/api/users/1/roles:create`, { + headers, + data: { ...roleSetting, name, title: name }, + }); + + if (!result.ok()) { + throw new Error(await result.text()); + } + const roleData = (await result.json()).data; + await setDefaultRole(name); + return roleData; +}; + +/** + * 根据配置更新角色权限 + * @param page 运行测试的 page 实例 + * @param AclRoleSetting + * @returns + */ +const updateRole = async (roleSetting: AclRoleSetting) => { + const api = await request.newContext({ + storageState: process.env.PLAYWRIGHT_AUTH_FILE, + }); + const state = await api.storageState(); + const headers = getHeaders(state); + const name = roleSetting.name; + + const result = await api.post(`/api/users/1/roles:update?filterByTk=${name}`, { + headers, + data: { ...roleSetting }, + }); + + if (!result.ok()) { + throw new Error(await result.text()); + } + const roleData = (await result.json()).data; + return roleData; +}; + +/** + * 设置默认角色 + * @param name + */ +const setDefaultRole = async (name) => { + const api = await request.newContext({ + storageState: process.env.PLAYWRIGHT_AUTH_FILE, + }); + const state = await api.storageState(); + const headers = getHeaders(state); + await api.post(`/api/users:setDefaultRole`, { + headers, + data: { roleName: name }, + }); +}; + /** * 根据 collection 的配置生成 Faker 数据 * @param collectionSetting diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/association.test.ts b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/association.test.ts new file mode 100644 index 000000000..58faec14f --- /dev/null +++ b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/association.test.ts @@ -0,0 +1,242 @@ +import { expect, test } from '@nocobase/test/e2e'; +import { oneTableBlock } from './utils'; + +test.describe('view', () => { + //关系字段有权限,关系目标表无权限 + test('association field accept, target collection denied', async ({ page, mockPage, mockRole, mockRecord }) => { + await mockPage(oneTableBlock).goto(); + await mockRecord('general'); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'users', + }, + { + usingActionsConfig: true, + name: 'general', + actions: [{ name: 'view', fields: ['oneToOneBelongsTo'] }], + }, + ], + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + //关系字段可见 + await expect(page.getByRole('button', { name: 'oneToOneBelongsTo' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'phone' })).not.toBeVisible(); + await page.getByLabel('action-Action.Link-Association block-customize:popup-general-table').click(); + //关系区块不可见 + await expect(await page.getByLabel('block-item-CardItem-users-form')).not.toBeVisible(); + }); + //关系字段有权限,关系目标表个别字段有权限 + test('association field accept, target collection accept with fields', async ({ + page, + mockPage, + mockRole, + mockRecord, + }) => { + await mockPage(oneTableBlock).goto(); + await mockRecord('general'); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'users', + actions: [{ name: 'view', fields: ['email'] }], + }, + { + usingActionsConfig: true, + name: 'general', + actions: [{ name: 'view', fields: ['oneToOneBelongsTo'] }], + }, + ], + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + //关系字段可见 + await expect(page.getByRole('button', { name: 'oneToOneBelongsTo' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'phone' })).not.toBeVisible(); + await page.getByLabel('action-Action.Link-Association block-customize:popup-general-table').click(); + //关系区块可见,个别字段可见 + await expect(await page.getByLabel('block-item-CardItem-users-form')).toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.nickname')).not.toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.email')).toBeVisible(); + }); +}); + +test.describe('update', () => { + //关系字段有权限,关系目标表无权限 + test('association field accept,target collection denied', async ({ page, mockPage, mockRole, mockRecord }) => { + await mockPage(oneTableBlock).goto(); + await mockRecord('general'); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'users', + }, + { + usingActionsConfig: true, + name: 'general', + actions: [ + { name: 'view', fields: ['oneToOneBelongsTo'] }, + { name: 'update', fields: ['oneToOneBelongsTo'] }, + ], + }, + ], + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + await page.getByLabel('action-Action.Link-Association field-customize:popup-general-table').click(); + //关系字段组件可见,子表单/子表格中字段不可见 + await expect( + await page.getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo'), + ).toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.email-Email')).not.toBeVisible(); + }); + //关系字段有权限,关系目标表个别字段有权限 + test('association field accept, target collection accept with fields', async ({ + page, + mockPage, + mockRole, + mockRecord, + }) => { + await mockPage(oneTableBlock).goto(); + await mockRecord('general'); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'users', + actions: [{ name: 'view' }, { name: 'update', fields: ['email'] }], + }, + { + usingActionsConfig: true, + name: 'general', + actions: [ + { name: 'view', fields: ['oneToOneBelongsTo'] }, + { name: 'update', fields: ['oneToOneBelongsTo'] }, + ], + }, + ], + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + await page.getByLabel('action-Action.Link-Association field-customize:popup-general-table').click(); + //关系字段组件可见,子表单/子表格中个别字段可见 + await expect( + await page.getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo'), + ).toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.email')).toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.phone')).not.toBeVisible(); + }); +}); + +test.describe('create', () => { + //关系字段有权限,关系目标表无权限 + test('association field accept,target collection denied', async ({ page, mockPage, mockRole, mockRecord }) => { + await mockPage(oneTableBlock).goto(); + await mockRecord('general'); + //新建角色并切换到新角色 + const roleData = await mockRole({ + default: true, + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'users', + }, + { + usingActionsConfig: true, + name: 'general', + actions: [ + { name: 'view', fields: ['oneToOneBelongsTo'] }, + { name: 'create', fields: ['oneToOneBelongsTo'] }, + ], + }, + ], + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + await page.getByLabel('action-Action-Add new-create').click(); + //关系字段组件可见,子表单/子表格中字段不可见 + await expect( + await page.getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo'), + ).toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.email')).not.toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.phone')).not.toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.username')).not.toBeVisible(); + }); + //关系字段有权限,关系目标表个别字段有权限 + test('association field accept, target collection accept with fields', async ({ + page, + mockPage, + mockRole, + mockRecord, + }) => { + await mockPage(oneTableBlock).goto(); + await mockRecord('general'); + //新建角色并切换到新角色 + const roleData = await mockRole({ + default: true, + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'users', + actions: [{ name: 'view' }, { name: 'create', fields: ['email'] }], + }, + { + usingActionsConfig: true, + name: 'general', + actions: [ + { name: 'view', fields: ['oneToOneBelongsTo'] }, + { name: 'create', fields: ['oneToOneBelongsTo'] }, + ], + }, + ], + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + await page.getByLabel('action-Action-Add new-create').click(); + //关系字段组件可见,子表单/子表格中个别字段可见 + await expect( + await page.getByLabel('block-item-CollectionField-general-form-general.oneToOneBelongsTo'), + ).toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.email')).toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.phone')).not.toBeVisible(); + await expect(await page.getByLabel('block-item-CollectionField-users-form-users.username')).not.toBeVisible(); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/collection.test.ts b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/collection.test.ts new file mode 100644 index 000000000..901050f16 --- /dev/null +++ b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/collection.test.ts @@ -0,0 +1,461 @@ +import { expect, test } from '@nocobase/test/e2e'; +import { oneTableBlock } from './utils'; + +test.describe('view', () => { + test('general permission', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage(oneTableBlock).goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + strategy: { + actions: ['view'], + }, + }); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + }); + test('individual collection permission', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage(oneTableBlock).goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + strategy: { + actions: ['view'], + }, + resources: [ + { + usingActionsConfig: true, + name: 'general', + }, + ], + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [{ name: 'view', fields: [] }], + }, + ], + }); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + await expect(page.getByRole('button', { name: 'singleLineText' })).not.toBeVisible(); + await expect(page.getByRole('button', { name: 'phone' })).not.toBeVisible(); + }); + test('individual collection permission with fields', async ({ page, mockPage, mockRole }) => { + await mockPage(oneTableBlock).goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [{ name: 'view', fields: ['singleLineText'] }], + }, + ], + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + //特定字段有权限 + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + await expect(page.getByRole('button', { name: 'singleLineText' })).toBeVisible(); + await expect(page.getByRole('button', { name: 'phone' })).not.toBeVisible(); + }); +}); + +test.describe('create', () => { + test('general permission', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage(oneTableBlock).goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + strategy: { + actions: ['view'], + }, + allowNewMenu: true, + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + await expect(await page.getByLabel('action-Action-Add new-create-general-table')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + strategy: { + actions: ['view', 'create'], + }, + }); + await page.reload(); + await expect(await page.getByLabel('action-Action-Add new-create-general-table')).toBeVisible(); + }); + test('individual collection permission', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage(oneTableBlock).goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + strategy: { + actions: ['create'], + }, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [ + { + name: 'view', + }, + ], + }, + ], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await mockPage(oneTableBlock).goto(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + await expect(await page.getByLabel('action-Action-Add new-create-general-table')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [ + { + name: 'view', + }, + { name: 'create' }, + ], + }, + ], + }); + await page.reload(); + await expect(await page.getByLabel('action-Action-Add new-create-general-table')).toBeVisible(); + }); + test('individual collection permission width fields', async ({ page, mockPage, mockRole }) => { + await mockPage(oneTableBlock).goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [ + { + name: 'view', + fields: ['id', 'singleLineText'], + scope: null, + }, + { + name: 'create', + fields: ['singleLineText'], + scope: null, + }, + ], + }, + ], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await mockPage(oneTableBlock).goto(); + await expect(await page.getByLabel('action-Action-Add new-create-general-table')).toBeVisible(); + await await page.getByLabel('action-Action-Add new-create-general-table').click(); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.singleLineText')).toBeVisible(); + }); +}); + +test.describe('update', () => { + test('general permission', async ({ page, mockPage, mockRole, mockRecord, updateRole }) => { + await mockPage(oneTableBlock).goto(); + await mockRecord('general'); + //新建角色并切换到新角色 + const roleData = await mockRole({ + strategy: { + actions: ['view'], + }, + allowNewMenu: true, + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(await page.getByLabel('action-Action.Link-Edit')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + strategy: { + actions: ['view', 'update'], + }, + }); + await page.reload(); + await expect(await page.getByLabel('action-Action.Link-Edit')).toBeVisible(); + }); + test('individual collection permission', async ({ page, mockPage, mockRole, mockRecord, updateRole }) => { + await mockPage(oneTableBlock).goto(); + await mockRecord('general'); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + strategy: { + actions: ['update'], + }, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [{ name: 'view' }], + }, + ], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await mockPage(oneTableBlock).goto(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + await expect(await page.getByLabel('action-Action.Link-Edit')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [ + { + name: 'view', + }, + { name: 'update' }, + ], + }, + ], + }); + await page.reload(); + await expect(await page.getByLabel('action-Action.Link-Edit')).toBeVisible(); + }); + test('individual collection permission with fields', async ({ page, mockPage, mockRole, mockRecord }) => { + await mockPage(oneTableBlock).goto(); + await mockRecord('general'); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [{ name: 'view' }, { name: 'update', fields: ['singleLineText', 'phone', 'email'] }], + }, + ], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await mockPage(oneTableBlock).goto(); + await expect(await page.getByLabel('action-Action.Link-Edit')).toBeVisible(); + await page.getByLabel('action-Action.Link-Edit').click(); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.singleLineText')).toBeVisible(); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.phone')).toBeVisible(); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.email')).toBeVisible(); + await expect(page.getByLabel('block-item-CollectionField-general-form-general.number')).not.toBeVisible(); + }); +}); + +test.describe('destroy', () => { + test('general permission', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage(oneTableBlock).goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + strategy: { + actions: ['view'], + }, + allowNewMenu: true, + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(await page.getByLabel('action-Action-Delete-destroy-general-table')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + strategy: { + actions: ['view', 'destroy'], + }, + }); + await page.reload(); + await expect(await page.getByLabel('action-Action-Delete-destroy-general-table')).toBeVisible(); + }); + test('individual collection permission', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage().goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + strategy: { + actions: ['destroy'], + }, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [{ name: 'view' }], + }, + ], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await mockPage(oneTableBlock).goto(); + await expect(page.getByLabel('block-item-CardItem-general-table')).toBeVisible(); + await expect(await page.getByLabel('action-Action-Delete-destroy-general-table')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [ + { + name: 'view', + }, + { name: 'destroy' }, + ], + }, + ], + }); + await page.reload(); + await expect(await page.getByLabel('action-Action-Delete-destroy-general-table')).toBeVisible(); + }); +}); + +test.describe('export', () => { + test('general permission', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage(oneTableBlock).goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + strategy: { + actions: ['view'], + }, + allowNewMenu: true, + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(await page.getByLabel('action-Action-Export')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + strategy: { + actions: ['view', 'export'], + }, + }); + await page.reload(); + await expect(await page.getByLabel('action-Action-Export')).toBeVisible(); + }); + test('individual collection permission', async ({ page, mockPage, mockRole }) => { + await mockPage().goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [ + { name: 'view' }, + { + name: 'export', + scope: null, + }, + ], + }, + ], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await mockPage(oneTableBlock).goto(); + await expect(await page.getByLabel('action-Action-Export')).toBeVisible(); + }); +}); + +test.describe('import', () => { + test('general permission', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage().goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + strategy: { + actions: ['view'], + }, + allowNewMenu: true, + }); + await mockPage(oneTableBlock).goto(); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(await page.getByLabel('action-Action-Import')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + strategy: { + actions: ['view', 'importXlsx'], + }, + }); + await page.reload(); + await expect(await page.getByLabel('action-Action-Import')).toBeVisible(); + }); + test('individual collection permission', async ({ page, mockPage, mockRole }) => { + await mockPage().goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + allowNewMenu: true, + resources: [ + { + usingActionsConfig: true, + name: 'general', + actions: [ + { name: 'view' }, + { + name: 'importXlsx', + scope: null, + }, + ], + }, + ], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await mockPage(oneTableBlock).goto(); + await expect(await page.getByLabel('action-Action-Import')).toBeVisible(); + }); +}); diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/configure.test.ts b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/configure.test.ts new file mode 100644 index 000000000..b4079f08a --- /dev/null +++ b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/configure.test.ts @@ -0,0 +1,151 @@ +import { expect, test } from '@nocobase/test/e2e'; +import { oneTableBlock } from './utils'; + +test('allows to configure interface', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage().goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + snippets: ['ui.*'], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(await page.getByTestId('ui-editor-button')).toBeVisible(); + await expect(await page.getByTestId('schema-initializer-Menu-header')).toBeVisible(); + //更新权限,无ui配置权限 + await updateRole({ + name: roleData.name, + snippets: ['!ui.*'], + }); + await page.reload(); + await expect(await page.getByTestId('ui-editor-button')).not.toBeVisible(); + await expect(await page.getByTestId('schema-initializer-Menu-header')).not.toBeVisible(); +}); + +test('allows to install ,install,disabled plugins ', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage().goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + snippets: ['pm'], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(await page.getByTestId('plugin-manager-button')).toBeVisible(); + await page.getByTestId('plugin-manager-button').click(); + await expect(await page.url()).toContain('/pm/list/local'); + await expect( + await page.locator('.ant-page-header-heading').getByTitle('Plugin manager', { exact: true }), + ).toBeVisible(); + //无插件管理权限时访问直接路由访问时404 + await updateRole({ + name: roleData.name, + snippets: ['!pm'], + }); + await page.reload(); + await expect(await page.getByTestId('plugin-manager-button')).not.toBeVisible(); + await page.goto('/pm/list/local'); + await expect(await page.getByText('Sorry, the page you visited')).toBeVisible(); + await expect(await page.getByRole('button', { name: 'Back Home' })).toBeVisible(); +}); + +test('allows to confgiure plugins ', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage().goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + snippets: ['pm.*'], + strategy: { + actions: ['view', 'update'], + }, + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await page.getByTestId('plugin-settings-button').click(); + await page.getByLabel('acl').click(); + await page.getByLabel(`action-Action.Link-Configure-roles-${roleData.name}`).click(); + await expect(page.getByRole('tab').getByText('Plugin settings permissions')).toBeVisible(); + await updateRole({ + name: roleData.name, + snippets: ['!pm.*'], + }); + await page.reload(); + await expect(page.getByTestId('plugin-settings-button')).not.toBeVisible(); +}); + +test('allows to clear cache,reboot application ', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage().goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + snippets: ['app'], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await page.getByTestId('user-center-button').hover(); + await expect(await page.getByRole('menuitem', { name: 'Clear cache' })).toBeVisible(); + await expect(await page.getByRole('menuitem', { name: 'Restart application' })).toBeVisible(); + await updateRole({ + name: roleData.name, + snippets: ['!app'], + }); + await page.reload(); + await page.getByTestId('user-center-button').hover(); + await expect(await page.getByRole('menuitem', { name: 'Clear cache' })).not.toBeVisible(); + await expect(await page.getByRole('menuitem', { name: 'Restart application' })).not.toBeVisible(); +}); + +test('new menu items allow to be asscessed by default ', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage().goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + snippets: ['ui.*'], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await mockPage({ ...oneTableBlock, name: 'new page' }).goto(); + await expect(page.getByLabel('new page')).not.toBeVisible(); + await updateRole({ + name: roleData.name, + allowNewMenu: true, + }); + await mockPage({ ...oneTableBlock, name: 'new page' }).goto(); + await expect(page.getByLabel('new page')).toBeVisible(); +}); + +test('plugin settings permissions', async ({ page, mockPage, mockRole, updateRole }) => { + await mockPage().goto(); + //新建角色并切换到新角色 + const roleData = await mockRole({ + snippets: ['pm', 'pm.*', '!pm.auth.authenticators', '!pm.collection-manager', '!pm.collection-manager.collections'], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await page.getByTestId('plugin-settings-button').hover(); + await expect(await page.getByLabel('acl')).toBeVisible(); + await expect(await page.getByLabel('auth')).not.toBeVisible(); + await expect(await page.getByLabel('collection-manager')).not.toBeVisible(); + await page.getByLabel('acl').click(); + await expect(await page.getByRole('menuitem', { name: 'login Authentication' })).not.toBeVisible(); + await expect(await page.getByRole('menuitem', { name: 'database Collection manager' })).not.toBeVisible(); + await updateRole({ + name: roleData.name, + snippets: ['pm', 'pm.*', 'pm.auth.authenticators', 'pm.collection-manager', 'pm.collection-manager.collections'], + }); + await page.reload(); + await page.getByTestId('plugin-settings-button').hover(); + await expect(await page.getByLabel('acl')).toBeVisible(); + await expect(await page.getByLabel('auth')).toBeVisible(); + await expect(await page.getByLabel('collection-manager')).toBeVisible(); + await page.getByLabel('acl').click(); + await expect(await page.getByRole('menuitem', { name: 'login Authentication' })).toBeVisible(); + await expect(await page.getByRole('menuitem', { name: 'database Collection manager' })).toBeVisible(); +}); diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/menu.test.ts b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/menu.test.ts new file mode 100644 index 000000000..bccee2b9f --- /dev/null +++ b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/menu.test.ts @@ -0,0 +1,50 @@ +import { expect, test } from '@nocobase/test/e2e'; + +test('menu permission ', async ({ page, mockPage, mockRole, updateRole }) => { + const page2 = await mockPage({ name: 'page2' }); + const page1 = await mockPage({ name: 'page1' }); + await page1.goto(); + const uid1 = await page1.getUid(); + const uid2 = await page2.getUid(); + //新建角色并切换到新角色,page1有权限,page2无权限 + const roleData = await mockRole({ + snippets: ['pm.*'], + strategy: { + actions: ['view', 'update'], + }, + menuUiSchemas: [uid1], + }); + await page.evaluate((roleData) => { + window.localStorage.setItem('NOCOBASE_ROLE', roleData.name); + }, roleData); + await page.reload(); + await expect(await page.getByLabel('page1')).toBeVisible(); + await expect(await page.getByLabel('page2')).not.toBeVisible(); + await page.getByTestId('plugin-settings-button').hover(); + await page.getByLabel('acl').click(); + await page.getByLabel(`action-Action.Link-Configure-roles-${roleData.name}`).click(); + await page.getByRole('tab').getByText('Menu permissions').click(); + await page.waitForSelector('.ant-table'); + const page1Menu = await page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input'); + const page2Menu = await page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input'); + await expect(await page1Menu.isChecked()).toBe(true); + await expect(await page2Menu.isChecked()).toBe(false); + //修改菜单权限,page1无权限,page2有权限 + await updateRole({ name: roleData.name, menuUiSchemas: [uid2] }); + await page.reload(); + await expect(await page.getByLabel('page2')).toBeVisible(); + await expect(await page.getByLabel('page1')).not.toBeVisible(); + await page.getByTestId('plugin-settings-button').hover(); + await page.getByLabel('acl').click(); + await page.getByLabel(`action-Action.Link-Configure-roles-${roleData.name}`).click(); + await page.getByRole('tab').getByText('Menu permissions').click(); + await page.waitForSelector('.ant-table'); + const page1Menu1 = await page.getByRole('row', { name: 'page1' }).locator('.ant-checkbox-input'); + const page2Menu1 = await page.getByRole('row', { name: 'page2' }).locator('.ant-checkbox-input'); + await expect(await page1Menu1.isChecked()).toBe(false); + await expect(await page2Menu1.isChecked()).toBe(true); + //通过路由访问无权限的菜单,跳到有权限的第一个菜单 + await page.goto(`/admin/${uid1}`); + await page.waitForSelector('.nb-page-wrapper'); + await expect(await page.url()).toContain(uid2); +}); diff --git a/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/utils.ts b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/utils.ts new file mode 100644 index 000000000..54857149e --- /dev/null +++ b/packages/plugins/@nocobase/plugin-acl/src/client/__e2e__/utils.ts @@ -0,0 +1,2551 @@ +import { general, PageConfig } from '@nocobase/test/e2e'; +/** + * 页面中有一个空的 Table 区块,并且配有字段:普通字段和关系字段 + */ +export const oneTableBlock: PageConfig = { + collections: general, + pageSchema: { + type: 'void', + version: '2.0', + 'x-component': 'Page', + _isJSONSchemaObject: true, + properties: { + gykihrjk18u: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': 'BlockInitializers', + _isJSONSchemaObject: true, + properties: { + hxf5h572bwc: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + x0n8tm56iqj: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + l4x3frse193: { + type: 'void', + version: '2.0', + 'x-designer': 'TableBlockDesigner', + 'x-component': 'CardItem', + 'x-decorator': 'TableBlockProvider', + 'x-acl-action': 'general:list', + 'x-filter-targets': [], + 'x-decorator-props': { + action: 'list', + params: { + pageSize: 20, + }, + rowKey: 'id', + dragSort: false, + resource: 'general', + showIndex: true, + collection: 'general', + disableTemplate: false, + }, + _isJSONSchemaObject: true, + properties: { + actions: { + type: 'void', + version: '2.0', + 'x-component': 'ActionBar', + 'x-initializer': 'TableActionInitializers', + 'x-component-props': { + style: { + marginBottom: 'var(--nb-spacing)', + }, + }, + _isJSONSchemaObject: true, + properties: { + bvmen0z04i2: { + type: 'void', + title: "{{t('Add new')}}", + version: '2.0', + 'x-align': 'right', + 'x-action': 'create', + 'x-designer': 'Action.Designer', + 'x-component': 'Action', + 'x-decorator': 'ACLActionProvider', + 'x-acl-action': 'create', + 'x-component-props': { + icon: 'PlusOutlined', + type: 'primary', + openMode: 'drawer', + component: 'CreateRecordAction', + }, + 'x-acl-action-props': { + skipScopeCheck: true, + }, + _isJSONSchemaObject: true, + properties: { + drawer: { + type: 'void', + title: '{{ t("Add record") }}', + version: '2.0', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + _isJSONSchemaObject: true, + properties: { + tabs: { + type: 'void', + version: '2.0', + 'x-component': 'Tabs', + 'x-initializer': 'TabPaneInitializersForCreateFormBlock', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + tab1: { + type: 'void', + title: '{{t("Add new")}}', + version: '2.0', + 'x-designer': 'Tabs.Designer', + 'x-component': 'Tabs.TabPane', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': 'CreateFormBlockInitializers', + _isJSONSchemaObject: true, + properties: { + f3q7xmyiyl4: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + rffotw9jklc: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + d1s558c7cb4: { + type: 'void', + version: '2.0', + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-decorator': 'FormBlockProvider', + 'x-acl-action': 'general:create', + 'x-component-props': {}, + 'x-decorator-props': { + resource: 'general', + collection: 'general', + }, + 'x-acl-action-props': { + skipScopeCheck: true, + }, + _isJSONSchemaObject: true, + properties: { + lrygnjl6p4s: { + type: 'void', + version: '2.0', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + _isJSONSchemaObject: true, + properties: { + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + _isJSONSchemaObject: true, + properties: { + ddz3kqt5kpf: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + vll7e5c0lh4: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + singleLineText: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'general.singleLineText', + _isJSONSchemaObject: true, + 'x-uid': '3pkx27o6m3j', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8j6aujpq65v', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4r1c8y0e06s', + 'x-async': false, + 'x-index': 1, + }, + tb917i47w36: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + gtfi08wzouz: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + oneToOneBelongsTo: { + type: 'string', + 'x-uid': 'pwo35zuqr1v', + default: null, + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': { + mode: 'Nester', + }, + 'x-collection-field': + 'general.oneToOneBelongsTo', + _isJSONSchemaObject: true, + properties: { + dkch0rg951t: { + type: 'void', + version: '2.0', + 'x-index': 1, + 'x-component': + 'AssociationField.Nester', + _isJSONSchemaObject: true, + properties: { + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': + 'FormItemInitializers', + _isJSONSchemaObject: true, + properties: { + yhxqnl03mak: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + l7iokbg3wcs: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + nickname: { + type: 'string', + version: '2.0', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'users.nickname', + _isJSONSchemaObject: + true, + 'x-uid': '4vyr92lhz7f', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4wzfdz6xrgs', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'aen7e2woz46', + 'x-async': false, + 'x-index': 1, + }, + '54ayk66amem': { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + hfl137d5gx0: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + username: { + type: 'string', + version: '2.0', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'users.username', + _isJSONSchemaObject: + true, + 'x-uid': 'eotcjdflbgi', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'rwbh7lm3bma', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'o319tmva8fg', + 'x-async': false, + 'x-index': 2, + }, + xhbqfbveyp0: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + wvypx99ojj0: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + email: { + type: 'string', + version: '2.0', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'users.email', + _isJSONSchemaObject: + true, + 'x-uid': 'rjfub70uv31', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1kt5y2aijem', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '14w4id6gxs5', + 'x-async': false, + 'x-index': 3, + }, + '84ul6m1kqzv': { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + '3h0ra3hwkr0': { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + phone: { + type: 'string', + version: '2.0', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'users.phone', + _isJSONSchemaObject: + true, + 'x-uid': 'kw641beat5d', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6m93zxc1vdv', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ty81vpz3o0n', + 'x-async': false, + 'x-index': 4, + }, + }, + 'x-uid': 'ownvko3myu2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'twrluj9mh14', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'cllv6lhjq59', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hshnjrfhnko', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'x8dr1tz2kot', + 'x-async': false, + 'x-index': 1, + }, + actions: { + type: 'void', + version: '2.0', + 'x-component': 'ActionBar', + 'x-initializer': 'CreateFormActionInitializers', + 'x-component-props': { + style: { + marginTop: 24, + }, + layout: 'one-column', + }, + _isJSONSchemaObject: true, + 'x-uid': '3vs5hzhb19b', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'bg7nbf4kpfo', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'g3gu5lo47a2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'om69zcduw9q', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'twiigjtop0c', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'eje4a2zww7g', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'uhk88drsltl', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'uqi3cyst86b', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xe4hysl00cl', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0nrtg8p8xn2', + 'x-async': false, + 'x-index': 1, + }, + '102mxbpes1i': { + type: 'void', + title: '{{ t("Delete") }}', + version: '2.0', + 'x-align': 'right', + 'x-action': 'destroy', + 'x-designer': 'Action.Designer', + 'x-component': 'Action', + 'x-decorator': 'ACLActionProvider', + 'x-acl-action': 'general:destroy', + 'x-component-props': { + icon: 'DeleteOutlined', + confirm: { + title: "{{t('Delete record')}}", + content: "{{t('Are you sure you want to delete it?')}}", + }, + useProps: '{{ useBulkDestroyActionProps }}', + }, + 'x-acl-action-props': { + skipScopeCheck: true, + }, + _isJSONSchemaObject: true, + 'x-uid': '2xl3c4hzknj', + 'x-async': false, + 'x-index': 2, + }, + a6foojqjkxz: { + type: 'void', + title: '{{ t("Export") }}', + version: '2.0', + 'x-align': 'right', + 'x-action': 'export', + 'x-designer': 'ExportDesigner', + 'x-component': 'Action', + 'x-decorator': 'ACLActionProvider', + 'x-action-settings': { + exportSettings: [ + { + dataIndex: ['id'], + }, + { + dataIndex: ['nickname'], + }, + { + dataIndex: ['username'], + }, + { + dataIndex: ['email'], + }, + { + dataIndex: ['phone'], + }, + { + dataIndex: ['password'], + }, + ], + }, + 'x-component-props': { + icon: 'clouddownloadoutlined', + useProps: '{{ useExportAction }}', + }, + 'x-acl-action-props': { + skipScopeCheck: true, + }, + _isJSONSchemaObject: true, + 'x-uid': 'ec384gccvkd', + 'x-async': false, + 'x-index': 1, + }, + ub6x23zylo0: { + type: 'void', + title: '{{ t("Import") }}', + version: '2.0', + 'x-align': 'right', + 'x-action': 'importXlsx', + 'x-designer': 'ImportDesigner', + 'x-component': 'Action', + 'x-decorator': 'ACLActionProvider', + 'x-acl-action': 'importXlsx', + 'x-action-settings': { + importSettings: { + explain: '', + importColumns: [ + { + dataIndex: ['nickname'], + }, + { + dataIndex: ['username'], + }, + { + dataIndex: ['email'], + }, + { + dataIndex: ['phone'], + }, + { + dataIndex: ['password'], + }, + ], + }, + }, + 'x-component-props': { + icon: 'CloudUploadOutlined', + openMode: 'modal', + }, + 'x-acl-action-props': { + skipScopeCheck: true, + }, + _isJSONSchemaObject: true, + properties: { + modal: { + type: 'void', + title: '{{ t("Import Data", {ns: "import" }) }}', + version: '2.0', + 'x-component': 'Action.Container', + 'x-decorator': 'Form', + 'x-component-props': { + width: '50%', + className: 'css-rg76rb', + }, + _isJSONSchemaObject: true, + properties: { + formLayout: { + type: 'void', + version: '2.0', + 'x-component': 'FormLayout', + _isJSONSchemaObject: true, + properties: { + download: { + type: 'void', + title: '{{ t("Step 1: Download template", {ns: "import" }) }}', + version: '2.0', + 'x-component': 'FormItem', + 'x-acl-ignore': true, + _isJSONSchemaObject: true, + properties: { + tip: { + type: 'void', + version: '2.0', + 'x-editable': false, + 'x-component': 'Markdown.Void', + 'x-component-props': { + style: { + color: 'var(--colorText)', + border: '1px solid var(--colorInfoBorder)', + padding: 'var(--paddingContentVerticalSM)', + marginBottom: 'var(--marginSM)', + backgroundColor: 'var(--colorInfoBg)', + }, + content: '{{ t("Download tip", {ns: "import" }) }}', + }, + _isJSONSchemaObject: true, + 'x-uid': 'p47ou5drhji', + 'x-async': false, + 'x-index': 1, + }, + downloadAction: { + type: 'void', + title: '{{ t("Download template", {ns: "import" }) }}', + version: '2.0', + 'x-component': 'Action', + 'x-component-props': { + className: 'css-mdli8g', + useAction: '{{ useDownloadXlsxTemplateAction }}', + }, + _isJSONSchemaObject: true, + 'x-uid': 'dbxz3d2ujxa', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'd6tpu2s3eiu', + 'x-async': false, + 'x-index': 1, + }, + upload: { + type: 'array', + title: '{{ t("Step 2: Upload Excel", {ns: "import" }) }}', + version: '2.0', + 'x-component': 'Upload.Dragger', + 'x-decorator': 'FormItem', + 'x-validator': '{{ uploadValidator }}', + 'x-acl-ignore': true, + 'x-component-props': { + action: '', + height: '150px', + tipContent: '{{ t("Upload placeholder", {ns: "import" }) }}', + beforeUpload: '{{ beforeUploadHandler }}', + }, + _isJSONSchemaObject: true, + 'x-uid': 'bqe1cf71x2a', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'ub1gnhd3erd', + 'x-async': false, + 'x-index': 1, + }, + footer: { + version: '2.0', + 'x-component': 'Action.Container.Footer', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + actions: { + type: 'void', + version: '2.0', + 'x-component': 'ActionBar', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + cancel: { + type: 'void', + title: '{{ t("Cancel") }}', + version: '2.0', + 'x-component': 'Action', + 'x-component-props': { + useAction: '{{ cm.useCancelAction }}', + }, + _isJSONSchemaObject: true, + 'x-uid': 'c6fy1agooio', + 'x-async': false, + 'x-index': 1, + }, + startImport: { + type: 'void', + title: '{{ t("Start import", {ns: "import" }) }}', + version: '2.0', + 'x-component': 'Action', + 'x-reactions': { + fulfill: { + run: 'validateUpload($form, $self, $deps)', + }, + dependencies: ['upload'], + }, + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useAction: '{{ useImportStartAction }}', + }, + _isJSONSchemaObject: true, + 'x-uid': 'fbe5njghnvp', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'nj5w0gbzrsa', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'a9qjj5eotkw', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'as8dekuon05', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6l46l104rnj', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'umw2wrvyo28', + 'x-async': false, + 'x-index': 1, + }, + nuqg6tj5dqw: { + type: 'array', + version: '2.0', + 'x-component': 'TableV2', + 'x-initializer': 'TableColumnInitializers', + 'x-component-props': { + rowKey: 'id', + useProps: '{{ useTableBlockProps }}', + rowSelection: { + type: 'checkbox', + }, + }, + _isJSONSchemaObject: true, + properties: { + actions: { + type: 'void', + title: '{{ t("Actions") }}', + 'x-uid': 'swmh4uwsmwa', + version: '2.0', + 'x-designer': 'TableV2.ActionColumnDesigner', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.ActionBar', + 'x-initializer': 'TableActionColumnInitializers', + 'x-action-column': 'actions', + 'x-component-props': { + width: 400, + }, + _isJSONSchemaObject: true, + properties: { + actions: { + type: 'void', + version: '2.0', + 'x-component': 'Space', + 'x-decorator': 'DndContext', + 'x-component-props': { + split: '|', + }, + _isJSONSchemaObject: true, + properties: { + rp84v9dau96: { + type: 'void', + title: '{{ t("Edit") }}', + version: '2.0', + 'x-action': 'update', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + 'x-component-props': { + icon: 'EditOutlined', + openMode: 'drawer', + }, + _isJSONSchemaObject: true, + properties: { + drawer: { + type: 'void', + title: '{{ t("Edit record") }}', + version: '2.0', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + _isJSONSchemaObject: true, + properties: { + tabs: { + type: 'void', + version: '2.0', + 'x-component': 'Tabs', + 'x-initializer': 'TabPaneInitializers', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + tab1: { + type: 'void', + title: '{{t("Edit")}}', + version: '2.0', + 'x-designer': 'Tabs.Designer', + 'x-component': 'Tabs.TabPane', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + _isJSONSchemaObject: true, + properties: { + yyehsjjoo8e: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + '1u81bmn26oh': { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + dwoh5owg1mu: { + type: 'void', + version: '2.0', + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-decorator': 'FormBlockProvider', + 'x-acl-action': 'general:update', + 'x-component-props': {}, + 'x-decorator-props': { + action: 'get', + resource: 'general', + useParams: '{{ useParamsFromRecord }}', + collection: 'general', + useSourceId: '{{ useSourceIdFromParentRecord }}', + }, + 'x-acl-action-props': { + skipScopeCheck: false, + }, + _isJSONSchemaObject: true, + properties: { + wf32dhpznsx: { + type: 'void', + version: '2.0', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + _isJSONSchemaObject: true, + properties: { + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + _isJSONSchemaObject: true, + properties: { + q3s02k44o3o: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + krgq64hq2lt: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + singleLineText: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'general.singleLineText', + _isJSONSchemaObject: true, + 'x-uid': 'lwz9i3cxh3f', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'cpxxudpe5vv', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'i2kne4spc11', + 'x-async': false, + 'x-index': 1, + }, + pv2y7i07nz1: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + e1m9i3ff9jw: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + phone: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'general.phone', + _isJSONSchemaObject: true, + 'x-uid': '4no4a66qmxx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'psai5tibdu1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'uqfbp8yft29', + 'x-async': false, + 'x-index': 2, + }, + xmkdit1yn3r: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + h6dfgswjl74: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + email: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'general.email', + _isJSONSchemaObject: true, + 'x-uid': 'ovxawxrhxu8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0xw7tlk4rel', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'q0yn43c6ur1', + 'x-async': false, + 'x-index': 3, + }, + '8lw4jgskiyq': { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + z97j4k1g0hu: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + number: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'general.number', + _isJSONSchemaObject: true, + 'x-uid': 'ohw7tc69996', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4xywmvuw07u', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'e8xld0n55s8', + 'x-async': false, + 'x-index': 4, + }, + }, + 'x-uid': '08amqmd1yyl', + 'x-async': false, + 'x-index': 1, + }, + actions: { + type: 'void', + version: '2.0', + 'x-component': 'ActionBar', + 'x-initializer': 'UpdateFormActionInitializers', + 'x-component-props': { + style: { + marginTop: 24, + }, + layout: 'one-column', + }, + _isJSONSchemaObject: true, + properties: { + jtq8q1sada2: { + type: 'void', + title: '{{ t("Submit") }}', + version: '2.0', + 'x-action': 'submit', + 'x-designer': 'Action.Designer', + 'x-component': 'Action', + 'x-action-settings': { + triggerWorkflows: [], + }, + 'x-component-props': { + type: 'primary', + htmlType: 'submit', + useProps: '{{ useUpdateActionProps }}', + }, + _isJSONSchemaObject: true, + 'x-uid': 'beaj4s0mglf', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'oqa2c44qmrv', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'rxt19fkl2mp', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0mmejmfgnrq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'jnufl16l10v', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vjuo13pvot5', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ef56p3ubs3z', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '86u3yngtvsp', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ywexcvyt332', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xclkpf3cmus', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'y0elzxa5ckn', + 'x-async': false, + 'x-index': 1, + }, + '4xs33evufma': { + type: 'void', + title: '{{ t("View") }}', + version: '2.0', + 'x-action': 'view', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-decorator': 'ACLActionProvider', + 'x-designer-props': { + linkageAction: true, + }, + 'x-component-props': { + openMode: 'drawer', + }, + _isJSONSchemaObject: true, + properties: { + drawer: { + type: 'void', + title: '{{ t("View record") }}', + version: '2.0', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + _isJSONSchemaObject: true, + properties: { + tabs: { + type: 'void', + version: '2.0', + 'x-component': 'Tabs', + 'x-initializer': 'TabPaneInitializers', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + tab1: { + type: 'void', + title: '{{t("Details")}}', + version: '2.0', + 'x-designer': 'Tabs.Designer', + 'x-component': 'Tabs.TabPane', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + _isJSONSchemaObject: true, + 'x-uid': '9be5zlgowvl', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'h2l84gezc9z', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'fw7v14u7dw0', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'd6qcrw7pxm9', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ot2916fqr88', + 'x-async': false, + 'x-index': 2, + }, + yv7t1ushwsj: { + type: 'void', + title: 'Association field', + 'x-uid': 'j5l7v52ftxf', + version: '2.0', + 'x-action': 'customize:popup', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-designer-props': { + linkageAction: true, + }, + 'x-component-props': { + danger: false, + openMode: 'drawer', + }, + _isJSONSchemaObject: true, + properties: { + drawer: { + type: 'void', + title: '{{ t("Popup") }}', + version: '2.0', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + _isJSONSchemaObject: true, + properties: { + tabs: { + type: 'void', + version: '2.0', + 'x-component': 'Tabs', + 'x-initializer': 'TabPaneInitializers', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + tab1: { + type: 'void', + title: '{{t("Details")}}', + version: '2.0', + 'x-designer': 'Tabs.Designer', + 'x-component': 'Tabs.TabPane', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + _isJSONSchemaObject: true, + properties: { + pk40wwnw0cp: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + vp07gwoy5zw: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + lcn5rklguxs: { + type: 'void', + version: '2.0', + 'x-designer': 'FormV2.Designer', + 'x-component': 'CardItem', + 'x-decorator': 'FormBlockProvider', + 'x-acl-action': 'general:update', + 'x-component-props': {}, + 'x-decorator-props': { + action: 'get', + resource: 'general', + useParams: '{{ useParamsFromRecord }}', + collection: 'general', + useSourceId: '{{ useSourceIdFromParentRecord }}', + }, + 'x-acl-action-props': { + skipScopeCheck: false, + }, + _isJSONSchemaObject: true, + properties: { + ayckfphyfov: { + type: 'void', + version: '2.0', + 'x-component': 'FormV2', + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + _isJSONSchemaObject: true, + properties: { + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': 'FormItemInitializers', + _isJSONSchemaObject: true, + properties: { + '7043nizntd8': { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + '3rpf7gxo2b0': { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + oneToOneBelongsTo: { + type: 'string', + 'x-uid': '2r7qxq1devc', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': { + mode: 'Nester', + }, + 'x-collection-field': + 'general.oneToOneBelongsTo', + _isJSONSchemaObject: true, + properties: { + jot4ibpbav6: { + type: 'void', + version: '2.0', + 'x-index': 1, + 'x-component': + 'AssociationField.Nester', + _isJSONSchemaObject: true, + properties: { + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': + 'FormItemInitializers', + _isJSONSchemaObject: true, + properties: { + dtxjb31ls31: { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Row', + _isJSONSchemaObject: + true, + properties: { + '16hy9o43lw3': { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Col', + _isJSONSchemaObject: + true, + properties: { + nickname: { + type: 'string', + version: '2.0', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-component-props': + {}, + 'x-collection-field': + 'users.nickname', + _isJSONSchemaObject: + true, + 'x-uid': + 'bmgy7q59phb', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'kk4o7xzwakq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'y6ecg89gwnc', + 'x-async': false, + 'x-index': 1, + }, + ivx1km02x4a: { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Row', + _isJSONSchemaObject: + true, + properties: { + '2ihsfcbje69': { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Col', + _isJSONSchemaObject: + true, + properties: { + username: { + type: 'string', + version: '2.0', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-component-props': + {}, + 'x-collection-field': + 'users.username', + _isJSONSchemaObject: + true, + 'x-uid': + 'egwd6ablbba', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + '7s4mmbpo70u', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'qeqe9w2ss7j', + 'x-async': false, + 'x-index': 2, + }, + p9z0x51055h: { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Row', + _isJSONSchemaObject: + true, + properties: { + wef811qqesy: { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Col', + _isJSONSchemaObject: + true, + properties: { + email: { + type: 'string', + version: '2.0', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-component-props': + {}, + 'x-collection-field': + 'users.email', + _isJSONSchemaObject: + true, + 'x-uid': + 'tf2u14d0bnm', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'hkyvgbi1ivc', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 't3gh0wv6e7n', + 'x-async': false, + 'x-index': 3, + }, + v6h9rzbxz3y: { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Row', + _isJSONSchemaObject: + true, + properties: { + '5mzmg368cgc': { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Col', + _isJSONSchemaObject: + true, + properties: { + phone: { + type: 'string', + version: '2.0', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-component-props': + {}, + 'x-collection-field': + 'users.phone', + _isJSONSchemaObject: + true, + 'x-uid': + '7svpr9sjqq7', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'wmnp7z1herk', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'x2372x0535z', + 'x-async': false, + 'x-index': 4, + }, + '6e7rg543py2': { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Row', + _isJSONSchemaObject: + true, + properties: { + '51r85dms6u5': { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Col', + _isJSONSchemaObject: + true, + properties: { + password: { + type: 'string', + version: '2.0', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-component-props': + {}, + 'x-collection-field': + 'users.password', + _isJSONSchemaObject: + true, + 'x-uid': + 'oadthvx1ers', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + '3i3zf2kajwh', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '48y13rla8md', + 'x-async': false, + 'x-index': 5, + }, + i9h89hft5dp: { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Row', + _isJSONSchemaObject: + true, + properties: { + helm5fnfsjx: { + type: 'void', + version: '2.0', + 'x-component': + 'Grid.Col', + _isJSONSchemaObject: + true, + properties: { + roles: { + type: 'string', + version: '2.0', + 'x-designer': + 'FormItem.Designer', + 'x-component': + 'CollectionField', + 'x-decorator': + 'FormItem', + 'x-component-props': + {}, + 'x-collection-field': + 'users.roles', + _isJSONSchemaObject: + true, + 'x-uid': + 'o35fyaetimm', + 'x-async': + false, + 'x-index': 1, + }, + }, + 'x-uid': + 'ymr0667h1rx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'r94l4c51qdu', + 'x-async': false, + 'x-index': 6, + }, + }, + 'x-uid': 'mef6cnvk4n1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '1cnjtwsrvce', + 'x-async': false, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '3zzp77bn550', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '4lbpg41i5hh', + 'x-async': false, + 'x-index': 1, + }, + z3ckqofz7uk: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + mhrfvtqmwwz: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + oneToOneHasOne: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'general.oneToOneHasOne', + _isJSONSchemaObject: true, + 'x-uid': '75qh2fu0yn3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 't2b53tdr8a6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'n9abk3dzeon', + 'x-async': false, + 'x-index': 2, + }, + z34ckqofz7uk: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + mhrfvtqmwwz: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + phone: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'general.phone', + _isJSONSchemaObject: true, + 'x-uid': '75qh2fu0yn3', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 't2b53tdr8a6', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'n9abk3dzeon', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'pl7g0fjy2nh', + 'x-async': false, + 'x-index': 1, + }, + actions: { + type: 'void', + version: '2.0', + 'x-component': 'ActionBar', + 'x-initializer': 'UpdateFormActionInitializers', + 'x-component-props': { + style: { + marginTop: 24, + }, + layout: 'one-column', + }, + _isJSONSchemaObject: true, + 'x-uid': 't7fz6v4krgf', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'rbc3kl2hvhy', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '06o9bp7jenm', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'hye1tyke2f5', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'gvcjxzj18rx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6vljvmrpdr1', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'eefwh6mxm72', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'm1gv9s8t1dq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0tmh3ohxp7i', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 3, + }, + cf04st1doqj: { + type: 'void', + title: 'Association block', + 'x-uid': 'ygit3lt71wu', + version: '2.0', + 'x-action': 'customize:popup', + 'x-designer': 'Action.Designer', + 'x-component': 'Action.Link', + 'x-designer-props': { + linkageAction: true, + }, + 'x-component-props': { + danger: false, + openMode: 'drawer', + }, + _isJSONSchemaObject: true, + properties: { + drawer: { + type: 'void', + title: '{{ t("Popup") }}', + version: '2.0', + 'x-component': 'Action.Container', + 'x-component-props': { + className: 'nb-action-popup', + }, + _isJSONSchemaObject: true, + properties: { + tabs: { + type: 'void', + version: '2.0', + 'x-component': 'Tabs', + 'x-initializer': 'TabPaneInitializers', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + tab1: { + type: 'void', + title: '{{t("Details")}}', + version: '2.0', + 'x-designer': 'Tabs.Designer', + 'x-component': 'Tabs.TabPane', + 'x-component-props': {}, + _isJSONSchemaObject: true, + properties: { + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': 'RecordBlockInitializers', + _isJSONSchemaObject: true, + properties: { + h9gq1awpz33: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + wwma4u9vs33: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Col', + _isJSONSchemaObject: true, + properties: { + e3wa9ksa61p: { + type: 'void', + version: '2.0', + 'x-designer': 'FormV2.ReadPrettyDesigner', + 'x-component': 'CardItem', + 'x-decorator': 'FormBlockProvider', + 'x-acl-action': 'general.oneToOneBelongsTo:get', + 'x-decorator-props': { + action: 'get', + resource: 'general.oneToOneBelongsTo', + useParams: '{{ useParamsFromRecord }}', + collection: 'users', + readPretty: true, + association: 'general.oneToOneBelongsTo', + useSourceId: '{{ useSourceIdFromParentRecord }}', + }, + _isJSONSchemaObject: true, + properties: { + hmrnj50stnn: { + type: 'void', + version: '2.0', + 'x-component': 'FormV2', + 'x-read-pretty': true, + 'x-component-props': { + useProps: '{{ useFormBlockProps }}', + }, + _isJSONSchemaObject: true, + properties: { + actions: { + type: 'void', + version: '2.0', + 'x-component': 'ActionBar', + 'x-initializer': + 'ReadPrettyFormActionInitializers', + 'x-component-props': { + style: { + marginBottom: 24, + }, + }, + _isJSONSchemaObject: true, + 'x-uid': 'tdc35crk959', + 'x-async': false, + 'x-index': 1, + }, + grid: { + type: 'void', + version: '2.0', + 'x-component': 'Grid', + 'x-initializer': + 'ReadPrettyFormItemInitializers', + _isJSONSchemaObject: true, + properties: { + hnzs6hajxl8: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + l2rzx99pe1q: { + type: 'void', + 'x-uid': 'tjzdv9fcy46', + version: '2.0', + 'x-component': 'Grid.Col', + 'x-component-props': { + width: 50, + }, + _isJSONSchemaObject: true, + properties: { + nickname: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'users.nickname', + _isJSONSchemaObject: true, + 'x-uid': 'hwj09s913pp', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + col_ieim3ainmxp: { + type: 'void', + 'x-uid': 'osiaahtxspl', + version: '2.0', + 'x-index': 2, + 'x-component': 'Grid.Col', + 'x-component-props': { + width: 50, + }, + _isJSONSchemaObject: true, + properties: { + username: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'users.username', + _isJSONSchemaObject: true, + 'x-uid': '3fgcmm59sn2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + }, + }, + 'x-uid': '4jh24thyzji', + 'x-async': false, + 'x-index': 1, + }, + w9sohgtdob8: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + 'x-uid': 'lg4k7rtlroe', + 'x-async': false, + 'x-index': 2, + }, + '0xed87brbgn': { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + eck0tjtvtqj: { + type: 'void', + 'x-uid': 'cu4iz7ec6cf', + version: '2.0', + 'x-component': 'Grid.Col', + 'x-component-props': { + width: 50, + }, + _isJSONSchemaObject: true, + properties: { + email: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': 'users.email', + _isJSONSchemaObject: true, + 'x-uid': 'f5nxznv89nw', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + col_q8pei4rwpuu: { + type: 'void', + 'x-uid': 'bze2uaq8sac', + version: '2.0', + 'x-index': 2, + 'x-component': 'Grid.Col', + 'x-component-props': { + width: 50, + }, + _isJSONSchemaObject: true, + properties: { + roles: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': 'users.roles', + _isJSONSchemaObject: true, + 'x-uid': 'p6o44dyg2hv', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + }, + }, + 'x-uid': '8487clm2h1d', + 'x-async': false, + 'x-index': 3, + }, + z2urij42mlu: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + properties: { + xxowyuoye0h: { + type: 'void', + 'x-uid': 'hmgps9sm6g8', + version: '2.0', + 'x-component': 'Grid.Col', + 'x-component-props': { + width: 50, + }, + _isJSONSchemaObject: true, + properties: { + phone: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': 'users.phone', + _isJSONSchemaObject: true, + 'x-uid': 'j7q42thdc0l', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + col_8kb6rj112c7: { + type: 'void', + 'x-uid': 'axqn8wwbhno', + version: '2.0', + 'x-index': 2, + 'x-component': 'Grid.Col', + 'x-component-props': { + width: 50, + }, + _isJSONSchemaObject: true, + properties: { + password: { + type: 'string', + version: '2.0', + 'x-designer': 'FormItem.Designer', + 'x-component': 'CollectionField', + 'x-decorator': 'FormItem', + 'x-component-props': {}, + 'x-collection-field': + 'users.password', + _isJSONSchemaObject: true, + 'x-uid': 'eni7v79rei8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + }, + }, + 'x-uid': 'p8q6fzmoyze', + 'x-async': false, + 'x-index': 4, + }, + acnkxdxfcrb: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + 'x-uid': 'uh1c0g2zmh7', + 'x-async': false, + 'x-index': 5, + }, + tp22hmqfkx4: { + type: 'void', + version: '2.0', + 'x-component': 'Grid.Row', + _isJSONSchemaObject: true, + 'x-uid': 'tjp2c1g04mp', + 'x-async': false, + 'x-index': 6, + }, + }, + 'x-uid': 'k8uldkiwlty', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 'moj4dj9zlaw', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8mncgotvyen', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'icoqry4f469', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 't4c10e77fao', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'etsjrvzlha2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'lg5dob1gc6r', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'zpiznv38ffh', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '94pm27jgsyh', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 4, + }, + }, + 'x-uid': 'mi05lvz5sj2', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-async': false, + 'x-index': 1, + }, + '3pmpjhgqowq': { + type: 'void', + version: '2.0', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.Decorator', + _isJSONSchemaObject: true, + properties: { + singleLineText: { + version: '2.0', + 'x-component': 'CollectionField', + 'x-decorator': null, + 'x-read-pretty': true, + 'x-component-props': { + ellipsis: true, + }, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-collection-field': 'general.singleLineText', + _isJSONSchemaObject: true, + 'x-uid': 'xm6e5fx373q', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '6t82jp5hr1m', + 'x-async': false, + 'x-index': 2, + }, + '11e49qf01aw': { + type: 'void', + version: '2.0', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.Decorator', + _isJSONSchemaObject: true, + properties: { + longText: { + version: '2.0', + 'x-component': 'CollectionField', + 'x-decorator': null, + 'x-read-pretty': true, + 'x-component-props': { + ellipsis: true, + }, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-collection-field': 'general.longText', + _isJSONSchemaObject: true, + 'x-uid': 't5nrfwmaigp', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'b3442vog2ub', + 'x-async': false, + 'x-index': 3, + }, + ty56uhq3oc3: { + type: 'void', + version: '2.0', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.Decorator', + _isJSONSchemaObject: true, + properties: { + phone: { + version: '2.0', + 'x-component': 'CollectionField', + 'x-decorator': null, + 'x-read-pretty': true, + 'x-component-props': {}, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-collection-field': 'general.phone', + _isJSONSchemaObject: true, + 'x-uid': 'veclsb4jroc', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'xunnak6o7cj', + 'x-async': false, + 'x-index': 4, + }, + ld3bbfttiuh: { + type: 'void', + version: '2.0', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.Decorator', + _isJSONSchemaObject: true, + properties: { + email: { + version: '2.0', + 'x-component': 'CollectionField', + 'x-decorator': null, + 'x-read-pretty': true, + 'x-component-props': { + ellipsis: true, + }, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-collection-field': 'general.email', + _isJSONSchemaObject: true, + 'x-uid': 'iy4abo2fgtf', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ps5f4jilksp', + 'x-async': false, + 'x-index': 5, + }, + kgu9w0kfa3h: { + type: 'void', + version: '2.0', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.Decorator', + _isJSONSchemaObject: true, + properties: { + singleSelect: { + version: '2.0', + 'x-component': 'CollectionField', + 'x-decorator': null, + 'x-read-pretty': true, + 'x-component-props': { + style: { + width: '100%', + }, + ellipsis: true, + }, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-collection-field': 'general.singleSelect', + _isJSONSchemaObject: true, + 'x-uid': 'r1hf1edkoxe', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'm38xdtsxffw', + 'x-async': false, + 'x-index': 6, + }, + '0nwbyr3jin1': { + type: 'void', + version: '2.0', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.Decorator', + _isJSONSchemaObject: true, + properties: { + oneToOneBelongsTo: { + version: '2.0', + 'x-component': 'CollectionField', + 'x-decorator': null, + 'x-read-pretty': true, + 'x-component-props': { + size: 'small', + ellipsis: true, + }, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-collection-field': 'general.oneToOneBelongsTo', + _isJSONSchemaObject: true, + 'x-uid': 'o1mia5vv7kx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'yqloj3n5bsd', + 'x-async': false, + 'x-index': 7, + }, + xgyu9wopugu: { + type: 'void', + version: '2.0', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.Decorator', + _isJSONSchemaObject: true, + properties: { + oneToOneHasOne: { + version: '2.0', + 'x-component': 'CollectionField', + 'x-decorator': null, + 'x-read-pretty': true, + 'x-component-props': { + size: 'small', + ellipsis: true, + }, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-collection-field': 'general.oneToOneHasOne', + _isJSONSchemaObject: true, + 'x-uid': 'lo7x9558odx', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '439igde42zv', + 'x-async': false, + 'x-index': 8, + }, + '83lxo5i9pwq': { + type: 'void', + version: '2.0', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.Decorator', + _isJSONSchemaObject: true, + properties: { + oneToMany: { + version: '2.0', + 'x-component': 'CollectionField', + 'x-decorator': null, + 'x-read-pretty': true, + 'x-component-props': { + size: 'small', + ellipsis: true, + }, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-collection-field': 'general.oneToMany', + _isJSONSchemaObject: true, + 'x-uid': '9h8rquhl00h', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '8mufbssl4do', + 'x-async': false, + 'x-index': 9, + }, + vzkxeoy50i9: { + type: 'void', + version: '2.0', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.Decorator', + _isJSONSchemaObject: true, + properties: { + manyToOne: { + version: '2.0', + 'x-component': 'CollectionField', + 'x-decorator': null, + 'x-read-pretty': true, + 'x-component-props': { + size: 'small', + ellipsis: true, + }, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-collection-field': 'general.manyToOne', + _isJSONSchemaObject: true, + 'x-uid': 'atg1d7n0ncs', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'ipj7p04jdqk', + 'x-async': false, + 'x-index': 10, + }, + x1i674dto56: { + type: 'void', + version: '2.0', + 'x-designer': 'TableV2.Column.Designer', + 'x-component': 'TableV2.Column', + 'x-decorator': 'TableV2.Column.Decorator', + _isJSONSchemaObject: true, + properties: { + manyToMany: { + version: '2.0', + 'x-component': 'CollectionField', + 'x-decorator': null, + 'x-read-pretty': true, + 'x-component-props': { + size: 'small', + ellipsis: true, + }, + 'x-decorator-props': { + labelStyle: { + display: 'none', + }, + }, + 'x-collection-field': 'general.manyToMany', + _isJSONSchemaObject: true, + 'x-uid': 'zp7u52u5b3s', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'wv4jzt9d5js', + 'x-async': false, + 'x-index': 11, + }, + }, + 'x-uid': 'vxm6u2njnf7', + 'x-async': false, + 'x-index': 2, + }, + }, + 'x-uid': 's4vae2h1w0s', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '5jcwzp2opkq', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'j3zf6q2e3c8', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': '0q7hj0y8wmr', + 'x-async': false, + 'x-index': 1, + }, + }, + 'x-uid': 'vq3rjplt98m', + 'x-async': true, + 'x-index': 1, + }, +};