Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions packages/base/src/page/Transit/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ describe('Transit Component', () => {
console.error = originOutputError;
});

it('should wait until user info is fetched before resolving project', () => {
mockUseCurrentUser({
isUserInfoFetched: false,
bindProjects: []
});
mockExtractQueries.mockReturnValue({
from: 'cloudbeaver',
to: 'create_workflow',
project_name: 'default',
compression_data: 'data'
});
superRender(<Transit />);
expect(mockNavigate).not.toHaveBeenCalled();
});

it('should navigate to / when required parameters are missing', () => {
mockExtractQueries.mockReturnValue({
from: 'cloudbeaver'
Expand Down
19 changes: 14 additions & 5 deletions packages/base/src/page/Transit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ const TARGET_DATA = (

const Transit: React.FC = () => {
const navigate = useTypedNavigate();
const { bindProjects } = useCurrentUser();
const { bindProjects, isUserInfoFetched } = useCurrentUser();
const extractQueries = useTypedQuery();
useEffect(() => {
const searchParams = extractQueries(ROUTE_PATHS.BASE.TRANSIT.index);
Expand All @@ -51,6 +51,9 @@ const Transit: React.FC = () => {
const compressionData = searchParams?.compression_data;
const projectName = searchParams?.project_name;
const workflowId = searchParams?.workflow_id;
if (!isUserInfoFetched) {
return;
}
if (!from || !to) {
console.error(`Missing required parameters!\n from=${from}\n to=${to}\n`);
navigate(ROUTE_PATHS.BASE.HOME, {
Expand Down Expand Up @@ -85,9 +88,15 @@ const Transit: React.FC = () => {
return;
}
if (compressionData) {
navigate(`${path}?from=${from}&compression_data=${compressionData}`, {
replace: true
});
// useTypedQuery / URLSearchParams 已解码;再拼 URL 必须重新编码,否则 + 变空格破坏预填
navigate(
`${path}?from=${encodeURIComponent(
from
)}&compression_data=${encodeURIComponent(compressionData)}`,
{
replace: true
}
);
} else {
navigate(path, {
replace: true
Expand All @@ -99,7 +108,7 @@ const Transit: React.FC = () => {
replace: true
});
}
}, [bindProjects, navigate, extractQueries]);
}, [bindProjects, isUserInfoFetched, navigate, extractQueries]);
return <HeaderProgress />;
};
export default Transit;
48 changes: 43 additions & 5 deletions packages/dms-kit/src/utils/Common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,26 +84,64 @@ export type GetErrorMessageParams =
| string
| AxiosResponse
| ISwaggerLoseRequireParamsRes;

const BUSINESS_ERROR_I18N_KEYS: Record<string, string> = {
'privilege_apply.no_assignee': 'privilegeApply.create.errors.noAssignee',
'privilege_apply.account_mismatch':
'privilegeApply.create.errors.accountMismatch',
'privilege_apply.invalid_argument':
'privilegeApply.create.errors.invalidArgument',
'privilege_apply.duplicate_open':
'privilegeApply.create.errors.duplicateOpen',
'privilege_apply.invalid_account_name':
'privilegeApply.create.errors.invalidAccountName',
'privilege_apply.forbidden': 'privilegeApply.detail.errors.forbidden'
};

const BUSINESS_ERROR_FALLBACK_ZH: Record<string, string> = {
'privilege_apply.no_assignee': '请先配置提权审批人后再提交(未落单)',
'privilege_apply.account_mismatch':
'当前连库账号已变更,请回到工作台刷新后重新申请',
'privilege_apply.invalid_argument': '请完善必填项后重试',
'privilege_apply.duplicate_open':
'该数据源已有进行中的提权申请,请等待处理完成后再提交',
'privilege_apply.invalid_account_name':
'新账号名不合法:仅支持字母开头,字母、数字、下划线、连字符与点,最长 32 字符',
'privilege_apply.forbidden': '没有账号管理权限,无法审批该提权申请'
};

const mapBusinessErrorMessage = (message: string): string => {
const i18nKey = BUSINESS_ERROR_I18N_KEYS[message];
if (!i18nKey) {
return message;
}
const translated = i18n.t(i18nKey);
if (translated && translated !== i18nKey) {
return translated;
}
return BUSINESS_ERROR_FALLBACK_ZH[message] || message;
};

export const getErrorMessage = (error: GetErrorMessageParams): string => {
if (typeof error === 'string') {
return error;
return mapBusinessErrorMessage(error);
}

if (error instanceof Error || 'code' in error) {
return error.message;
return mapBusinessErrorMessage(error.message);
}

if (error.data) {
if (typeof error.data?.message === 'string') {
return error.data.message;
return mapBusinessErrorMessage(error.data.message);
}

if (typeof error.data?.msg === 'string') {
return error.data.msg;
return mapBusinessErrorMessage(error.data.msg);
}

if (typeof error.data === 'string') {
return error.data;
return mapBusinessErrorMessage(error.data);
}

return JSON.stringify(error.data);
Expand Down
Loading