mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 05:29:26 +08:00
Merge branch 'next' into develop
This commit is contained in:
commit
461525353b
@ -72,7 +72,7 @@ describe('SchemaInitializerDivider', () => {
|
|||||||
expect(onSubmit).toBeCalled();
|
expect(onSubmit).toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('item mode', async () => {
|
it.skip('item mode', async () => {
|
||||||
const onSubmit = vitest.fn();
|
const onSubmit = vitest.fn();
|
||||||
const Demo = () => {
|
const Demo = () => {
|
||||||
return (
|
return (
|
||||||
|
@ -52,6 +52,7 @@ import { useBlockRequestContext, useFilterByTk, useParamsFromRecord } from '../B
|
|||||||
import { useOperators } from '../CollectOperators';
|
import { useOperators } from '../CollectOperators';
|
||||||
import { useDetailsBlockContext } from '../DetailsBlockProvider';
|
import { useDetailsBlockContext } from '../DetailsBlockProvider';
|
||||||
import { TableFieldResource } from '../TableFieldProvider';
|
import { TableFieldResource } from '../TableFieldProvider';
|
||||||
|
import { getVariableValue } from '../../common/getVariableValue';
|
||||||
|
|
||||||
export * from './useBlockHeightProps';
|
export * from './useBlockHeightProps';
|
||||||
export * from './useDataBlockParentRecord';
|
export * from './useDataBlockParentRecord';
|
||||||
@ -232,12 +233,6 @@ export function useCollectValuesToSubmit() {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function interpolateVariables(str: string, scope: Record<string, any>): string {
|
|
||||||
return str.replace(/\{\{\s*([a-zA-Z0-9_$.-]+?)\s*\}\}/g, (_, key) => {
|
|
||||||
return scope[key] !== undefined ? String(scope[key]) : '';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const useCreateActionProps = () => {
|
export const useCreateActionProps = () => {
|
||||||
const filterByTk = useFilterByTk();
|
const filterByTk = useFilterByTk();
|
||||||
const record = useCollectionRecord();
|
const record = useCollectionRecord();
|
||||||
@ -287,11 +282,10 @@ export const useCreateActionProps = () => {
|
|||||||
});
|
});
|
||||||
let redirectTo = rawRedirectTo;
|
let redirectTo = rawRedirectTo;
|
||||||
if (rawRedirectTo) {
|
if (rawRedirectTo) {
|
||||||
const { exp, scope: expScope } = await replaceVariables(rawRedirectTo, {
|
redirectTo = await getVariableValue(rawRedirectTo, {
|
||||||
variables,
|
variables,
|
||||||
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(data?.data?.data, {}) }],
|
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(data?.data?.data, {}) }],
|
||||||
});
|
});
|
||||||
redirectTo = interpolateVariables(exp, expScope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
||||||
@ -686,11 +680,11 @@ export const useCustomizeUpdateActionProps = () => {
|
|||||||
|
|
||||||
let redirectTo = rawRedirectTo;
|
let redirectTo = rawRedirectTo;
|
||||||
if (rawRedirectTo) {
|
if (rawRedirectTo) {
|
||||||
const { exp, scope: expScope } = await replaceVariables(rawRedirectTo, {
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
redirectTo = await getVariableValue(rawRedirectTo, {
|
||||||
variables,
|
variables,
|
||||||
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(result?.data?.data?.[0], {}) }],
|
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(result?.data?.data, {}) }],
|
||||||
});
|
});
|
||||||
redirectTo = interpolateVariables(exp, expScope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
||||||
@ -1050,11 +1044,11 @@ export const useUpdateActionProps = () => {
|
|||||||
}
|
}
|
||||||
let redirectTo = rawRedirectTo;
|
let redirectTo = rawRedirectTo;
|
||||||
if (rawRedirectTo) {
|
if (rawRedirectTo) {
|
||||||
const { exp, scope: expScope } = await replaceVariables(rawRedirectTo, {
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||||
|
redirectTo = await getVariableValue(rawRedirectTo, {
|
||||||
variables,
|
variables,
|
||||||
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(result?.data?.data?.[0], {}) }],
|
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(result?.data?.data, {}) }],
|
||||||
});
|
});
|
||||||
redirectTo = interpolateVariables(exp, expScope);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
||||||
|
23
packages/core/client/src/common/getVariableValue.ts
Normal file
23
packages/core/client/src/common/getVariableValue.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/**
|
||||||
|
* 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 { evaluators } from '@nocobase/evaluators/client';
|
||||||
|
import { replaceVariables } from '../schema-settings/LinkageRules/bindLinkageRulesToFiled';
|
||||||
|
|
||||||
|
export const getVariableValue = async (text: string, scopes) => {
|
||||||
|
if (!text) {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { evaluate } = evaluators.get('string');
|
||||||
|
|
||||||
|
const { exp, scope: expScope } = await replaceVariables(text, scopes);
|
||||||
|
const result = evaluate(exp, { now: () => new Date().toString(), ...expScope });
|
||||||
|
return result;
|
||||||
|
};
|
@ -10,3 +10,4 @@
|
|||||||
export * from './AppNotFound';
|
export * from './AppNotFound';
|
||||||
export * from './SelectWithTitle';
|
export * from './SelectWithTitle';
|
||||||
export * from './useFieldComponentName';
|
export * from './useFieldComponentName';
|
||||||
|
export * from './getVariableValue';
|
||||||
|
@ -31,7 +31,11 @@ test.describe('Link', () => {
|
|||||||
await expect(
|
await expect(
|
||||||
page.getByRole('button', { name: 'designer-schema-settings-Action.Link-actionSettings:link-users' }),
|
page.getByRole('button', { name: 'designer-schema-settings-Action.Link-actionSettings:link-users' }),
|
||||||
).toHaveCount(1);
|
).toHaveCount(1);
|
||||||
await page.getByRole('button', { name: 'designer-schema-settings-Action.Link-actionSettings:link-users' }).hover();
|
await page
|
||||||
|
.getByRole('button', { name: 'designer-schema-settings-Action.Link-actionSettings:link-users' })
|
||||||
|
.first()
|
||||||
|
.hover();
|
||||||
|
await page.getByLabel('designer-schema-settings-Action.Link-actionSettings:link-users').first().hover();
|
||||||
await page.getByRole('menuitem', { name: 'Edit link' }).click();
|
await page.getByRole('menuitem', { name: 'Edit link' }).click();
|
||||||
await page.getByLabel('block-item-users-URL').getByLabel('textbox').click();
|
await page.getByLabel('block-item-users-URL').getByLabel('textbox').click();
|
||||||
await page
|
await page
|
||||||
@ -106,7 +110,7 @@ test.describe('Link', () => {
|
|||||||
await page.getByLabel('block-item-users-URL').getByLabel('textbox').fill(otherPageUrl);
|
await page.getByLabel('block-item-users-URL').getByLabel('textbox').fill(otherPageUrl);
|
||||||
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
await page.getByRole('button', { name: 'OK', exact: true }).click();
|
||||||
|
|
||||||
await page.getByLabel('action-Action.Link-Link-').click();
|
await page.getByLabel('action-Action.Link-Link-').first().click();
|
||||||
expect(page.url().endsWith(otherPageUrl)).toBe(true);
|
expect(page.url().endsWith(otherPageUrl)).toBe(true);
|
||||||
|
|
||||||
// 开启 “Open in new window” 选项后,点击链接按钮会在新窗口打开
|
// 开启 “Open in new window” 选项后,点击链接按钮会在新窗口打开
|
||||||
|
@ -23,7 +23,7 @@ test.describe('options of Select field in linkage rule', () => {
|
|||||||
// 去掉联动规则恢复选项
|
// 去掉联动规则恢复选项
|
||||||
await page.getByLabel('block-item-CardItem-general-').hover();
|
await page.getByLabel('block-item-CardItem-general-').hover();
|
||||||
await page.getByLabel('designer-schema-settings-CardItem-blockSettings:createForm-general').hover();
|
await page.getByLabel('designer-schema-settings-CardItem-blockSettings:createForm-general').hover();
|
||||||
await page.getByRole('menuitem', { name: 'Linkage rules' }).click();
|
await page.getByRole('menuitem', { name: 'Field linkage rules' }).click();
|
||||||
await page.getByRole('switch', { name: 'On Off' }).click();
|
await page.getByRole('switch', { name: 'On Off' }).click();
|
||||||
await page.getByRole('button', { name: 'OK' }).click();
|
await page.getByRole('button', { name: 'OK' }).click();
|
||||||
await page.reload();
|
await page.reload();
|
||||||
|
@ -19,7 +19,8 @@ test('tabs', async ({ page, mockPage }) => {
|
|||||||
|
|
||||||
await page.getByText('tab 1').hover();
|
await page.getByText('tab 1').hover();
|
||||||
await page.getByRole('button', { name: 'designer-drag-handler-Page-tab' }).dragTo(page.getByText('tab 2'));
|
await page.getByRole('button', { name: 'designer-drag-handler-Page-tab' }).dragTo(page.getByText('tab 2'));
|
||||||
await expect(page.getByText('tab 1')).toBeVisible();
|
await page.waitForTimeout(500);
|
||||||
|
await expect(page.getByText('tab 2')).toBeVisible();
|
||||||
|
|
||||||
tab1Box = await page.getByText('tab 1').boundingBox();
|
tab1Box = await page.getByText('tab 1').boundingBox();
|
||||||
tab2Box = await page.getByText('tab 2').boundingBox();
|
tab2Box = await page.getByText('tab 2').boundingBox();
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* For more information, please refer to: https://www.nocobase.com/agreement.
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { ISchema, useField, useFieldSchema } from '@formily/react';
|
import { ISchema, useField, useFieldSchema, useForm } from '@formily/react';
|
||||||
import { isValid, uid } from '@formily/shared';
|
import { isValid, uid } from '@formily/shared';
|
||||||
import { ModalProps, Select } from 'antd';
|
import { ModalProps, Select } from 'antd';
|
||||||
import React, { useCallback, useMemo } from 'react';
|
import React, { useCallback, useMemo } from 'react';
|
||||||
@ -18,7 +18,12 @@ import { useGlobalVariable } from '../../../application/hooks/useGlobalVariable'
|
|||||||
import { SchemaSettingOptions, SchemaSettings } from '../../../application/schema-settings';
|
import { SchemaSettingOptions, SchemaSettings } from '../../../application/schema-settings';
|
||||||
import { useSchemaToolbar } from '../../../application/schema-toolbar';
|
import { useSchemaToolbar } from '../../../application/schema-toolbar';
|
||||||
import { useCollectionManager_deprecated, useCollection_deprecated } from '../../../collection-manager';
|
import { useCollectionManager_deprecated, useCollection_deprecated } from '../../../collection-manager';
|
||||||
import { highlightBlock, startScrollEndTracking, stopScrollEndTracking, unhighlightBlock } from '../../../filter-provider/highlightBlock';
|
import {
|
||||||
|
highlightBlock,
|
||||||
|
startScrollEndTracking,
|
||||||
|
stopScrollEndTracking,
|
||||||
|
unhighlightBlock,
|
||||||
|
} from '../../../filter-provider/highlightBlock';
|
||||||
import { FlagProvider } from '../../../flag-provider';
|
import { FlagProvider } from '../../../flag-provider';
|
||||||
import { SaveMode } from '../../../modules/actions/submit/createSubmitActionSettings';
|
import { SaveMode } from '../../../modules/actions/submit/createSubmitActionSettings';
|
||||||
import { useOpenModeContext } from '../../../modules/popup/OpenModeProvider';
|
import { useOpenModeContext } from '../../../modules/popup/OpenModeProvider';
|
||||||
@ -38,6 +43,8 @@ import { useAllDataBlocks } from '../page/AllDataBlocksProvider';
|
|||||||
import { useLinkageAction } from './hooks';
|
import { useLinkageAction } from './hooks';
|
||||||
import { useAfterSuccessOptions } from './hooks/useGetAfterSuccessVariablesOptions';
|
import { useAfterSuccessOptions } from './hooks/useGetAfterSuccessVariablesOptions';
|
||||||
import { requestSettingsSchema } from './utils';
|
import { requestSettingsSchema } from './utils';
|
||||||
|
import { useVariableOptions } from '../../../schema-settings/VariableInput/hooks/useVariableOptions';
|
||||||
|
import { useCollectionRecordData } from '../../../data-source';
|
||||||
|
|
||||||
const MenuGroup = (props) => {
|
const MenuGroup = (props) => {
|
||||||
return props.children;
|
return props.children;
|
||||||
@ -307,7 +314,7 @@ const hideDialog = (dialogClassName: string) => {
|
|||||||
dialogWrap.style.opacity = '0';
|
dialogWrap.style.opacity = '0';
|
||||||
dialogWrap.style.transition = 'opacity 0.5s ease';
|
dialogWrap.style.transition = 'opacity 0.5s ease';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const showDialog = (dialogClassName: string) => {
|
const showDialog = (dialogClassName: string) => {
|
||||||
const dialogMask = document.querySelector<HTMLElement>(`.${dialogClassName} > .ant-modal-mask`);
|
const dialogMask = document.querySelector<HTMLElement>(`.${dialogClassName} > .ant-modal-mask`);
|
||||||
@ -320,7 +327,7 @@ const showDialog = (dialogClassName: string) => {
|
|||||||
dialogWrap.style.opacity = '1';
|
dialogWrap.style.opacity = '1';
|
||||||
dialogWrap.style.transition = 'opacity 0.5s ease';
|
dialogWrap.style.transition = 'opacity 0.5s ease';
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export const BlocksSelector = (props) => {
|
export const BlocksSelector = (props) => {
|
||||||
const { getAllDataBlocks } = useAllDataBlocks();
|
const { getAllDataBlocks } = useAllDataBlocks();
|
||||||
@ -330,31 +337,33 @@ export const BlocksSelector = (props) => {
|
|||||||
|
|
||||||
// 转换 allDataBlocks 为 Select 选项
|
// 转换 allDataBlocks 为 Select 选项
|
||||||
const options = useMemo(() => {
|
const options = useMemo(() => {
|
||||||
return allDataBlocks.map(block => {
|
return allDataBlocks
|
||||||
// 防止列表中出现已关闭的弹窗中的区块
|
.map((block) => {
|
||||||
if (!block.dom?.isConnected) {
|
// 防止列表中出现已关闭的弹窗中的区块
|
||||||
return null;
|
if (!block.dom?.isConnected) {
|
||||||
}
|
return null;
|
||||||
|
|
||||||
const title = `${compile(block.collection.title)} #${block.uid.slice(0, 4)}`;
|
|
||||||
return {
|
|
||||||
label: title,
|
|
||||||
value: block.uid,
|
|
||||||
onMouseEnter() {
|
|
||||||
block.highlightBlock();
|
|
||||||
hideDialog('dialog-after-successful-submission');
|
|
||||||
startScrollEndTracking(block.dom, () => {
|
|
||||||
highlightBlock(block.dom.cloneNode(true) as HTMLElement, block.dom.getBoundingClientRect());
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onMouseLeave() {
|
|
||||||
block.unhighlightBlock();
|
|
||||||
showDialog('dialog-after-successful-submission');
|
|
||||||
stopScrollEndTracking(block.dom);
|
|
||||||
unhighlightBlock();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}).filter(Boolean);
|
const title = `${compile(block.collection.title)} #${block.uid.slice(0, 4)}`;
|
||||||
|
return {
|
||||||
|
label: title,
|
||||||
|
value: block.uid,
|
||||||
|
onMouseEnter() {
|
||||||
|
block.highlightBlock();
|
||||||
|
hideDialog('dialog-after-successful-submission');
|
||||||
|
startScrollEndTracking(block.dom, () => {
|
||||||
|
highlightBlock(block.dom.cloneNode(true) as HTMLElement, block.dom.getBoundingClientRect());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onMouseLeave() {
|
||||||
|
block.unhighlightBlock();
|
||||||
|
showDialog('dialog-after-successful-submission');
|
||||||
|
stopScrollEndTracking(block.dom);
|
||||||
|
unhighlightBlock();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(Boolean);
|
||||||
}, [allDataBlocks, t]);
|
}, [allDataBlocks, t]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -367,7 +376,7 @@ export const BlocksSelector = (props) => {
|
|||||||
onChange={props.onChange}
|
onChange={props.onChange}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
export function AfterSuccess() {
|
export function AfterSuccess() {
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
@ -380,21 +389,21 @@ export function AfterSuccess() {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SchemaSettingsModalItem
|
<SchemaSettingsModalItem
|
||||||
dialogRootClassName='dialog-after-successful-submission'
|
dialogRootClassName="dialog-after-successful-submission"
|
||||||
width={700}
|
width={700}
|
||||||
title={t('After successful submission')}
|
title={t('After successful submission')}
|
||||||
initialValues={
|
initialValues={
|
||||||
onSuccess
|
onSuccess
|
||||||
? {
|
? {
|
||||||
actionAfterSuccess: onSuccess?.redirecting ? 'redirect' : 'previous',
|
actionAfterSuccess: onSuccess?.redirecting ? 'redirect' : 'previous',
|
||||||
...onSuccess,
|
...onSuccess,
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
manualClose: false,
|
manualClose: false,
|
||||||
redirecting: false,
|
redirecting: false,
|
||||||
successMessage: '{{t("Saved successfully")}}',
|
successMessage: '{{t("Saved successfully")}}',
|
||||||
actionAfterSuccess: 'previous',
|
actionAfterSuccess: 'previous',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
schema={
|
schema={
|
||||||
{
|
{
|
||||||
@ -704,6 +713,20 @@ export const actionSettingsItems: SchemaSettingOptions['items'] = [
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const useSecondConFirmVariables = () => {
|
||||||
|
const fieldSchema = useFieldSchema();
|
||||||
|
const form = useForm();
|
||||||
|
const record = useCollectionRecordData();
|
||||||
|
const scope = useVariableOptions({
|
||||||
|
collectionField: { uiSchema: fieldSchema },
|
||||||
|
form,
|
||||||
|
record,
|
||||||
|
uiSchema: fieldSchema,
|
||||||
|
noDisabled: true,
|
||||||
|
});
|
||||||
|
return scope;
|
||||||
|
};
|
||||||
export function SecondConFirm() {
|
export function SecondConFirm() {
|
||||||
const { dn } = useDesignable();
|
const { dn } = useDesignable();
|
||||||
const fieldSchema = useFieldSchema();
|
const fieldSchema = useFieldSchema();
|
||||||
@ -738,9 +761,11 @@ export function SecondConFirm() {
|
|||||||
},
|
},
|
||||||
title: {
|
title: {
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Input.TextArea',
|
'x-component': 'Variable.RawTextArea',
|
||||||
title: t('Title'),
|
title: t('Title'),
|
||||||
|
'x-component-props': {
|
||||||
|
scope: useSecondConFirmVariables,
|
||||||
|
},
|
||||||
'x-reactions': {
|
'x-reactions': {
|
||||||
dependencies: ['enable'],
|
dependencies: ['enable'],
|
||||||
fulfill: {
|
fulfill: {
|
||||||
@ -752,8 +777,11 @@ export function SecondConFirm() {
|
|||||||
},
|
},
|
||||||
content: {
|
content: {
|
||||||
'x-decorator': 'FormItem',
|
'x-decorator': 'FormItem',
|
||||||
'x-component': 'Input.TextArea',
|
'x-component': 'Variable.RawTextArea',
|
||||||
title: t('Content'),
|
title: t('Content'),
|
||||||
|
'x-component-props': {
|
||||||
|
scope: useSecondConFirmVariables,
|
||||||
|
},
|
||||||
'x-reactions': {
|
'x-reactions': {
|
||||||
dependencies: ['enable'],
|
dependencies: ['enable'],
|
||||||
fulfill: {
|
fulfill: {
|
||||||
|
@ -50,6 +50,7 @@ import { ActionContextProps, ActionProps, ComposedAction } from './types';
|
|||||||
import { linkageAction, setInitialActionState } from './utils';
|
import { linkageAction, setInitialActionState } from './utils';
|
||||||
import { NAMESPACE_UI_SCHEMA } from '../../../i18n/constant';
|
import { NAMESPACE_UI_SCHEMA } from '../../../i18n/constant';
|
||||||
import { BlockContext } from '../../../block-provider/BlockProvider';
|
import { BlockContext } from '../../../block-provider/BlockProvider';
|
||||||
|
import { getVariableValue } from '../../../common/getVariableValue';
|
||||||
|
|
||||||
// 这个要放到最下面,否则会导致前端单测失败
|
// 这个要放到最下面,否则会导致前端单测失败
|
||||||
import { useApp } from '../../../application';
|
import { useApp } from '../../../application';
|
||||||
@ -450,18 +451,24 @@ const RenderButton = ({
|
|||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { isPopupVisibleControlledByURL } = usePopupSettings();
|
const { isPopupVisibleControlledByURL } = usePopupSettings();
|
||||||
const { openPopup } = usePopupUtils();
|
const { openPopup } = usePopupUtils();
|
||||||
|
const variables = useVariables();
|
||||||
|
const localVariables = useLocalVariables();
|
||||||
const openPopupRef = useRef(null);
|
const openPopupRef = useRef(null);
|
||||||
openPopupRef.current = openPopup;
|
openPopupRef.current = openPopup;
|
||||||
|
const scopes = {
|
||||||
|
variables,
|
||||||
|
localVariables,
|
||||||
|
};
|
||||||
|
|
||||||
const handleButtonClick = useCallback(
|
const handleButtonClick = useCallback(
|
||||||
(e: React.MouseEvent, checkPortal = true) => {
|
async (e: React.MouseEvent, checkPortal = true) => {
|
||||||
if (checkPortal && isPortalInBody(e.target as Element)) {
|
if (checkPortal && isPortalInBody(e.target as Element)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
const resultTitle = await getVariableValue(confirm?.title, scopes);
|
||||||
|
const resultContent = await getVariableValue(confirm?.content, scopes);
|
||||||
if (!disabled && aclCtx) {
|
if (!disabled && aclCtx) {
|
||||||
const onOk = () => {
|
const onOk = () => {
|
||||||
if (onClick) {
|
if (onClick) {
|
||||||
@ -489,8 +496,8 @@ const RenderButton = ({
|
|||||||
};
|
};
|
||||||
if (confirm?.enable !== false && confirm?.content) {
|
if (confirm?.enable !== false && confirm?.content) {
|
||||||
modal.confirm({
|
modal.confirm({
|
||||||
title: t(confirm.title, { title: confirmTitle || title || field?.title }),
|
title: t(resultTitle, { title: confirmTitle || title || field?.title }),
|
||||||
content: t(confirm.content, { title: confirmTitle || title || field?.title }),
|
content: t(resultContent, { title: confirmTitle || title || field?.title }),
|
||||||
onOk,
|
onOk,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -46,6 +46,7 @@ export function AccessControl() {
|
|||||||
'x-decorator': 'ACLActionProvider',
|
'x-decorator': 'ACLActionProvider',
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
fieldSchema['x-decorator'] = 'ACLActionProvider';
|
||||||
dn.refresh();
|
dn.refresh();
|
||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
@ -20,8 +20,7 @@ import {
|
|||||||
useContextVariable,
|
useContextVariable,
|
||||||
useLocalVariables,
|
useLocalVariables,
|
||||||
useVariables,
|
useVariables,
|
||||||
replaceVariables,
|
getVariableValue,
|
||||||
interpolateVariables,
|
|
||||||
} from '@nocobase/client';
|
} from '@nocobase/client';
|
||||||
import { isURL } from '@nocobase/utils/client';
|
import { isURL } from '@nocobase/utils/client';
|
||||||
import { App } from 'antd';
|
import { App } from 'antd';
|
||||||
@ -84,19 +83,13 @@ export const useCustomizeRequestActionProps = () => {
|
|||||||
},
|
},
|
||||||
responseType: fieldSchema['x-response-type'] === 'stream' ? 'blob' : 'json',
|
responseType: fieldSchema['x-response-type'] === 'stream' ? 'blob' : 'json',
|
||||||
});
|
});
|
||||||
try {
|
successMessage = await getVariableValue(successMessage, {
|
||||||
const { exp, scope: expScope } = await replaceVariables(successMessage, {
|
variables,
|
||||||
variables,
|
localVariables: [
|
||||||
localVariables: [
|
...localVariables,
|
||||||
...localVariables,
|
{ name: '$nResponse', ctx: new Proxy({ ...res?.data?.data, ...res?.data }, {}) },
|
||||||
{ name: '$nResponse', ctx: new Proxy({ ...res?.data?.data, ...res?.data }, {}) },
|
],
|
||||||
],
|
});
|
||||||
});
|
|
||||||
successMessage = interpolateVariables(exp, expScope);
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.headers['content-disposition']) {
|
if (res.headers['content-disposition']) {
|
||||||
const contentDisposition = res.headers['content-disposition'];
|
const contentDisposition = res.headers['content-disposition'];
|
||||||
const utf8Match = contentDisposition.match(/filename\*=utf-8''([^;]+)/i);
|
const utf8Match = contentDisposition.match(/filename\*=utf-8''([^;]+)/i);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user