mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 21:49:25 +08:00
Merge branch 'main' into next
This commit is contained in:
commit
2dad5b32c9
@ -7,7 +7,13 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { appendQueryStringToUrl, parseVariablesAndChangeParamsToQueryString, reduceValueSize } from '../../hooks/index';
|
import {
|
||||||
|
appendQueryStringToUrl,
|
||||||
|
completeURL,
|
||||||
|
navigateWithinSelf,
|
||||||
|
parseVariablesAndChangeParamsToQueryString,
|
||||||
|
reduceValueSize,
|
||||||
|
} from '../../hooks/index';
|
||||||
|
|
||||||
describe('parseVariablesAndChangeParamsToQueryString', () => {
|
describe('parseVariablesAndChangeParamsToQueryString', () => {
|
||||||
it('should parse variables and change params to query string', async () => {
|
it('should parse variables and change params to query string', async () => {
|
||||||
@ -150,3 +156,82 @@ describe('appendQueryStringToUrl', () => {
|
|||||||
expect(result).toBe('https://example.com?existingParam=value¶m1=value1¶m2=value2');
|
expect(result).toBe('https://example.com?existingParam=value¶m1=value1¶m2=value2');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('completeURL', () => {
|
||||||
|
it('should complete a relative URL with the origin', () => {
|
||||||
|
const origin = 'https://example.com';
|
||||||
|
const url = '/path/to/resource';
|
||||||
|
|
||||||
|
const result = completeURL(url, origin);
|
||||||
|
|
||||||
|
expect(result).toBe('https://example.com/path/to/resource');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the URL as is if it is already complete', () => {
|
||||||
|
const origin = 'https://example.com';
|
||||||
|
const url = 'https://example.com/path/to/resource';
|
||||||
|
|
||||||
|
const result = completeURL(url, origin);
|
||||||
|
|
||||||
|
expect(result).toBe('https://example.com/path/to/resource');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return the URL as is if it is already complete with a different origin', () => {
|
||||||
|
const origin = 'https://example.com';
|
||||||
|
const url = 'https://another.com/path/to/resource';
|
||||||
|
|
||||||
|
const result = completeURL(url, origin);
|
||||||
|
|
||||||
|
expect(result).toBe('https://another.com/path/to/resource');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return an empty string if the URL is falsy', () => {
|
||||||
|
const origin = 'https://example.com';
|
||||||
|
const url = '';
|
||||||
|
|
||||||
|
const result = completeURL(url, origin);
|
||||||
|
|
||||||
|
expect(result).toBe('');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('navigateWithinSelf', () => {
|
||||||
|
it('should navigate within the same window if the link is a relative URL', () => {
|
||||||
|
const origin = 'https://example.com';
|
||||||
|
const link = '/path/to/resource';
|
||||||
|
const navigate = vi.fn();
|
||||||
|
|
||||||
|
navigateWithinSelf(link, navigate, origin);
|
||||||
|
|
||||||
|
expect(navigate).toHaveBeenCalledWith(link);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should navigate within the same window if the link starts with the origin', () => {
|
||||||
|
const origin = 'https://example.com';
|
||||||
|
const link = 'https://example.com/path/to/resource';
|
||||||
|
const navigate = vi.fn();
|
||||||
|
|
||||||
|
navigateWithinSelf(link, navigate, origin);
|
||||||
|
|
||||||
|
expect(navigate).toHaveBeenCalledWith('/path/to/resource');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open the link in the same window if it is an external URL', () => {
|
||||||
|
const origin = 'https://example.com';
|
||||||
|
const link = 'https://other.com/path/to/resource';
|
||||||
|
window.open = vi.fn();
|
||||||
|
|
||||||
|
navigateWithinSelf(link, () => {}, origin);
|
||||||
|
|
||||||
|
expect(window.open).toHaveBeenCalledWith(link, '_self');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should log an error if the link is not a string', () => {
|
||||||
|
const link = null;
|
||||||
|
console.error = vi.fn();
|
||||||
|
|
||||||
|
navigateWithinSelf(link, () => {});
|
||||||
|
|
||||||
|
expect(console.error).toHaveBeenCalledWith('link should be a string');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
@ -19,6 +19,7 @@ import omit from 'lodash/omit';
|
|||||||
import qs from 'qs';
|
import qs from 'qs';
|
||||||
import { ChangeEvent, useCallback, useContext, useEffect, useMemo } from 'react';
|
import { ChangeEvent, useCallback, useContext, useEffect, useMemo } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { NavigateFunction } from 'react-router-dom';
|
||||||
import { useReactToPrint } from 'react-to-print';
|
import { useReactToPrint } from 'react-to-print';
|
||||||
import {
|
import {
|
||||||
AssociationFilter,
|
AssociationFilter,
|
||||||
@ -1561,6 +1562,7 @@ export function useLinkActionProps() {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const url = fieldSchema?.['x-component-props']?.['url'];
|
const url = fieldSchema?.['x-component-props']?.['url'];
|
||||||
const searchParams = fieldSchema?.['x-component-props']?.['params'] || [];
|
const searchParams = fieldSchema?.['x-component-props']?.['params'] || [];
|
||||||
|
const openInNewWindow = fieldSchema?.['x-component-props']?.['openInNewWindow'];
|
||||||
const { parseURLAndParams } = useParseURLAndParams();
|
const { parseURLAndParams } = useParseURLAndParams();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -1573,11 +1575,13 @@ export function useLinkActionProps() {
|
|||||||
const link = await parseURLAndParams(url, searchParams);
|
const link = await parseURLAndParams(url, searchParams);
|
||||||
|
|
||||||
if (link) {
|
if (link) {
|
||||||
if (isURL(link)) {
|
if (openInNewWindow) {
|
||||||
window.open(link, '_blank');
|
window.open(completeURL(link), '_blank');
|
||||||
} else {
|
} else {
|
||||||
navigate(link);
|
navigateWithinSelf(link, navigate);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
console.error('link should be a string');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -1676,3 +1680,30 @@ export function reduceValueSize(value: any) {
|
|||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 补全 URL
|
||||||
|
export function completeURL(url: string, origin = window.location.origin) {
|
||||||
|
if (!url) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
if (isURL(url)) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
return url.startsWith('/') ? `${origin}${url}` : `${origin}/${url}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function navigateWithinSelf(link: string, navigate: NavigateFunction, origin = window.location.origin) {
|
||||||
|
if (!_.isString(link)) {
|
||||||
|
return console.error('link should be a string');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isURL(link)) {
|
||||||
|
if (link.startsWith(origin)) {
|
||||||
|
navigate(link.replace(origin, ''));
|
||||||
|
} else {
|
||||||
|
window.open(link, '_self');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigate(link.startsWith('/') ? link : `/${link}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -63,7 +63,7 @@ export * from './variables';
|
|||||||
export { withDynamicSchemaProps } from './hoc/withDynamicSchemaProps';
|
export { withDynamicSchemaProps } from './hoc/withDynamicSchemaProps';
|
||||||
|
|
||||||
export { SchemaSettingsActionLinkItem } from './modules/actions/link/customizeLinkActionSettings';
|
export { SchemaSettingsActionLinkItem } from './modules/actions/link/customizeLinkActionSettings';
|
||||||
export { useURLAndParamsSchema } from './modules/actions/link/useURLAndParamsSchema';
|
export { useURLAndHTMLSchema } from './modules/actions/link/useURLAndHTMLSchema';
|
||||||
export * from './modules/blocks/BlockSchemaToolbar';
|
export * from './modules/blocks/BlockSchemaToolbar';
|
||||||
export * from './modules/blocks/data-blocks/form';
|
export * from './modules/blocks/data-blocks/form';
|
||||||
export * from './modules/blocks/data-blocks/table';
|
export * from './modules/blocks/data-blocks/table';
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { expect, test } from '@nocobase/test/e2e';
|
import { expect, test } from '@nocobase/test/e2e';
|
||||||
import { PopupAndSubPageWithParams, oneEmptyTableWithUsers } from './templates';
|
import { PopupAndSubPageWithParams, oneEmptyTableWithUsers, openInNewWidow } from './templates';
|
||||||
|
|
||||||
test.describe('Link', () => {
|
test.describe('Link', () => {
|
||||||
test('basic', async ({ page, mockPage, mockRecords }) => {
|
test('basic', async ({ page, mockPage, mockRecords }) => {
|
||||||
@ -85,6 +85,36 @@ test.describe('Link', () => {
|
|||||||
await expect(page.getByRole('button', { name: users[1].username, exact: true })).toBeVisible();
|
await expect(page.getByRole('button', { name: users[1].username, exact: true })).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('open in new window', async ({ page, mockPage, mockRecords }) => {
|
||||||
|
await mockPage(openInNewWidow).goto();
|
||||||
|
const otherPage = mockPage();
|
||||||
|
const otherPageUrl = await otherPage.getUrl();
|
||||||
|
|
||||||
|
// 默认情况下,点击链接按钮会在当前窗口打开
|
||||||
|
await page.getByLabel('action-Action.Link-Link-').hover();
|
||||||
|
await page.getByLabel('designer-schema-settings-Action.Link-actionSettings:link-users').hover();
|
||||||
|
await page.getByRole('menuitem', { name: 'Edit link' }).click();
|
||||||
|
await page.getByLabel('block-item-users-table-URL').getByLabel('textbox').fill(otherPageUrl);
|
||||||
|
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
||||||
|
|
||||||
|
await page.getByLabel('action-Action.Link-Link-').click();
|
||||||
|
expect(page.url().endsWith(otherPageUrl)).toBe(true);
|
||||||
|
|
||||||
|
// 开启 “Open in new window” 选项后,点击链接按钮会在新窗口打开
|
||||||
|
await page.goBack();
|
||||||
|
await page.getByLabel('action-Action.Link-Link-').hover();
|
||||||
|
await page.getByLabel('designer-schema-settings-Action.Link-actionSettings:link-users').hover();
|
||||||
|
await page.getByRole('menuitem', { name: 'Edit link' }).click();
|
||||||
|
await page.getByLabel('Open in new window').check();
|
||||||
|
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
||||||
|
|
||||||
|
await page.getByLabel('action-Action.Link-Link-').click();
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
|
const newPage = page.context().pages()[1];
|
||||||
|
expect(newPage.url().endsWith(otherPageUrl)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
test('popup and sub page with search params', async ({ page, mockPage, mockRecords }) => {
|
test('popup and sub page with search params', async ({ page, mockPage, mockRecords }) => {
|
||||||
const nocoPage = mockPage(PopupAndSubPageWithParams);
|
const nocoPage = mockPage(PopupAndSubPageWithParams);
|
||||||
const url = await nocoPage.getUrl();
|
const url = await nocoPage.getUrl();
|
||||||
|
@ -222,6 +222,176 @@ export const oneEmptyTableWithUsers = {
|
|||||||
'x-index': 1,
|
'x-index': 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
export const openInNewWidow = {
|
||||||
|
pageSchema: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Page',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
g3i4gd8j68w: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'page:addBlock',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
k0tx69u4ge5: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
hck9q8g9nfw: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
jq1vb4hd0vk: {
|
||||||
|
_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.21-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.21-alpha',
|
||||||
|
'x-uid': 'n7hoqcgj7nn',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
'068dk7k35nk': {
|
||||||
|
_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.21-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.21-alpha',
|
||||||
|
properties: {
|
||||||
|
mo7685lm8vz: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'DndContext',
|
||||||
|
'x-component': 'Space',
|
||||||
|
'x-component-props': {
|
||||||
|
split: '|',
|
||||||
|
},
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
t4s3iem6ael: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Link") }}',
|
||||||
|
'x-action': 'customize:link',
|
||||||
|
'x-toolbar': 'ActionSchemaToolbar',
|
||||||
|
'x-settings': 'actionSettings:link',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-use-component-props': 'useLinkActionProps',
|
||||||
|
'x-designer-props': {
|
||||||
|
linkageAction: true,
|
||||||
|
},
|
||||||
|
'x-uid': 'pvrerrk3t7w',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'cih8h4b2193',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '50yfcnetw5a',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '4q78sr1a4so',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'k38ru1y7s6s',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'a0aiamh41on',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'gn2c5n843iv',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'gvbup8mmfql',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'af02n5ipxrk',
|
||||||
|
'x-async': true,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
export const PopupAndSubPageWithParams = {
|
export const PopupAndSubPageWithParams = {
|
||||||
pageSchema: {
|
pageSchema: {
|
||||||
_isJSONSchemaObject: true,
|
_isJSONSchemaObject: true,
|
||||||
|
@ -17,15 +17,19 @@ import { SchemaSettings } from '../../../application/schema-settings/SchemaSetti
|
|||||||
import { useCollection_deprecated } from '../../../collection-manager';
|
import { useCollection_deprecated } from '../../../collection-manager';
|
||||||
import { ButtonEditor, RemoveButton } from '../../../schema-component/antd/action/Action.Designer';
|
import { ButtonEditor, RemoveButton } from '../../../schema-component/antd/action/Action.Designer';
|
||||||
import { SchemaSettingsLinkageRules, SchemaSettingsModalItem } from '../../../schema-settings';
|
import { SchemaSettingsLinkageRules, SchemaSettingsModalItem } from '../../../schema-settings';
|
||||||
import { useURLAndParamsSchema } from './useURLAndParamsSchema';
|
import { useURLAndHTMLSchema } from './useURLAndHTMLSchema';
|
||||||
|
|
||||||
export function SchemaSettingsActionLinkItem() {
|
export function SchemaSettingsActionLinkItem() {
|
||||||
const field = useField();
|
const field = useField();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { urlSchema, paramsSchema } = useURLAndParamsSchema();
|
const { urlSchema, paramsSchema, openInNewWindowSchema } = useURLAndHTMLSchema();
|
||||||
const initialValues = { url: field.componentProps.url, params: field.componentProps.params || [{}] };
|
const initialValues = {
|
||||||
|
url: field.componentProps.url,
|
||||||
|
params: field.componentProps.params || [{}],
|
||||||
|
openInNewWindow: field.componentProps.openInNewWindow,
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SchemaSettingsModalItem
|
<SchemaSettingsModalItem
|
||||||
@ -40,16 +44,21 @@ export function SchemaSettingsActionLinkItem() {
|
|||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
params: paramsSchema,
|
params: paramsSchema,
|
||||||
|
openInNewWindow: openInNewWindowSchema,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
onSubmit={({ url, params }) => {
|
onSubmit={({ url, params, openInNewWindow }) => {
|
||||||
const componentProps = fieldSchema['x-component-props'] || {};
|
const componentProps = fieldSchema['x-component-props'] || {};
|
||||||
componentProps.url = url;
|
componentProps.url = url;
|
||||||
fieldSchema['x-component-props'] = componentProps;
|
|
||||||
field.componentProps.url = url;
|
|
||||||
componentProps.params = params;
|
componentProps.params = params;
|
||||||
|
componentProps.openInNewWindow = openInNewWindow;
|
||||||
|
|
||||||
fieldSchema['x-component-props'] = componentProps;
|
fieldSchema['x-component-props'] = componentProps;
|
||||||
|
|
||||||
|
field.componentProps.url = url;
|
||||||
field.componentProps.params = params;
|
field.componentProps.params = params;
|
||||||
|
field.componentProps.openInNewWindow = openInNewWindow;
|
||||||
|
|
||||||
dn.emit('patch', {
|
dn.emit('patch', {
|
||||||
schema: {
|
schema: {
|
||||||
['x-uid']: fieldSchema['x-uid'],
|
['x-uid']: fieldSchema['x-uid'],
|
||||||
|
@ -32,8 +32,7 @@ const getVariableComponentWithScope = (Com) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useURLAndParamsSchema = () => {
|
export const useURLAndHTMLSchema = () => {
|
||||||
const fieldSchema = useFieldSchema();
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const Com = useMemo(() => getVariableComponentWithScope(Variable.TextArea), []);
|
const Com = useMemo(() => getVariableComponentWithScope(Variable.TextArea), []);
|
||||||
|
|
||||||
@ -53,7 +52,40 @@ export const useURLAndParamsSchema = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}, [t, fieldSchema]);
|
}, [t, Com]);
|
||||||
|
|
||||||
|
const modeSchema = useMemo(() => {
|
||||||
|
return {
|
||||||
|
title: '{{t("Mode")}}',
|
||||||
|
'x-component': 'Radio.Group',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
default: 'url',
|
||||||
|
enum: [
|
||||||
|
{ value: 'url', label: t('URL') },
|
||||||
|
{ value: 'html', label: t('HTML') },
|
||||||
|
],
|
||||||
|
};
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
|
const htmlSchema = useMemo(() => {
|
||||||
|
return {
|
||||||
|
title: t('html'),
|
||||||
|
type: 'string',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': getVariableComponentWithScope(Variable.RawTextArea),
|
||||||
|
'x-component-props': {
|
||||||
|
rows: 10,
|
||||||
|
},
|
||||||
|
'x-reactions': {
|
||||||
|
dependencies: ['mode'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
hidden: '{{$deps[0] === "url"}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
const paramsSchema = useMemo(() => {
|
const paramsSchema = useMemo(() => {
|
||||||
return {
|
return {
|
||||||
@ -123,7 +155,24 @@ export const useURLAndParamsSchema = () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}, [fieldSchema]);
|
}, [Com]);
|
||||||
|
|
||||||
return { urlSchema, paramsSchema };
|
const openInNewWindowSchema = useMemo(() => {
|
||||||
|
return {
|
||||||
|
type: 'boolean',
|
||||||
|
'x-content': t('Open in new window'),
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-component': 'Checkbox',
|
||||||
|
'x-reactions': {
|
||||||
|
dependencies: ['mode'],
|
||||||
|
fulfill: {
|
||||||
|
state: {
|
||||||
|
hidden: '{{$deps[0] === "html"}}',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}, [t]);
|
||||||
|
|
||||||
|
return { urlSchema, paramsSchema, openInNewWindowSchema, modeSchema, htmlSchema };
|
||||||
};
|
};
|
@ -16,7 +16,7 @@ import { SchemaInitializerItem, useSchemaInitializer } from '../../application';
|
|||||||
import { useGlobalTheme } from '../../global-theme';
|
import { useGlobalTheme } from '../../global-theme';
|
||||||
import { FormDialog, SchemaComponent, SchemaComponentOptions } from '../../schema-component';
|
import { FormDialog, SchemaComponent, SchemaComponentOptions } from '../../schema-component';
|
||||||
import { useStyles } from '../../schema-component/antd/menu/MenuItemInitializers';
|
import { useStyles } from '../../schema-component/antd/menu/MenuItemInitializers';
|
||||||
import { useURLAndParamsSchema } from '../actions/link/useURLAndParamsSchema';
|
import { useURLAndHTMLSchema } from '../actions/link/useURLAndHTMLSchema';
|
||||||
|
|
||||||
export const LinkMenuItem = () => {
|
export const LinkMenuItem = () => {
|
||||||
const { insert } = useSchemaInitializer();
|
const { insert } = useSchemaInitializer();
|
||||||
@ -24,7 +24,7 @@ export const LinkMenuItem = () => {
|
|||||||
const options = useContext(SchemaOptionsContext);
|
const options = useContext(SchemaOptionsContext);
|
||||||
const { theme } = useGlobalTheme();
|
const { theme } = useGlobalTheme();
|
||||||
const { styles } = useStyles();
|
const { styles } = useStyles();
|
||||||
const { urlSchema, paramsSchema } = useURLAndParamsSchema();
|
const { urlSchema, paramsSchema } = useURLAndHTMLSchema();
|
||||||
|
|
||||||
const handleClick = useCallback(async () => {
|
const handleClick = useCallback(async () => {
|
||||||
const values = await FormDialog(
|
const values = await FormDialog(
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* 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 { expect, test } from '@nocobase/test/e2e';
|
||||||
|
import { T4874 } from './templates';
|
||||||
|
|
||||||
|
test.describe('variable: current object', () => {
|
||||||
|
test('in sub table', async ({ page, mockPage }) => {
|
||||||
|
await mockPage(T4874).goto();
|
||||||
|
|
||||||
|
// 在子表格中,使用“当前对象”变量
|
||||||
|
await page.getByLabel('action-Action.Link-Edit-').click();
|
||||||
|
await page.getByRole('button', { name: 'Role name', exact: true }).hover();
|
||||||
|
await page
|
||||||
|
.getByRole('button', { name: 'designer-schema-settings-TableV2.Column-fieldSettings:TableColumn-roles' })
|
||||||
|
.hover();
|
||||||
|
await page.getByRole('menuitem', { name: 'Set default value' }).click();
|
||||||
|
await page.getByLabel('variable-button').click();
|
||||||
|
await page.getByRole('menuitemcheckbox', { name: 'Current object right' }).click();
|
||||||
|
await page.getByRole('menuitemcheckbox', { name: 'Role UID' }).click();
|
||||||
|
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
||||||
|
await page.getByRole('button', { name: 'Add new' }).click();
|
||||||
|
await page.getByRole('row', { name: 'table-index-4 block-item-' }).getByRole('textbox').nth(1).fill('123456');
|
||||||
|
await expect(page.getByRole('row', { name: 'table-index-4 block-item-' }).getByRole('textbox').first()).toHaveValue(
|
||||||
|
'123456',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
@ -388,3 +388,478 @@ export const APIToken = {
|
|||||||
'x-index': 1,
|
'x-index': 1,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
export const T4874 = {
|
||||||
|
pageSchema: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Page',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
d5btnu6z239: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'page:addBlock',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
dqmrwgx3h5j: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
'3q6wd3o9ve3': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
'1mw2svlh1t4': {
|
||||||
|
_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.21-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.21-alpha',
|
||||||
|
'x-uid': '66gj8p6hj5f',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
no5z0g08zmh: {
|
||||||
|
_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.21-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.21-alpha',
|
||||||
|
properties: {
|
||||||
|
'07oxu98m060': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator': 'DndContext',
|
||||||
|
'x-component': 'Space',
|
||||||
|
'x-component-props': {
|
||||||
|
split: '|',
|
||||||
|
},
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
'40ond6gt5sp': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Edit") }}',
|
||||||
|
'x-action': 'update',
|
||||||
|
'x-toolbar': 'ActionSchemaToolbar',
|
||||||
|
'x-settings': 'actionSettings:edit',
|
||||||
|
'x-component': 'Action.Link',
|
||||||
|
'x-component-props': {
|
||||||
|
openMode: 'drawer',
|
||||||
|
icon: 'EditOutlined',
|
||||||
|
},
|
||||||
|
'x-decorator': 'ACLActionProvider',
|
||||||
|
'x-designer-props': {
|
||||||
|
linkageAction: true,
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
drawer: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
title: '{{ t("Edit record") }}',
|
||||||
|
'x-component': 'Action.Container',
|
||||||
|
'x-component-props': {
|
||||||
|
className: 'nb-action-popup',
|
||||||
|
},
|
||||||
|
properties: {
|
||||||
|
tabs: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Tabs',
|
||||||
|
'x-component-props': {},
|
||||||
|
'x-initializer': 'popup:addTab',
|
||||||
|
properties: {
|
||||||
|
tab1: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
title: '{{t("Edit")}}',
|
||||||
|
'x-component': 'Tabs.TabPane',
|
||||||
|
'x-designer': 'Tabs.Designer',
|
||||||
|
'x-component-props': {},
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'popup:common:addBlock',
|
||||||
|
properties: {
|
||||||
|
xv1rqhlertx: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
j7nzjmqyrt6: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
te5nblgjx91: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-acl-action-props': {
|
||||||
|
skipScopeCheck: false,
|
||||||
|
},
|
||||||
|
'x-acl-action': 'users:update',
|
||||||
|
'x-decorator': 'FormBlockProvider',
|
||||||
|
'x-use-decorator-props':
|
||||||
|
'useEditFormBlockDecoratorProps',
|
||||||
|
'x-decorator-props': {
|
||||||
|
action: 'get',
|
||||||
|
dataSource: 'main',
|
||||||
|
collection: 'users',
|
||||||
|
},
|
||||||
|
'x-toolbar': 'BlockSchemaToolbar',
|
||||||
|
'x-settings': 'blockSettings:editForm',
|
||||||
|
'x-component': 'CardItem',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
'1c7o18qoag1': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'FormV2',
|
||||||
|
'x-use-component-props': 'useEditFormBlockProps',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
grid: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid',
|
||||||
|
'x-initializer': 'form:configureFields',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
'2k2z18gbdoy': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Row',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
c607566i7l3: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component': 'Grid.Col',
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
roles: {
|
||||||
|
'x-uid': 'nz02ten5fzf',
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'string',
|
||||||
|
'x-toolbar':
|
||||||
|
'FormItemSchemaToolbar',
|
||||||
|
'x-settings':
|
||||||
|
'fieldSettings:FormItem',
|
||||||
|
'x-component': 'CollectionField',
|
||||||
|
'x-decorator': 'FormItem',
|
||||||
|
'x-collection-field': 'users.roles',
|
||||||
|
'x-component-props': {
|
||||||
|
fieldNames: {
|
||||||
|
label: 'name',
|
||||||
|
value: 'name',
|
||||||
|
},
|
||||||
|
mode: 'SubTable',
|
||||||
|
},
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
fj6qv4odhaa: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-component':
|
||||||
|
'AssociationField.SubTable',
|
||||||
|
'x-initializer':
|
||||||
|
'table:configureColumns',
|
||||||
|
'x-initializer-props': {
|
||||||
|
action: false,
|
||||||
|
},
|
||||||
|
'x-index': 1,
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
'5j2fwrcfzuu': {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator':
|
||||||
|
'TableV2.Column.Decorator',
|
||||||
|
'x-toolbar':
|
||||||
|
'TableColumnSchemaToolbar',
|
||||||
|
'x-settings':
|
||||||
|
'fieldSettings:TableColumn',
|
||||||
|
'x-component':
|
||||||
|
'TableV2.Column',
|
||||||
|
'x-app-version':
|
||||||
|
'1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
title: {
|
||||||
|
_isJSONSchemaObject:
|
||||||
|
true,
|
||||||
|
version: '2.0',
|
||||||
|
'x-collection-field':
|
||||||
|
'roles.title',
|
||||||
|
'x-component':
|
||||||
|
'CollectionField',
|
||||||
|
'x-component-props': {
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
'x-decorator':
|
||||||
|
'FormItem',
|
||||||
|
'x-decorator-props': {
|
||||||
|
labelStyle: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-app-version':
|
||||||
|
'1.2.21-alpha',
|
||||||
|
'x-uid': '6hnbfgke4v9',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'xrfnjtprhgk',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
nm5lqvmdmol: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-decorator':
|
||||||
|
'TableV2.Column.Decorator',
|
||||||
|
'x-toolbar':
|
||||||
|
'TableColumnSchemaToolbar',
|
||||||
|
'x-settings':
|
||||||
|
'fieldSettings:TableColumn',
|
||||||
|
'x-component':
|
||||||
|
'TableV2.Column',
|
||||||
|
'x-app-version':
|
||||||
|
'1.2.21-alpha',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
_isJSONSchemaObject:
|
||||||
|
true,
|
||||||
|
version: '2.0',
|
||||||
|
'x-collection-field':
|
||||||
|
'roles.name',
|
||||||
|
'x-component':
|
||||||
|
'CollectionField',
|
||||||
|
'x-component-props': {
|
||||||
|
ellipsis: true,
|
||||||
|
},
|
||||||
|
'x-decorator':
|
||||||
|
'FormItem',
|
||||||
|
'x-decorator-props': {
|
||||||
|
labelStyle: {
|
||||||
|
display: 'none',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-app-version':
|
||||||
|
'1.2.21-alpha',
|
||||||
|
'x-uid': 'nug7nu8ebhi',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '0esgluhnedb',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'xsx2rz70uwz',
|
||||||
|
'x-async': false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'r23ltwfb8by',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'tudt41ppj3p',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '96z12k7x884',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
qq4upukd8xf: {
|
||||||
|
_isJSONSchemaObject: true,
|
||||||
|
version: '2.0',
|
||||||
|
type: 'void',
|
||||||
|
'x-initializer': 'editForm:configureActions',
|
||||||
|
'x-component': 'ActionBar',
|
||||||
|
'x-component-props': {
|
||||||
|
layout: 'one-column',
|
||||||
|
},
|
||||||
|
'x-app-version': '1.2.21-alpha',
|
||||||
|
'x-uid': 'wdmwmy60e2r',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '33zsf8du7j2',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'vfpz90ab0qw',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'gujrsvgrmjj',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '8xws8vfulhx',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'nl73uc805kr',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'izwg6n04xw3',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'p6wyw65zj1l',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': '7hlmuhqrtpk',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'yfxjokc1rxx',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'rriritgfmdw',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'liz6v1lau34',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'vh37l43zevq',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'wxsf1stb1oi',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'nnkwbb57n9f',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'dfonxd85q4n',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'uxb09qu50d0',
|
||||||
|
'x-async': false,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'x-uid': 'kg5tkkrw3x4',
|
||||||
|
'x-async': true,
|
||||||
|
'x-index': 1,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@ -14,7 +14,6 @@ import { observer, RecursionField, useFieldSchema } from '@formily/react';
|
|||||||
import { action } from '@formily/reactive';
|
import { action } from '@formily/reactive';
|
||||||
import { isArr } from '@formily/shared';
|
import { isArr } from '@formily/shared';
|
||||||
import { Button } from 'antd';
|
import { Button } from 'antd';
|
||||||
import { unionBy, uniqBy } from 'lodash';
|
|
||||||
import React, { useContext, useMemo, useState } from 'react';
|
import React, { useContext, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
@ -28,15 +27,66 @@ import { useCreateActionProps } from '../../../block-provider/hooks';
|
|||||||
import { FormActiveFieldsProvider } from '../../../block-provider/hooks/useFormActiveFields';
|
import { FormActiveFieldsProvider } from '../../../block-provider/hooks/useFormActiveFields';
|
||||||
import { TableSelectorParamsProvider } from '../../../block-provider/TableSelectorProvider';
|
import { TableSelectorParamsProvider } from '../../../block-provider/TableSelectorProvider';
|
||||||
import { CollectionProvider_deprecated } from '../../../collection-manager';
|
import { CollectionProvider_deprecated } from '../../../collection-manager';
|
||||||
import { CollectionRecordProvider, useCollectionRecord } from '../../../data-source';
|
import { CollectionRecordProvider, useCollection, useCollectionRecord } from '../../../data-source';
|
||||||
|
import { markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
|
||||||
import { FlagProvider } from '../../../flag-provider';
|
import { FlagProvider } from '../../../flag-provider';
|
||||||
import { useCompile } from '../../hooks';
|
import { useCompile } from '../../hooks';
|
||||||
import { ActionContextProvider } from '../action';
|
import { ActionContextProvider } from '../action';
|
||||||
import { Table } from '../table-v2/Table';
|
import { Table } from '../table-v2/Table';
|
||||||
import { useAssociationFieldContext, useFieldNames } from './hooks';
|
import { SubFormProvider, useAssociationFieldContext, useFieldNames } from './hooks';
|
||||||
import { useTableSelectorProps } from './InternalPicker';
|
import { useTableSelectorProps } from './InternalPicker';
|
||||||
import { getLabelFormatValue, useLabelUiSchema } from './util';
|
import { getLabelFormatValue, useLabelUiSchema } from './util';
|
||||||
import { markRecordAsNew } from '../../../data-source/collection-record/isNewRecord';
|
|
||||||
|
const subTableContainer = css`
|
||||||
|
.ant-table-footer {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
.ant-formily-item-error-help {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.ant-description-textarea {
|
||||||
|
line-height: 34px;
|
||||||
|
}
|
||||||
|
.ant-table-cell .ant-formily-item-error-help {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
font-size: 12px;
|
||||||
|
top: 100%;
|
||||||
|
background: #fff;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: -15px;
|
||||||
|
padding: 3px;
|
||||||
|
z-index: 1;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 0 10px #eee;
|
||||||
|
animation: none;
|
||||||
|
transform: translateY(0);
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const tableClassName = css`
|
||||||
|
.ant-formily-item.ant-formily-item-feedback-layout-loose {
|
||||||
|
margin-bottom: 0px !important;
|
||||||
|
}
|
||||||
|
.ant-formily-editable {
|
||||||
|
vertical-align: sub;
|
||||||
|
}
|
||||||
|
.ant-table-footer {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const addNewButtonClassName = css`
|
||||||
|
display: block;
|
||||||
|
border-radius: 0px;
|
||||||
|
border-right: 1px solid rgba(0, 0, 0, 0.06);
|
||||||
|
`;
|
||||||
|
|
||||||
|
const selectButtonClassName = css`
|
||||||
|
display: block;
|
||||||
|
border-radius: 0px;
|
||||||
|
`;
|
||||||
|
|
||||||
export const SubTable: any = observer(
|
export const SubTable: any = observer(
|
||||||
(props: any) => {
|
(props: any) => {
|
||||||
@ -50,6 +100,7 @@ export const SubTable: any = observer(
|
|||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const labelUiSchema = useLabelUiSchema(collectionField, fieldNames?.label || 'label');
|
const labelUiSchema = useLabelUiSchema(collectionField, fieldNames?.label || 'label');
|
||||||
const recordV2 = useCollectionRecord();
|
const recordV2 = useCollectionRecord();
|
||||||
|
const collection = useCollection();
|
||||||
const move = (fromIndex: number, toIndex: number) => {
|
const move = (fromIndex: number, toIndex: number) => {
|
||||||
if (toIndex === undefined) return;
|
if (toIndex === undefined) return;
|
||||||
if (!isArr(field.value)) return;
|
if (!isArr(field.value)) return;
|
||||||
@ -115,98 +166,56 @@ export const SubTable: any = observer(
|
|||||||
return filter;
|
return filter;
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={subTableContainer}>
|
||||||
className={css`
|
|
||||||
.ant-table-footer {
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
.ant-formily-item-error-help {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.ant-description-textarea {
|
|
||||||
line-height: 34px;
|
|
||||||
}
|
|
||||||
.ant-table-cell .ant-formily-item-error-help {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
font-size: 12px;
|
|
||||||
top: 100%;
|
|
||||||
background: #fff;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: -15px;
|
|
||||||
padding: 3px;
|
|
||||||
z-index: 1;
|
|
||||||
border-radius: 3px;
|
|
||||||
box-shadow: 0 0 10px #eee;
|
|
||||||
animation: none;
|
|
||||||
transform: translateY(0);
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<FlagProvider isInSubTable>
|
<FlagProvider isInSubTable>
|
||||||
<CollectionRecordProvider record={null} parentRecord={recordV2}>
|
<CollectionRecordProvider record={null} parentRecord={recordV2}>
|
||||||
<FormActiveFieldsProvider name="nester">
|
<FormActiveFieldsProvider name="nester">
|
||||||
<Table
|
{/* 在这里加,是为了让 “当前对象” 的配置显示正确 */}
|
||||||
className={css`
|
<SubFormProvider value={{ value: null, collection }}>
|
||||||
.ant-formily-item.ant-formily-item-feedback-layout-loose {
|
<Table
|
||||||
margin-bottom: 0px !important;
|
className={tableClassName}
|
||||||
|
bordered
|
||||||
|
size={'small'}
|
||||||
|
field={field}
|
||||||
|
showIndex
|
||||||
|
dragSort={false}
|
||||||
|
showDel={field.editable}
|
||||||
|
pagination={false}
|
||||||
|
rowSelection={{ type: 'none', hideSelectAll: true }}
|
||||||
|
footer={() =>
|
||||||
|
field.editable && (
|
||||||
|
<>
|
||||||
|
{field.componentProps?.allowAddnew !== false && (
|
||||||
|
<Button
|
||||||
|
type={'text'}
|
||||||
|
block
|
||||||
|
className={addNewButtonClassName}
|
||||||
|
onClick={() => {
|
||||||
|
field.value = field.value || [];
|
||||||
|
field.value.push(markRecordAsNew({}));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('Add new')}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{field.componentProps?.allowSelectExistingRecord && (
|
||||||
|
<Button
|
||||||
|
type={'text'}
|
||||||
|
block
|
||||||
|
className={selectButtonClassName}
|
||||||
|
onClick={() => {
|
||||||
|
setVisibleSelector(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('Select')}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
.ant-formily-editable {
|
isSubTable={true}
|
||||||
vertical-align: sub;
|
/>
|
||||||
}
|
</SubFormProvider>
|
||||||
.ant-table-footer {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
bordered
|
|
||||||
size={'small'}
|
|
||||||
field={field}
|
|
||||||
showIndex
|
|
||||||
dragSort={false}
|
|
||||||
showDel={field.editable}
|
|
||||||
pagination={false}
|
|
||||||
rowSelection={{ type: 'none', hideSelectAll: true }}
|
|
||||||
footer={() =>
|
|
||||||
field.editable && (
|
|
||||||
<>
|
|
||||||
{field.componentProps?.allowAddnew !== false && (
|
|
||||||
<Button
|
|
||||||
type={'text'}
|
|
||||||
block
|
|
||||||
className={css`
|
|
||||||
display: block;
|
|
||||||
border-radius: 0px;
|
|
||||||
border-right: 1px solid rgba(0, 0, 0, 0.06);
|
|
||||||
`}
|
|
||||||
onClick={() => {
|
|
||||||
field.value = field.value || [];
|
|
||||||
field.value.push(markRecordAsNew({}));
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Add new')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
{field.componentProps?.allowSelectExistingRecord && (
|
|
||||||
<Button
|
|
||||||
type={'text'}
|
|
||||||
block
|
|
||||||
className={css`
|
|
||||||
display: block;
|
|
||||||
border-radius: 0px;
|
|
||||||
`}
|
|
||||||
onClick={() => {
|
|
||||||
setVisibleSelector(true);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('Select')}
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
isSubTable={true}
|
|
||||||
/>
|
|
||||||
</FormActiveFieldsProvider>
|
</FormActiveFieldsProvider>
|
||||||
</CollectionRecordProvider>
|
</CollectionRecordProvider>
|
||||||
</FlagProvider>
|
</FlagProvider>
|
||||||
|
@ -22,7 +22,7 @@ import {
|
|||||||
SchemaSettingsSubMenu,
|
SchemaSettingsSubMenu,
|
||||||
useAPIClient,
|
useAPIClient,
|
||||||
useDesignable,
|
useDesignable,
|
||||||
useURLAndParamsSchema,
|
useURLAndHTMLSchema,
|
||||||
} from '../../../';
|
} from '../../../';
|
||||||
|
|
||||||
const toItems = (properties = {}) => {
|
const toItems = (properties = {}) => {
|
||||||
@ -61,7 +61,7 @@ const InsertMenuItems = (props) => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
const { urlSchema, paramsSchema } = useURLAndParamsSchema();
|
const { urlSchema, paramsSchema } = useURLAndHTMLSchema();
|
||||||
const isSubMenu = fieldSchema['x-component'] === 'Menu.SubMenu';
|
const isSubMenu = fieldSchema['x-component'] === 'Menu.SubMenu';
|
||||||
if (!isSubMenu && insertPosition === 'beforeEnd') {
|
if (!isSubMenu && insertPosition === 'beforeEnd') {
|
||||||
return null;
|
return null;
|
||||||
@ -220,7 +220,7 @@ export const MenuDesigner = () => {
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const menuSchema = findMenuSchema(fieldSchema);
|
const menuSchema = findMenuSchema(fieldSchema);
|
||||||
const compile = useCompile();
|
const compile = useCompile();
|
||||||
const { urlSchema, paramsSchema } = useURLAndParamsSchema();
|
const { urlSchema, paramsSchema } = useURLAndHTMLSchema();
|
||||||
const onSelect = useMemo(
|
const onSelect = useMemo(
|
||||||
() => compile(menuSchema?.['x-component-props']?.['onSelect']),
|
() => compile(menuSchema?.['x-component-props']?.['onSelect']),
|
||||||
[menuSchema?.['x-component-props']?.['onSelect']],
|
[menuSchema?.['x-component-props']?.['onSelect']],
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
import { Schema } from '@formily/json-schema';
|
import { Schema } from '@formily/json-schema';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { CollectionFieldOptions_deprecated } from '../../../collection-manager';
|
import { CollectionFieldOptions_deprecated } from '../../../collection-manager';
|
||||||
|
import { useCollection } from '../../../data-source';
|
||||||
import { CollectionFieldOptions } from '../../../data-source/collection/Collection';
|
import { CollectionFieldOptions } from '../../../data-source/collection/Collection';
|
||||||
import { useFlag } from '../../../flag-provider';
|
import { useFlag } from '../../../flag-provider';
|
||||||
import { useSubFormValue } from '../../../schema-component/antd/association-field/hooks';
|
import { useSubFormValue } from '../../../schema-component/antd/association-field/hooks';
|
||||||
import { useBaseVariable } from './useBaseVariable';
|
import { useBaseVariable } from './useBaseVariable';
|
||||||
import { useCollection } from '../../../data-source';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
|
@ -7,8 +7,13 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否是完整的 URL(带协议的)
|
||||||
|
* @param string
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
export function isURL(string) {
|
export function isURL(string) {
|
||||||
let url;
|
let url: URL;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
url = new URL(string);
|
url = new URL(string);
|
||||||
|
@ -17,7 +17,7 @@ import {
|
|||||||
useDesignable,
|
useDesignable,
|
||||||
useFormBlockContext,
|
useFormBlockContext,
|
||||||
useRecord,
|
useRecord,
|
||||||
useURLAndParamsSchema,
|
useURLAndHTMLSchema,
|
||||||
useVariableOptions,
|
useVariableOptions,
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
@ -65,7 +65,7 @@ const commonOptions: any = {
|
|||||||
return data?.data;
|
return data?.data;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const { urlSchema, paramsSchema } = useURLAndParamsSchema();
|
const { urlSchema, paramsSchema } = useURLAndHTMLSchema();
|
||||||
const submitHandler = async ({ mode, url, html, height, params }) => {
|
const submitHandler = async ({ mode, url, html, height, params }) => {
|
||||||
const componentProps = fieldSchema['x-component-props'] || {};
|
const componentProps = fieldSchema['x-component-props'] || {};
|
||||||
componentProps['mode'] = mode;
|
componentProps['mode'] = mode;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user