@retailcrm/datalens-ui 0.2.4 → 0.2.6
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 -6
- 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/DashKit/helpers.js +4 -4
- 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/libs/DatalensChartkit/ChartKit/helpers/apply-hc-handlers.js +23 -2
- package/ui/libs/DatalensChartkit/menu/MenuItems.js +25 -17
- package/ui/libs/DatalensChartkit/modules/data-provider/charts/ui-sandbox.js +23 -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 +2 -0
- package/ui/units/dash/components/DashActionPanel/DashActionPanel.js +36 -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 +26 -6
- 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
|
@@ -12,16 +12,24 @@ import { isEnabledFeature } from "../../../utils/isEnabledFeature.js";
|
|
|
12
12
|
import { getExportItem, isExportItemDisabled } from "../components/ChartKitBase/components/Header/components/Menu/Items/Export/Export.js";
|
|
13
13
|
import getInspectorMenuitem from "../components/ChartKitBase/components/Header/components/Menu/Items/Inspector/Inspector.js";
|
|
14
14
|
import ChartKitIcon_default from "../components/ChartKitIcon/ChartKitIcon.js";
|
|
15
|
+
import { getRouter, getLocation } from "../../../navigation/router.js";
|
|
15
16
|
import { Feature } from "../../../../shared/types/feature.js";
|
|
16
17
|
import { MenuItemsIds } from "../../../../shared/types/menu.js";
|
|
17
18
|
import { DL, URL_OPTIONS } from "../../../constants/common.js";
|
|
18
19
|
import { WidgetKind } from "../../../../shared/types/widget.js";
|
|
19
20
|
import { PREVIEW_ROUTE } from "../../../../shared/constants/entry.js";
|
|
20
|
-
import { getLocation } from "../../../navigation/router.js";
|
|
21
21
|
import { FOCUSED_WIDGET_PARAM_NAME } from "../../../../shared/constants/dash.js";
|
|
22
22
|
const getExportMenuItem = getExportItem;
|
|
23
23
|
const getInspectorMenuItem = getInspectorMenuitem;
|
|
24
24
|
const alertI18n = I18n.keyset("component.chartkit-alerts.view");
|
|
25
|
+
const openInternalUrlInNewTab = (rawUrl) => {
|
|
26
|
+
const url = new URL(rawUrl, window.location.origin);
|
|
27
|
+
getRouter().openTab({
|
|
28
|
+
pathname: url.pathname,
|
|
29
|
+
search: url.search,
|
|
30
|
+
hash: url.hash
|
|
31
|
+
});
|
|
32
|
+
};
|
|
25
33
|
const getAlertsMenuItem = ({
|
|
26
34
|
chartsDataProvider,
|
|
27
35
|
customConfig
|
|
@@ -89,7 +97,7 @@ const getNewWindowMenuItem = ({
|
|
|
89
97
|
}
|
|
90
98
|
)
|
|
91
99
|
);
|
|
92
|
-
|
|
100
|
+
openInternalUrlInNewTab(link.toString());
|
|
93
101
|
})
|
|
94
102
|
});
|
|
95
103
|
const getEditMenuItem = ({
|
|
@@ -103,14 +111,15 @@ const getEditMenuItem = ({
|
|
|
103
111
|
icon: customConfig?.icon || /* @__PURE__ */ jsx(ChartKitIcon_default, { data: Pencil }),
|
|
104
112
|
isVisible: () => !DL.IS_MOBILE && (customConfig?.isVisible ? customConfig.isVisible() : true),
|
|
105
113
|
action: customConfig?.action || (({ loadedData = {}, propsData, chartsDataProvider: dataProvider }) => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
)
|
|
114
|
+
const url = (dataProvider || chartsDataProvider)?.getGoAwayLink(
|
|
115
|
+
{ loadedData, propsData },
|
|
116
|
+
{
|
|
117
|
+
idPrefix: "/navigate/"
|
|
118
|
+
}
|
|
113
119
|
);
|
|
120
|
+
if (url) {
|
|
121
|
+
openInternalUrlInNewTab(url);
|
|
122
|
+
}
|
|
114
123
|
})
|
|
115
124
|
});
|
|
116
125
|
const getOpenAsTableMenuItem = ({
|
|
@@ -131,15 +140,14 @@ const getOpenAsTableMenuItem = ({
|
|
|
131
140
|
return Boolean(!isCriticalError && isExportAllowed && isChart && customIsVisible);
|
|
132
141
|
},
|
|
133
142
|
action: customConfig?.action || (({ loadedData, propsData, chartsDataProvider: dataProvider }) => {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
{
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
)
|
|
143
|
+
const url = (dataProvider || chartsDataProvider).getGoAwayLink(
|
|
144
|
+
{ loadedData, propsData },
|
|
145
|
+
{
|
|
146
|
+
extraParams: { _chart_type: "table" },
|
|
147
|
+
idPrefix: "/preview/"
|
|
148
|
+
}
|
|
142
149
|
);
|
|
150
|
+
openInternalUrlInNewTab(url);
|
|
143
151
|
})
|
|
144
152
|
});
|
|
145
153
|
const getLinkMenuItem = (customConfig) => ({
|
|
@@ -4,6 +4,7 @@ import get from "lodash/get";
|
|
|
4
4
|
import merge from "lodash/merge";
|
|
5
5
|
import set from "lodash/set";
|
|
6
6
|
import { chartStorage } from "../../../ChartKit/plugins/chart-storage.js";
|
|
7
|
+
import "../../../../../navigation/index.js";
|
|
7
8
|
import "../../../../../../shared/index.js";
|
|
8
9
|
import { wrapHtml } from "../../../../../../shared/utils/ui-sandbox.js";
|
|
9
10
|
import { getRandomCKId } from "../../../ChartKit/helpers/getRandomCKId.js";
|
|
@@ -13,11 +14,32 @@ import { generateHtml } from "../../html-generator/index.js";
|
|
|
13
14
|
import { getParseHtmlFn } from "../../html-generator/utils.js";
|
|
14
15
|
import { UiSandboxRuntime } from "./ui-sandbox-runtime.js";
|
|
15
16
|
import { clearVmProp } from "./utils.js";
|
|
17
|
+
import { getRouter } from "../../../../../navigation/router.js";
|
|
16
18
|
import { EditorType, LegacyEditorType } from "../../../../../../shared/types/widget.js";
|
|
17
19
|
import { WRAPPED_FN_KEY } from "../../../../../../shared/constants/ui-sandbox.js";
|
|
18
20
|
import { WRAPPED_HTML_KEY } from "../../../../../../shared/constants/chartkit-handlers.js";
|
|
19
21
|
const UI_SANDBOX_TOTAL_TIME_LIMIT = 3e3;
|
|
20
22
|
const UI_SANDBOX_FN_TIME_LIMIT = 100;
|
|
23
|
+
const openSandboxUrl = (rawUrl, target) => {
|
|
24
|
+
if (typeof window === "undefined") {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const windowTarget = target === "_self" ? "_self" : "_blank";
|
|
28
|
+
const href = sanitizeUrl(rawUrl);
|
|
29
|
+
const url = new URL(href, window.location.origin);
|
|
30
|
+
if (url.origin === window.location.origin) {
|
|
31
|
+
getRouter().open(
|
|
32
|
+
{
|
|
33
|
+
pathname: url.pathname,
|
|
34
|
+
search: url.search,
|
|
35
|
+
hash: url.hash
|
|
36
|
+
},
|
|
37
|
+
windowTarget
|
|
38
|
+
);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
window.open(url.toString(), windowTarget);
|
|
42
|
+
};
|
|
21
43
|
let uiSandbox;
|
|
22
44
|
let getInterruptAfterDeadlineHandler;
|
|
23
45
|
const getUISandbox = async () => {
|
|
@@ -196,8 +218,7 @@ async function getUnwrappedFunction(args) {
|
|
|
196
218
|
window: {
|
|
197
219
|
open: function(url, target) {
|
|
198
220
|
try {
|
|
199
|
-
|
|
200
|
-
window.open(href, target === "_self" ? "_self" : "_blank");
|
|
221
|
+
openSandboxUrl(url, target);
|
|
201
222
|
} catch (e) {
|
|
202
223
|
console.error(e);
|
|
203
224
|
}
|
|
@@ -515,4 +515,4 @@ export declare const Datepicker: ConnectedComponent<{
|
|
|
515
515
|
validationErrors?: ValidationError[];
|
|
516
516
|
width?: BaseControlItem["width"];
|
|
517
517
|
hintText?: BaseControlItem["hintText"];
|
|
518
|
-
}, "form" | "actions" | "
|
|
518
|
+
}, "form" | "actions" | "validationErrors" | "innerForm">>;
|
|
@@ -598,5 +598,5 @@ export declare const FileInput: ConnectedComponent<{
|
|
|
598
598
|
validationErrors?: ValidationError[];
|
|
599
599
|
width?: BaseControlItem["width"];
|
|
600
600
|
hintText?: BaseControlItem["hintText"];
|
|
601
|
-
}, "form" | "actions" | "
|
|
601
|
+
}, "form" | "actions" | "validationErrors" | "innerForm">>;
|
|
602
602
|
export {};
|
|
@@ -546,4 +546,4 @@ export declare const Input: ConnectedComponent<{
|
|
|
546
546
|
validationErrors?: ValidationError[];
|
|
547
547
|
width?: BaseControlItem["width"];
|
|
548
548
|
hintText?: BaseControlItem["hintText"];
|
|
549
|
-
}, "form" | "actions" | "
|
|
549
|
+
}, "form" | "actions" | "validationErrors" | "innerForm">>;
|
|
@@ -547,4 +547,4 @@ export declare const Select: ConnectedComponent<{
|
|
|
547
547
|
validationErrors?: ValidationError[];
|
|
548
548
|
width?: BaseControlItem["width"];
|
|
549
549
|
hintText?: BaseControlItem["hintText"];
|
|
550
|
-
}, "form" | "actions" | "
|
|
550
|
+
}, "form" | "actions" | "validationErrors" | "innerForm">>;
|
|
@@ -55,6 +55,8 @@ declare class DashActionPanel extends React.PureComponent<ActionPanelProps, Acti
|
|
|
55
55
|
private getAdditionalEntryItems;
|
|
56
56
|
private onSelectStateClick;
|
|
57
57
|
private onValueTableOfContentsClick;
|
|
58
|
+
private isDashboardBreadcrumbEditingAccessible;
|
|
59
|
+
private filterEntryContextMenuItems;
|
|
58
60
|
private handleGoBack;
|
|
59
61
|
private handleGoForward;
|
|
60
62
|
private handleSaveDash;
|
|
@@ -8,7 +8,9 @@ import { connect } from "react-redux";
|
|
|
8
8
|
import "../../../../../shared/index.js";
|
|
9
9
|
import { ActionPanelEntryContextMenuQa } from "../../../../../shared/constants/qa/action-panel.js";
|
|
10
10
|
import "../../../../index.js";
|
|
11
|
+
import { capabilities } from "../../../../capabilities/index.js";
|
|
11
12
|
import ActionPanel from "../../../../components/ActionPanel/ActionPanel.js";
|
|
13
|
+
import "../../../../components/EntryContextMenu/index.js";
|
|
12
14
|
import { registry } from "../../../../registry/index.js";
|
|
13
15
|
import { closeDialog, openDialogConfirm } from "../../../../store/actions/dialog.js";
|
|
14
16
|
import { goForward, goBack } from "../../../../store/actions/editHistory.js";
|
|
@@ -30,13 +32,29 @@ import { EditControls } from "./EditControls/EditControls.js";
|
|
|
30
32
|
import { ViewControls } from "./ViewControls/ViewControls.js";
|
|
31
33
|
import { cancelEditClick } from "./helpers.js";
|
|
32
34
|
/* empty css */
|
|
35
|
+
import { ENTRY_CONTEXT_MENU_ACTION } from "../../../../components/EntryContextMenu/constants.js";
|
|
33
36
|
import { EntryDialogName } from "../../../../components/EntryDialogues/EntryDialogues.js";
|
|
34
37
|
import { EntryDialogResolveStatus } from "../../../../components/EntryDialogues/constants.js";
|
|
38
|
+
import { Capability } from "../../../../capabilities/capabilities.js";
|
|
39
|
+
import { EntryScope } from "../../../../../shared/types/common.js";
|
|
35
40
|
import { Feature } from "../../../../../shared/types/feature.js";
|
|
36
41
|
import { DL } from "../../../../constants/common.js";
|
|
37
42
|
import { ICONS_MENU_DEFAULT_SIZE } from "../../../../libs/DatalensChartkit/menu/constants.js";
|
|
38
43
|
const b = block("dash-action-panel");
|
|
39
44
|
const i18n = I18n.keyset("dash.action-panel.view");
|
|
45
|
+
const HIDDEN_DASH_ACTION_PANEL_CONTEXT_MENU_ITEMS = /* @__PURE__ */ new Set([
|
|
46
|
+
ENTRY_CONTEXT_MENU_ACTION.RENAME,
|
|
47
|
+
ENTRY_CONTEXT_MENU_ACTION.DELETE,
|
|
48
|
+
ENTRY_CONTEXT_MENU_ACTION.MOVE,
|
|
49
|
+
ENTRY_CONTEXT_MENU_ACTION.COPY,
|
|
50
|
+
ENTRY_CONTEXT_MENU_ACTION.ACCESS,
|
|
51
|
+
ENTRY_CONTEXT_MENU_ACTION.SHARE,
|
|
52
|
+
ENTRY_CONTEXT_MENU_ACTION.MIGRATE_TO_WORKBOOK
|
|
53
|
+
]);
|
|
54
|
+
const DASH_BREADCRUMB_EDITING_MENU_ITEMS = /* @__PURE__ */ new Set([
|
|
55
|
+
"edit",
|
|
56
|
+
ENTRY_CONTEXT_MENU_ACTION.RENAME
|
|
57
|
+
]);
|
|
40
58
|
const _DashActionPanel = class _DashActionPanel extends React__default.PureComponent {
|
|
41
59
|
constructor() {
|
|
42
60
|
super(...arguments);
|
|
@@ -133,6 +151,22 @@ const _DashActionPanel = class _DashActionPanel extends React__default.PureCompo
|
|
|
133
151
|
this.onValueTableOfContentsClick = () => {
|
|
134
152
|
this.props.toggleTableOfContent();
|
|
135
153
|
};
|
|
154
|
+
this.isDashboardBreadcrumbEditingAccessible = () => {
|
|
155
|
+
return capabilities.has(Capability.AccessibleDashboardBreadcrumbEditing);
|
|
156
|
+
};
|
|
157
|
+
this.filterEntryContextMenuItems = ({ items }) => {
|
|
158
|
+
const isDashboardBreadcrumbEditingAccessible = this.isDashboardBreadcrumbEditingAccessible();
|
|
159
|
+
const shouldHideDashEditingItems = this.props.entry?.scope === EntryScope.Dash && !isDashboardBreadcrumbEditingAccessible;
|
|
160
|
+
return items.filter((item) => {
|
|
161
|
+
if (HIDDEN_DASH_ACTION_PANEL_CONTEXT_MENU_ITEMS.has(item.id)) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
if (shouldHideDashEditingItems && DASH_BREADCRUMB_EDITING_MENU_ITEMS.has(item.id)) {
|
|
165
|
+
return false;
|
|
166
|
+
}
|
|
167
|
+
return true;
|
|
168
|
+
});
|
|
169
|
+
};
|
|
136
170
|
this.handleGoBack = () => {
|
|
137
171
|
if (this.props.canGoBack) {
|
|
138
172
|
this.props.goBack({ unitId: DASH_EDIT_HISTORY_UNIT_ID });
|
|
@@ -183,6 +217,7 @@ const _DashActionPanel = class _DashActionPanel extends React__default.PureCompo
|
|
|
183
217
|
{
|
|
184
218
|
entry,
|
|
185
219
|
additionalEntryItems: this.getAdditionalEntryItems(),
|
|
220
|
+
filterEntryContextMenuItems: this.filterEntryContextMenuItems,
|
|
186
221
|
rightItems: [
|
|
187
222
|
/* @__PURE__ */ jsx(
|
|
188
223
|
DashActionPanelAdditionalButtons,
|
|
@@ -238,6 +273,7 @@ const _DashActionPanel = class _DashActionPanel extends React__default.PureCompo
|
|
|
238
273
|
canEdit: this.props.canEdit,
|
|
239
274
|
progress: this.props.progress,
|
|
240
275
|
isLoadingEditMode: this.props.isLoadingEditMode,
|
|
276
|
+
showEditButton: this.isDashboardBreadcrumbEditingAccessible(),
|
|
241
277
|
onEditClick: this.props.handlerEditClick,
|
|
242
278
|
onAccessClick: this.openDialogAccess,
|
|
243
279
|
entryDialoguesRef: this.props.entryDialoguesRef,
|
|
@@ -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);
|
|
@@ -91,12 +96,21 @@ const QLActionPanel = (props) => {
|
|
|
91
96
|
icon: /* @__PURE__ */ jsx(Icon, { data: SvgMonitoring, width: 16, height: 16 }),
|
|
92
97
|
id: "sql-to-monitoring",
|
|
93
98
|
action: () => {
|
|
94
|
-
|
|
99
|
+
const url = new URL(redirectUrl, window.location.origin);
|
|
100
|
+
if (url.origin === window.location.origin) {
|
|
101
|
+
router.openTab({
|
|
102
|
+
pathname: url.pathname,
|
|
103
|
+
search: url.search,
|
|
104
|
+
hash: url.hash
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
window.open(url.toString(), "_blank");
|
|
95
109
|
}
|
|
96
110
|
});
|
|
97
111
|
}
|
|
98
112
|
return items;
|
|
99
|
-
}, [redirectUrl]);
|
|
113
|
+
}, [redirectUrl, router]);
|
|
100
114
|
const defaultChartName = React__default.useMemo(() => {
|
|
101
115
|
if (connection === null) {
|
|
102
116
|
return "";
|
|
@@ -127,7 +141,12 @@ const QLActionPanel = (props) => {
|
|
|
127
141
|
if (!result || !result.data || result.status === EntryDialogResolveStatus.Close) {
|
|
128
142
|
return;
|
|
129
143
|
}
|
|
130
|
-
|
|
144
|
+
dispatch(setIsRenameWithoutReload(true));
|
|
145
|
+
try {
|
|
146
|
+
router.replace({ pathname: `/ql/${result.data.entryId}` });
|
|
147
|
+
} finally {
|
|
148
|
+
dispatch(setIsRenameWithoutReload(false));
|
|
149
|
+
}
|
|
131
150
|
result.data.data = {
|
|
132
151
|
shared: JSON.parse(result.data.data.shared)
|
|
133
152
|
};
|
|
@@ -152,6 +171,7 @@ const QLActionPanel = (props) => {
|
|
|
152
171
|
entryDialoguesRef,
|
|
153
172
|
defaultChartName,
|
|
154
173
|
qlState,
|
|
174
|
+
router,
|
|
155
175
|
wizardState
|
|
156
176
|
]
|
|
157
177
|
);
|
|
@@ -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 {};
|