@retailcrm/datalens-ui 0.2.4 → 0.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.css +587 -587
- package/package.json +1 -1
- package/public/i18n/data.json +2 -1
- package/public/i18n/{en.144c7612.js → en.01e3d689.js} +2 -1
- package/public/i18n/manifest.json +2 -2
- package/public/i18n/{ru.b7e6f7b0.js → ru.a9fbfe3a.js} +2 -1
- package/ui/capabilities/capabilities.d.ts +1 -0
- package/ui/capabilities/capabilities.js +5 -0
- package/ui/components/ActionPanel/ActionPanel.js +2 -1
- package/ui/components/AsideHeaderAdapter/AsideHeaderAdapter.js +9 -1
- package/ui/components/DialogAddSharedEntryFromLink/DialogAddSharedEntryFromLink.js +4 -1
- package/ui/components/DialogSharedEntryPermissions/DialogSharedEntryPermissions.js +3 -8
- package/ui/components/EntryDialogues/DialogCreateDashboard/DialogCreateDashboard.js +4 -3
- package/ui/components/EntryDialogues/DialogCreateEditorChart/DialogCreateEditorChart.js +4 -3
- package/ui/components/EntryDialogues/DialogCreateQLChart/DialogCreateQLChart.js +4 -3
- package/ui/components/EntryDialogues/DialogCreateWizardChart/DialogCreateWizardChart.js +4 -3
- package/ui/components/EntryDialogues/DialogRenameEntry/DialogRenameEntry.js +4 -3
- package/ui/components/InaccessibleOnMobileInset/InaccessibleOnMobileInset.js +18 -4
- package/ui/components/Navigation/Base/configure.d.ts +0 -20
- package/ui/components/Navigation/Base/configure.js +23 -23
- package/ui/components/Navigation/Core/NavigationBreadcrumbs/BreadcrumbMenu.d.ts +1 -1
- package/ui/components/Navigation/Core/NavigationBreadcrumbs/BreadcrumbMenu.js +32 -2
- package/ui/units/connections/components/ConnectorForm/components/Datepicker/Datepicker.d.ts +1 -1
- package/ui/units/connections/components/ConnectorForm/components/FileInput/FileInput.d.ts +1 -1
- package/ui/units/connections/components/ConnectorForm/components/Input/Input.d.ts +1 -1
- package/ui/units/connections/components/ConnectorForm/components/Select/Select.d.ts +1 -1
- package/ui/units/dash/components/DashActionPanel/DashActionPanel.d.ts +1 -0
- package/ui/units/dash/components/DashActionPanel/DashActionPanel.js +35 -0
- package/ui/units/dash/components/DashActionPanel/ViewControls/ViewControls.d.ts +1 -0
- package/ui/units/dash/components/DashActionPanel/ViewControls/ViewControls.js +2 -1
- package/ui/units/dash/store/utils.js +2 -1
- package/ui/units/ql/containers/QL/QLActionPanel/QLActionPanel.js +15 -4
- package/ui/units/wizard/actions/widget.js +7 -1
- package/ui/units/wizard/containers/Wizard/Wizard.js +5 -3
- package/ui/units/workbooks/components/RenameEntryDialog/RenameEntryDialog.js +48 -12
- package/ui/units/workbooks/store/actions/index.d.ts +1 -1
- package/ui/units/workbooks/store/actions/index.js +1 -7
- package/ui/utils/errors/errorByCode.d.ts +1 -0
- package/ui/utils/errors/errorByCode.js +97 -0
|
@@ -13,6 +13,7 @@ const ViewControls = (props) => {
|
|
|
13
13
|
canEdit,
|
|
14
14
|
progress,
|
|
15
15
|
isLoadingEditMode,
|
|
16
|
+
showEditButton = true,
|
|
16
17
|
onEditClick,
|
|
17
18
|
onAccessClick,
|
|
18
19
|
entryDialoguesRef,
|
|
@@ -33,7 +34,7 @@ const ViewControls = (props) => {
|
|
|
33
34
|
}
|
|
34
35
|
),
|
|
35
36
|
/* @__PURE__ */ jsx(EntryDialogues, { ref: entryDialoguesRef }),
|
|
36
|
-
canEdit && !DL.IS_MOBILE && /* @__PURE__ */ jsx(
|
|
37
|
+
showEditButton && canEdit && !DL.IS_MOBILE && /* @__PURE__ */ jsx(
|
|
37
38
|
Button,
|
|
38
39
|
{
|
|
39
40
|
view: "normal",
|
|
@@ -8,6 +8,7 @@ import "../../../utils/index.js";
|
|
|
8
8
|
import { Mode, DASHKIT_STATE_VERSION } from "../modules/constants.js";
|
|
9
9
|
import { getLocation } from "../../../navigation/router.js";
|
|
10
10
|
import { URL_QUERY, DL } from "../../../constants/common.js";
|
|
11
|
+
import { normalizeDestination } from "../../../../shared/modules/entry.js";
|
|
11
12
|
import Utils from "../../../utils/utils.js";
|
|
12
13
|
import { EntryScope } from "../../../../shared/types/common.js";
|
|
13
14
|
const storeI18n = I18n.keyset("dash.store.view");
|
|
@@ -17,7 +18,7 @@ const getFakeDashEntry = (workbookId) => {
|
|
|
17
18
|
const { counter, id: newTabId } = generateUniqId({ salt, counter: 0, ids: [] });
|
|
18
19
|
const searchParams = getLocation().params();
|
|
19
20
|
const searchCurrentPath = searchParams.get(URL_QUERY.CURRENT_PATH);
|
|
20
|
-
const path = searchCurrentPath || DL.USER_FOLDER;
|
|
21
|
+
const path = normalizeDestination(searchCurrentPath || DL.USER_FOLDER);
|
|
21
22
|
const initialKey = `${path}${dashCreateI18n("label_default-name")}`;
|
|
22
23
|
const data = {
|
|
23
24
|
tabs: [
|
|
@@ -11,10 +11,12 @@ import { isDraftVersion } from "../../../../../utils/revisions.js";
|
|
|
11
11
|
import "../../../../../index.js";
|
|
12
12
|
import ActionPanel from "../../../../../components/ActionPanel/ActionPanel.js";
|
|
13
13
|
import { ChartSaveControls } from "../../../../../components/ActionPanel/components/ChartSaveControls/ChartSaveControl.js";
|
|
14
|
+
import "../../../../../navigation/index.js";
|
|
14
15
|
import { registry } from "../../../../../registry/index.js";
|
|
15
16
|
import { openDialogSaveDraftChartAsActualConfirm } from "../../../../../store/actions/dialog.js";
|
|
16
17
|
import { resetEditHistoryUnit, addEditHistoryPoint } from "../../../../../store/actions/editHistory.js";
|
|
17
|
-
import { reloadRevisionsOnSave } from "../../../../../store/actions/entryContent.js";
|
|
18
|
+
import { setIsRenameWithoutReload, reloadRevisionsOnSave } from "../../../../../store/actions/entryContent.js";
|
|
19
|
+
import { selectIsRenameWithoutReload } from "../../../../../store/selectors/entryContent.js";
|
|
18
20
|
import DialogSettings from "../../../components/Dialogs/Settings/Settings.js";
|
|
19
21
|
import { QL_EDIT_HISTORY_UNIT_ID } from "../../../constants/index.js";
|
|
20
22
|
import { prepareChartDataBeforeSave } from "../../../modules/helpers.js";
|
|
@@ -25,6 +27,7 @@ import SvgMonitoring from "../../../../../assets/icons/monitoring.svg.js";
|
|
|
25
27
|
/* empty css */
|
|
26
28
|
import { getValid, getConnection, getExtraSettings, getPreviewData, getEntry } from "../../../store/selectors/ql.js";
|
|
27
29
|
import { Feature } from "../../../../../../shared/types/feature.js";
|
|
30
|
+
import { useRouter } from "../../../../../navigation/router.js";
|
|
28
31
|
import Utils from "../../../../../utils/utils.js";
|
|
29
32
|
import { EntryDialogName } from "../../../../../components/EntryDialogues/EntryDialogues.js";
|
|
30
33
|
import { EntryDialogResolveStatus } from "../../../../../components/EntryDialogues/constants.js";
|
|
@@ -42,6 +45,7 @@ const QLActionPanel = (props) => {
|
|
|
42
45
|
const redirectUrl = useSelector(getRedirectUrl);
|
|
43
46
|
const previewData = useSelector(getPreviewData);
|
|
44
47
|
const entry = useSelector(getEntry);
|
|
48
|
+
const isRenameWithoutReload = useSelector(selectIsRenameWithoutReload);
|
|
45
49
|
const canEdit = !(entry && entry.permissions && entry.permissions.edit === false);
|
|
46
50
|
const isCurrentRevisionActual = entry?.revId && entry?.revId === entry?.publishedId;
|
|
47
51
|
const isNewChart = typeof entry?.fake !== "undefined" && entry?.fake;
|
|
@@ -49,17 +53,18 @@ const QLActionPanel = (props) => {
|
|
|
49
53
|
const { QlActionPanelExtension } = registry.ql.components.getAll();
|
|
50
54
|
const enablePublish = entry && isEnabledFeature(Feature.EnablePublishEntry) && !entry.fake;
|
|
51
55
|
const dispatch = useDispatch();
|
|
56
|
+
const router = useRouter();
|
|
52
57
|
const [dialogNoRightsVisible, setDialogNoRightsVisible] = React__default.useState(false);
|
|
53
58
|
const [dialogSettingsVisible, setDialogSettingsVisible] = React__default.useState(false);
|
|
54
59
|
const qlState = useSelector((state) => state.ql);
|
|
55
60
|
const wizardState = useSelector((state) => state.wizard);
|
|
56
61
|
const handleBeforeunload = React__default.useCallback(
|
|
57
62
|
(event) => {
|
|
58
|
-
if (!entryNotChanged) {
|
|
63
|
+
if (!entryNotChanged && !isRenameWithoutReload) {
|
|
59
64
|
event.returnValue = true;
|
|
60
65
|
}
|
|
61
66
|
},
|
|
62
|
-
[entryNotChanged]
|
|
67
|
+
[entryNotChanged, isRenameWithoutReload]
|
|
63
68
|
);
|
|
64
69
|
React__default.useEffect(() => {
|
|
65
70
|
window.removeEventListener("beforeunload", handleBeforeunload);
|
|
@@ -127,7 +132,12 @@ const QLActionPanel = (props) => {
|
|
|
127
132
|
if (!result || !result.data || result.status === EntryDialogResolveStatus.Close) {
|
|
128
133
|
return;
|
|
129
134
|
}
|
|
130
|
-
|
|
135
|
+
dispatch(setIsRenameWithoutReload(true));
|
|
136
|
+
try {
|
|
137
|
+
router.replace({ pathname: `/ql/${result.data.entryId}` });
|
|
138
|
+
} finally {
|
|
139
|
+
dispatch(setIsRenameWithoutReload(false));
|
|
140
|
+
}
|
|
131
141
|
result.data.data = {
|
|
132
142
|
shared: JSON.parse(result.data.data.shared)
|
|
133
143
|
};
|
|
@@ -152,6 +162,7 @@ const QLActionPanel = (props) => {
|
|
|
152
162
|
entryDialoguesRef,
|
|
153
163
|
defaultChartName,
|
|
154
164
|
qlState,
|
|
165
|
+
router,
|
|
155
166
|
wizardState
|
|
156
167
|
]
|
|
157
168
|
);
|
|
@@ -2,6 +2,7 @@ import { WIZARD_DATASET_ID_PARAMETER_KEY } from "../../../constants/misc.js";
|
|
|
2
2
|
import { CHART_SETTINGS } from "../../../constants/visualizations/index.js";
|
|
3
3
|
import "../../../navigation/index.js";
|
|
4
4
|
import { saveWidget } from "../../../store/actions/chartWidget.js";
|
|
5
|
+
import { setIsRenameWithoutReload } from "../../../store/actions/entryContent.js";
|
|
5
6
|
import { updateClientChartsConfig } from "./preview.js";
|
|
6
7
|
import { mapClientConfigToChartsConfig } from "../utils/mappers/mapClientToChartsConfig.js";
|
|
7
8
|
import { removeUrlParameters } from "../utils/wizard.js";
|
|
@@ -32,7 +33,12 @@ function receiveWidgetAndPrepareMetadata({
|
|
|
32
33
|
pathname += entryId;
|
|
33
34
|
}
|
|
34
35
|
if (!location.pathname.includes(entryId)) {
|
|
35
|
-
|
|
36
|
+
dispatch(setIsRenameWithoutReload(true));
|
|
37
|
+
try {
|
|
38
|
+
router.replace({ pathname });
|
|
39
|
+
} finally {
|
|
40
|
+
dispatch(setIsRenameWithoutReload(false));
|
|
41
|
+
}
|
|
36
42
|
}
|
|
37
43
|
}
|
|
38
44
|
if (error) {
|
|
@@ -23,6 +23,7 @@ import { registry } from "../../../../registry/index.js";
|
|
|
23
23
|
import { openDialogSaveDraftChartAsActualConfirm } from "../../../../store/actions/dialog.js";
|
|
24
24
|
import { addEditHistoryPoint, resetEditHistoryUnit, initEditHistoryUnit } from "../../../../store/actions/editHistory.js";
|
|
25
25
|
import { reloadRevisionsOnSave, cleanRevisions, setRevisionsMode } from "../../../../store/actions/entryContent.js";
|
|
26
|
+
import { selectIsRenameWithoutReload } from "../../../../store/selectors/entryContent.js";
|
|
26
27
|
import { RevisionsMode } from "../../../../store/typings/entryContent.js";
|
|
27
28
|
import "../../../../utils/index.js";
|
|
28
29
|
import { isDraft, isEditMode } from "../../../dash/store/selectors/dashTypedSelectors.js";
|
|
@@ -67,9 +68,9 @@ class Wizard extends React__default.Component {
|
|
|
67
68
|
super(props);
|
|
68
69
|
this.chartKitRef = React__default.createRef();
|
|
69
70
|
this.unloadConfirmation = (event) => {
|
|
70
|
-
const { previewHash, widgetHash, initialPreviewHash } = this.props;
|
|
71
|
+
const { previewHash, widgetHash, initialPreviewHash, isRenameWithoutReload } = this.props;
|
|
71
72
|
const widgetChanged = previewHash !== widgetHash && previewHash !== initialPreviewHash;
|
|
72
|
-
if (widgetChanged) {
|
|
73
|
+
if (widgetChanged && !isRenameWithoutReload) {
|
|
73
74
|
const message = i18n("wizard", "toast_unsaved");
|
|
74
75
|
(event || window.event).returnValue = message;
|
|
75
76
|
return message;
|
|
@@ -478,7 +479,8 @@ const mapStateToProps = (state, ownProps) => {
|
|
|
478
479
|
isParentDashWasChanged: isDraft(state) && isEditMode(state),
|
|
479
480
|
initialPreviewHash: selectInitialPreviewHash(state),
|
|
480
481
|
wizardState: state.wizard,
|
|
481
|
-
description: selectPreviewDescription(state)
|
|
482
|
+
description: selectPreviewDescription(state),
|
|
483
|
+
isRenameWithoutReload: selectIsRenameWithoutReload(state)
|
|
482
484
|
};
|
|
483
485
|
};
|
|
484
486
|
const mapDispatchToProps = (dispatch) => {
|
|
@@ -4,7 +4,9 @@ import { Dialog, TextInput } from "@gravity-ui/uikit";
|
|
|
4
4
|
import block from "bem-cn-lite";
|
|
5
5
|
import { I18n } from "../../../../../i18n/index.js";
|
|
6
6
|
import { useDispatch, useSelector } from "react-redux";
|
|
7
|
+
import { getEntryNameInputError } from "../../../../utils/errors/errorByCode.js";
|
|
7
8
|
import DialogManager from "../../../../components/DialogManager/DialogManager.js";
|
|
9
|
+
import { showToast } from "../../../../store/actions/toaster.js";
|
|
8
10
|
import { renameEntry } from "../../store/actions/index.js";
|
|
9
11
|
import { selectRenameEntryIsLoading } from "../../store/selectors/index.js";
|
|
10
12
|
/* empty css */
|
|
@@ -15,21 +17,54 @@ const RenameEntryDialog = React__default.memo(({ open, data, onClose }) => {
|
|
|
15
17
|
const dispatch = useDispatch();
|
|
16
18
|
const isLoading = useSelector(selectRenameEntryIsLoading);
|
|
17
19
|
const [newNameValue, setNewNameValue] = React__default.useState(data.name);
|
|
20
|
+
const [inputError, setInputError] = React__default.useState(false);
|
|
18
21
|
const textInputControlRef = React__default.useRef(null);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
22
|
+
React__default.useEffect(() => {
|
|
23
|
+
if (open) {
|
|
24
|
+
setNewNameValue(data.name);
|
|
25
|
+
setInputError(false);
|
|
26
|
+
}
|
|
27
|
+
}, [data.name, open]);
|
|
28
|
+
const handleApply = React__default.useCallback(async () => {
|
|
29
|
+
const name = newNameValue.trim();
|
|
30
|
+
try {
|
|
31
|
+
const renamedEntry = await dispatch(
|
|
32
|
+
renameEntry({
|
|
33
|
+
entryId: data.entryId,
|
|
34
|
+
name,
|
|
35
|
+
updateInline: true
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
if (renamedEntry) {
|
|
39
|
+
onClose();
|
|
40
|
+
}
|
|
41
|
+
} catch (error) {
|
|
42
|
+
const errorMessage = getEntryNameInputError(
|
|
43
|
+
error,
|
|
44
|
+
i18n("label_entry-name-already-exists")
|
|
45
|
+
);
|
|
46
|
+
if (errorMessage) {
|
|
47
|
+
setInputError(errorMessage);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
dispatch(
|
|
51
|
+
showToast({
|
|
52
|
+
title: error.message,
|
|
53
|
+
name: "RenameEntryDialogFailed",
|
|
54
|
+
error,
|
|
55
|
+
withReport: true
|
|
56
|
+
})
|
|
57
|
+
);
|
|
58
|
+
}
|
|
29
59
|
}, [data.entryId, dispatch, newNameValue, onClose]);
|
|
60
|
+
const handleInputUpdate = React__default.useCallback((value) => {
|
|
61
|
+
setNewNameValue(value);
|
|
62
|
+
setInputError(false);
|
|
63
|
+
}, []);
|
|
30
64
|
const propsButtonApply = React__default.useMemo(() => {
|
|
65
|
+
const normalizedValue = newNameValue.trim();
|
|
31
66
|
return {
|
|
32
|
-
disabled: !
|
|
67
|
+
disabled: !normalizedValue || normalizedValue === data.name
|
|
33
68
|
};
|
|
34
69
|
}, [data.name, newNameValue]);
|
|
35
70
|
return /* @__PURE__ */ jsxs(
|
|
@@ -49,7 +84,8 @@ const RenameEntryDialog = React__default.memo(({ open, data, onClose }) => {
|
|
|
49
84
|
{
|
|
50
85
|
value: newNameValue,
|
|
51
86
|
controlRef: textInputControlRef,
|
|
52
|
-
onUpdate:
|
|
87
|
+
onUpdate: handleInputUpdate,
|
|
88
|
+
error: inputError
|
|
53
89
|
}
|
|
54
90
|
)
|
|
55
91
|
] }),
|
|
@@ -164,7 +164,7 @@ export declare const renameEntry: ({ entryId, name, updateInline, }: {
|
|
|
164
164
|
entryId: string;
|
|
165
165
|
name: string;
|
|
166
166
|
updateInline: boolean;
|
|
167
|
-
}) => (dispatch: WorkbooksDispatch) => CancellablePromise<RenameEntryResponse
|
|
167
|
+
}) => (dispatch: WorkbooksDispatch) => CancellablePromise<RenameEntryResponse>;
|
|
168
168
|
type ChangeFavoriteEntryLoadingAction = {
|
|
169
169
|
type: typeof CHANGE_FAVORITE_ENTRY_LOADING;
|
|
170
170
|
};
|
|
@@ -319,18 +319,12 @@ const renameEntry = ({
|
|
|
319
319
|
}).catch((error) => {
|
|
320
320
|
if (!getSdk().sdk.isCancel(error)) {
|
|
321
321
|
logger.logError("workbooks/renameEntry failed", error);
|
|
322
|
-
dispatch(
|
|
323
|
-
showToast({
|
|
324
|
-
title: error.message,
|
|
325
|
-
error
|
|
326
|
-
})
|
|
327
|
-
);
|
|
328
322
|
}
|
|
329
323
|
dispatch({
|
|
330
324
|
type: RENAME_ENTRY_FAILED,
|
|
331
325
|
error
|
|
332
326
|
});
|
|
333
|
-
|
|
327
|
+
throw error;
|
|
334
328
|
});
|
|
335
329
|
};
|
|
336
330
|
};
|
|
@@ -14,4 +14,5 @@ interface EntryIsLockedError extends Error {
|
|
|
14
14
|
export declare function isEntryIsLockedError(error: DataLensApiError): error is EntryIsLockedError;
|
|
15
15
|
export declare function getLoginOrIdFromLockedError(error: EntryIsLockedError): string;
|
|
16
16
|
export declare function isEntryAlreadyExists(error: DataLensApiError): boolean;
|
|
17
|
+
export declare function getEntryNameInputError(error: DataLensApiError, duplicateNameErrorText: string): string | null;
|
|
17
18
|
export {};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { I18n } from "../../../i18n/index.js";
|
|
1
2
|
import "../../../shared/index.js";
|
|
2
3
|
import { parseError } from "./parse.js";
|
|
3
4
|
import { ErrorCode } from "../../../shared/constants/error-codes.js";
|
|
@@ -14,7 +15,103 @@ function isEntryAlreadyExists(error) {
|
|
|
14
15
|
}
|
|
15
16
|
return false;
|
|
16
17
|
}
|
|
18
|
+
const NON_INPUT_ENTRY_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
19
|
+
ErrorCode.EntryIsLocked,
|
|
20
|
+
ErrorCode.UsAccessDenied,
|
|
21
|
+
ErrorCode.EntryForbidden
|
|
22
|
+
]);
|
|
23
|
+
const validationI18n = I18n.keyset("validation");
|
|
24
|
+
const GENERIC_VALIDATION_MESSAGES = /* @__PURE__ */ new Set(["validation error", "validation_error"]);
|
|
25
|
+
const VALIDATION_TEXT_KEYS = [
|
|
26
|
+
"validationErrors",
|
|
27
|
+
"validationError",
|
|
28
|
+
"errors",
|
|
29
|
+
"error",
|
|
30
|
+
"message",
|
|
31
|
+
"description",
|
|
32
|
+
"detail",
|
|
33
|
+
"reason"
|
|
34
|
+
];
|
|
35
|
+
function normalizeErrorText(value) {
|
|
36
|
+
return typeof value === "string" && value.trim() ? value.trim() : null;
|
|
37
|
+
}
|
|
38
|
+
function normalizeEntryNameValidationText(value) {
|
|
39
|
+
const withoutFieldPrefix = value.replace(/^data\.name\s+/i, "").trim();
|
|
40
|
+
const isSlashValidation = /contain/i.test(withoutFieldPrefix) && /symbol/i.test(withoutFieldPrefix) && withoutFieldPrefix.includes("/");
|
|
41
|
+
if (isSlashValidation) {
|
|
42
|
+
return validationI18n("label_validation-slash_error");
|
|
43
|
+
}
|
|
44
|
+
const isSymbolsValidation = /should start and end with/i.test(withoutFieldPrefix) && /can contain only symbols/i.test(withoutFieldPrefix);
|
|
45
|
+
if (isSymbolsValidation) {
|
|
46
|
+
return validationI18n("label_validation-symbols_error");
|
|
47
|
+
}
|
|
48
|
+
return withoutFieldPrefix;
|
|
49
|
+
}
|
|
50
|
+
function isGenericValidationMessage(value) {
|
|
51
|
+
return GENERIC_VALIDATION_MESSAGES.has(value.toLowerCase());
|
|
52
|
+
}
|
|
53
|
+
function getValidationTextFromUnknown(value) {
|
|
54
|
+
const stringValue = normalizeErrorText(value);
|
|
55
|
+
if (stringValue) {
|
|
56
|
+
return isGenericValidationMessage(stringValue) ? null : normalizeEntryNameValidationText(stringValue);
|
|
57
|
+
}
|
|
58
|
+
if (Array.isArray(value)) {
|
|
59
|
+
const messages = value.map((item) => getValidationTextFromUnknown(item)).filter((item) => Boolean(item));
|
|
60
|
+
if (messages.length === 0) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return Array.from(new Set(messages)).join("; ");
|
|
64
|
+
}
|
|
65
|
+
if (!value || typeof value !== "object") {
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
const record = value;
|
|
69
|
+
for (const key of VALIDATION_TEXT_KEYS) {
|
|
70
|
+
if (key in record) {
|
|
71
|
+
const text = getValidationTextFromUnknown(record[key]);
|
|
72
|
+
if (text) {
|
|
73
|
+
return text;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
for (const nestedValue of Object.values(record)) {
|
|
78
|
+
const text = getValidationTextFromUnknown(nestedValue);
|
|
79
|
+
if (text) {
|
|
80
|
+
return text;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
function getDetailsValidationText(details) {
|
|
86
|
+
return getValidationTextFromUnknown(details);
|
|
87
|
+
}
|
|
88
|
+
function getEntryNameInputError(error, duplicateNameErrorText) {
|
|
89
|
+
if (isEntryAlreadyExists(error)) {
|
|
90
|
+
return duplicateNameErrorText;
|
|
91
|
+
}
|
|
92
|
+
const { code, message, status, details } = parseError(error);
|
|
93
|
+
const normalizedMessage = normalizeErrorText(message);
|
|
94
|
+
const detailsValidationText = getDetailsValidationText(details);
|
|
95
|
+
const messageForInput = detailsValidationText || (normalizedMessage && !isGenericValidationMessage(normalizedMessage) ? normalizeEntryNameValidationText(normalizedMessage) : null);
|
|
96
|
+
if (!messageForInput) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
if (code && NON_INPUT_ENTRY_ERROR_CODES.has(code)) {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
if (!code) {
|
|
103
|
+
const isValidationStatus2 = status === 400 || status === 409 || status === 422;
|
|
104
|
+
return isValidationStatus2 ? messageForInput : null;
|
|
105
|
+
}
|
|
106
|
+
const isUsRelatedError = code.startsWith("ERR.US.") || code.startsWith("ERR.DS_API.US.");
|
|
107
|
+
if (isUsRelatedError) {
|
|
108
|
+
return messageForInput;
|
|
109
|
+
}
|
|
110
|
+
const isValidationStatus = status === 400 || status === 409 || status === 422;
|
|
111
|
+
return isValidationStatus ? messageForInput : null;
|
|
112
|
+
}
|
|
17
113
|
export {
|
|
114
|
+
getEntryNameInputError,
|
|
18
115
|
getLoginOrIdFromLockedError,
|
|
19
116
|
isEntryAlreadyExists,
|
|
20
117
|
isEntryIsLockedError
|