mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-07-02 03:02:19 +08:00
Merge branch 'next' into develop
This commit is contained in:
commit
7eb262670c
@ -203,6 +203,12 @@ export function useCollectValuesToSubmit() {
|
||||
]);
|
||||
}
|
||||
|
||||
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 = () => {
|
||||
const filterByTk = useFilterByTk();
|
||||
const record = useCollectionRecord();
|
||||
@ -219,11 +225,20 @@ export const useCreateActionProps = () => {
|
||||
const collectValues = useCollectValuesToSubmit();
|
||||
const action = record.isNew ? actionField.componentProps.saveMode || 'create' : 'update';
|
||||
const filterKeys = actionField.componentProps.filterKeys?.checked || [];
|
||||
const localVariables = useLocalVariables();
|
||||
const variables = useVariables();
|
||||
|
||||
return {
|
||||
async onClick() {
|
||||
const { onSuccess, skipValidator, triggerWorkflows } = actionSchema?.['x-action-settings'] ?? {};
|
||||
const { manualClose, redirecting, redirectTo, successMessage, actionAfterSuccess } = onSuccess || {};
|
||||
const {
|
||||
manualClose,
|
||||
redirecting,
|
||||
redirectTo: rawRedirectTo,
|
||||
successMessage,
|
||||
actionAfterSuccess,
|
||||
} = onSuccess || {};
|
||||
|
||||
if (!skipValidator) {
|
||||
await form.submit();
|
||||
}
|
||||
@ -241,6 +256,15 @@ export const useCreateActionProps = () => {
|
||||
: undefined,
|
||||
updateAssociationValues,
|
||||
});
|
||||
let redirectTo = rawRedirectTo;
|
||||
if (rawRedirectTo) {
|
||||
const { exp, scope: expScope } = await replaceVariables(rawRedirectTo, {
|
||||
variables,
|
||||
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(data?.data?.data, {}) }],
|
||||
});
|
||||
redirectTo = interpolateVariables(exp, expScope);
|
||||
}
|
||||
|
||||
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
||||
setVisible?.(false);
|
||||
}
|
||||
@ -588,7 +612,13 @@ export const useCustomizeUpdateActionProps = () => {
|
||||
skipValidator,
|
||||
triggerWorkflows,
|
||||
} = actionSchema?.['x-action-settings'] ?? {};
|
||||
const { manualClose, redirecting, redirectTo, successMessage, actionAfterSuccess } = onSuccess || {};
|
||||
const {
|
||||
manualClose,
|
||||
redirecting,
|
||||
redirectTo: rawRedirectTo,
|
||||
successMessage,
|
||||
actionAfterSuccess,
|
||||
} = onSuccess || {};
|
||||
const assignedValues = {};
|
||||
const waitList = Object.keys(originalAssignedValues).map(async (key) => {
|
||||
const value = originalAssignedValues[key];
|
||||
@ -614,7 +644,7 @@ export const useCustomizeUpdateActionProps = () => {
|
||||
if (skipValidator === false) {
|
||||
await form.submit();
|
||||
}
|
||||
await resource.update({
|
||||
const result = await resource.update({
|
||||
filterByTk,
|
||||
values: { ...assignedValues },
|
||||
// TODO(refactor): should change to inject by plugin
|
||||
@ -622,6 +652,16 @@ export const useCustomizeUpdateActionProps = () => {
|
||||
? triggerWorkflows.map((row) => [row.workflowKey, row.context].filter(Boolean).join('!')).join(',')
|
||||
: undefined,
|
||||
});
|
||||
|
||||
let redirectTo = rawRedirectTo;
|
||||
if (rawRedirectTo) {
|
||||
const { exp, scope: expScope } = await replaceVariables(rawRedirectTo, {
|
||||
variables,
|
||||
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(result?.data?.data?.[0], {}) }],
|
||||
});
|
||||
redirectTo = interpolateVariables(exp, expScope);
|
||||
}
|
||||
|
||||
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
||||
setVisible?.(false);
|
||||
}
|
||||
@ -913,7 +953,13 @@ export const useUpdateActionProps = () => {
|
||||
skipValidator,
|
||||
triggerWorkflows,
|
||||
} = actionSchema?.['x-action-settings'] ?? {};
|
||||
const { manualClose, redirecting, redirectTo, successMessage, actionAfterSuccess } = onSuccess || {};
|
||||
const {
|
||||
manualClose,
|
||||
redirecting,
|
||||
redirectTo: rawRedirectTo,
|
||||
successMessage,
|
||||
actionAfterSuccess,
|
||||
} = onSuccess || {};
|
||||
const assignedValues = {};
|
||||
const waitList = Object.keys(originalAssignedValues).map(async (key) => {
|
||||
const value = originalAssignedValues[key];
|
||||
@ -952,7 +998,7 @@ export const useUpdateActionProps = () => {
|
||||
actionField.data = field.data || {};
|
||||
actionField.data.loading = true;
|
||||
try {
|
||||
await resource.update({
|
||||
const result = await resource.update({
|
||||
filterByTk,
|
||||
values: {
|
||||
...values,
|
||||
@ -971,6 +1017,15 @@ export const useUpdateActionProps = () => {
|
||||
if (callBack) {
|
||||
callBack?.();
|
||||
}
|
||||
let redirectTo = rawRedirectTo;
|
||||
if (rawRedirectTo) {
|
||||
const { exp, scope: expScope } = await replaceVariables(rawRedirectTo, {
|
||||
variables,
|
||||
localVariables: [...localVariables, { name: '$record', ctx: new Proxy(result?.data?.data?.[0], {}) }],
|
||||
});
|
||||
redirectTo = interpolateVariables(exp, expScope);
|
||||
}
|
||||
|
||||
if (actionAfterSuccess === 'previous' || (!actionAfterSuccess && redirecting !== true)) {
|
||||
setVisible?.(false);
|
||||
}
|
||||
|
@ -157,6 +157,8 @@ export const useCollectionFilterOptions = (collection: any, dataSource?: string)
|
||||
const option = {
|
||||
name: field.name,
|
||||
title: field?.uiSchema?.title || field.name,
|
||||
label: field?.uiSchema?.title || field.name,
|
||||
value: field.name,
|
||||
schema: field?.uiSchema,
|
||||
operators:
|
||||
operators?.filter?.((operator) => {
|
||||
|
@ -1094,5 +1094,6 @@
|
||||
"Font Size(px)": "字体大小(像素)",
|
||||
"Font Weight": "字体粗细",
|
||||
"Font Style": "字体样式",
|
||||
"Italic": "斜体"
|
||||
"Italic": "斜体",
|
||||
"Response record":"响应结果记录"
|
||||
}
|
||||
|
@ -34,6 +34,8 @@ import {
|
||||
import { DefaultValueProvider } from '../../../schema-settings/hooks/useIsAllowToSetDefaultValue';
|
||||
import { useLinkageAction } from './hooks';
|
||||
import { requestSettingsSchema } from './utils';
|
||||
import { useAfterSuccessOptions } from './hooks/useGetAfterSuccessVariablesOptions';
|
||||
import { useGlobalVariable } from '../../../application/hooks/useGlobalVariable';
|
||||
|
||||
const MenuGroup = (props) => {
|
||||
return props.children;
|
||||
@ -280,11 +282,24 @@ export function SkipValidation() {
|
||||
);
|
||||
}
|
||||
|
||||
const fieldNames = {
|
||||
value: 'value',
|
||||
label: 'label',
|
||||
};
|
||||
const useVariableProps = (environmentVariables) => {
|
||||
const scope = useAfterSuccessOptions();
|
||||
return {
|
||||
scope: [environmentVariables, ...scope].filter(Boolean),
|
||||
fieldNames,
|
||||
};
|
||||
};
|
||||
|
||||
export function AfterSuccess() {
|
||||
const { dn } = useDesignable();
|
||||
const { t } = useTranslation();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const { onSuccess } = fieldSchema?.['x-action-settings'] || {};
|
||||
const environmentVariables = useGlobalVariable('$env');
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
title={t('After successful submission')}
|
||||
@ -363,8 +378,9 @@ export function AfterSuccess() {
|
||||
redirectTo: {
|
||||
title: t('Link'),
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-component-props': {},
|
||||
'x-component': 'Variable.TextArea',
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
'x-use-component-props': () => useVariableProps(environmentVariables),
|
||||
},
|
||||
},
|
||||
} as ISchema
|
||||
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* 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 { useMemo } from 'react';
|
||||
import { useCollection_deprecated, useCollectionFilterOptions } from '../../../../collection-manager';
|
||||
import { useCollectionRecordData } from '../../../../data-source';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useCompile } from '../../../';
|
||||
import { useBlockContext } from '../../../../block-provider/BlockProvider';
|
||||
import { usePopupVariable } from '../../../../schema-settings/VariableInput/hooks';
|
||||
import { useCurrentRoleVariable } from '../../../../schema-settings/VariableInput/hooks';
|
||||
|
||||
export const useAfterSuccessOptions = () => {
|
||||
const collection = useCollection_deprecated();
|
||||
const { t } = useTranslation();
|
||||
const fieldsOptions = useCollectionFilterOptions(collection);
|
||||
const userFieldOptions = useCollectionFilterOptions('users', 'main');
|
||||
const compile = useCompile();
|
||||
const recordData = useCollectionRecordData();
|
||||
const { name: blockType } = useBlockContext() || {};
|
||||
const [fields, userFields] = useMemo(() => {
|
||||
return [compile(fieldsOptions), compile(userFieldOptions)];
|
||||
}, [fieldsOptions, userFieldOptions]);
|
||||
const { settings: popupRecordSettings, shouldDisplayPopupRecord } = usePopupVariable();
|
||||
const { currentRoleSettings } = useCurrentRoleVariable();
|
||||
const record = useCollectionRecordData();
|
||||
return useMemo(() => {
|
||||
return [
|
||||
(record || blockType === 'form') && {
|
||||
value: '$record',
|
||||
label: t('Response record', { ns: 'client' }),
|
||||
children: [...fields],
|
||||
},
|
||||
recordData && {
|
||||
value: 'currentRecord',
|
||||
label: t('Current record', { ns: 'client' }),
|
||||
children: [...fields],
|
||||
},
|
||||
shouldDisplayPopupRecord && {
|
||||
...popupRecordSettings,
|
||||
},
|
||||
{
|
||||
value: 'currentUser',
|
||||
label: t('Current user', { ns: 'client' }),
|
||||
children: userFields,
|
||||
},
|
||||
currentRoleSettings,
|
||||
{
|
||||
value: 'currentTime',
|
||||
label: t('Current time', { ns: 'client' }),
|
||||
children: null,
|
||||
},
|
||||
{
|
||||
value: '$nToken',
|
||||
label: 'API token',
|
||||
children: null,
|
||||
},
|
||||
].filter(Boolean);
|
||||
}, [recordData, t, fields, blockType, userFields]);
|
||||
};
|
@ -16,5 +16,6 @@ export * from './hooks/useGetAriaLabelOfAction';
|
||||
export * from './hooks/useGetAriaLabelOfDrawer';
|
||||
export * from './hooks/useGetAriaLabelOfModal';
|
||||
export * from './hooks/useGetAriaLabelOfPopover';
|
||||
export * from './hooks/useGetAfterSuccessVariablesOptions';
|
||||
export * from './types';
|
||||
export * from './zIndexContext';
|
||||
|
@ -8,7 +8,6 @@
|
||||
*/
|
||||
|
||||
import { ISchema, useFieldSchema } from '@formily/react';
|
||||
import { isValid } from '@formily/shared';
|
||||
import {
|
||||
ActionDesigner,
|
||||
SchemaSettings,
|
||||
@ -19,6 +18,8 @@ import {
|
||||
useDesignable,
|
||||
useSchemaToolbar,
|
||||
RefreshDataBlockRequest,
|
||||
useAfterSuccessOptions,
|
||||
useGlobalVariable,
|
||||
} from '@nocobase/client';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import React from 'react';
|
||||
@ -49,11 +50,22 @@ function UpdateMode() {
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const fieldNames = {
|
||||
value: 'value',
|
||||
label: 'label',
|
||||
};
|
||||
const useVariableProps = (environmentVariables) => {
|
||||
const scope = useAfterSuccessOptions();
|
||||
return {
|
||||
scope: [environmentVariables, ...scope].filter(Boolean),
|
||||
fieldNames,
|
||||
};
|
||||
};
|
||||
function AfterSuccess() {
|
||||
const { dn } = useDesignable();
|
||||
const { t } = useTranslation();
|
||||
const fieldSchema = useFieldSchema();
|
||||
const environmentVariables = useGlobalVariable('$env');
|
||||
return (
|
||||
<SchemaSettingsModalItem
|
||||
title={t('After successful submission')}
|
||||
@ -100,8 +112,9 @@ function AfterSuccess() {
|
||||
redirectTo: {
|
||||
title: t('Link'),
|
||||
'x-decorator': 'FormItem',
|
||||
'x-component': 'Input',
|
||||
'x-component-props': {},
|
||||
'x-component': 'Variable.TextArea',
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
'x-use-component-props': () => useVariableProps(environmentVariables),
|
||||
},
|
||||
},
|
||||
} as ISchema
|
||||
|
Loading…
x
Reference in New Issue
Block a user