@gooddata/sdk-ui-dashboard 11.61.0-alpha.0 → 11.61.0-alpha.2
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/esm/__version.d.ts +1 -1
- package/esm/__version.js +1 -1
- package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.d.ts.map +1 -1
- package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.js +13 -5
- package/esm/model/store/topBar/topBarSelectors.d.ts.map +1 -1
- package/esm/model/store/topBar/topBarSelectors.js +11 -3
- package/esm/model/store/unavailableObjects/copyBlockingReferences.d.ts +35 -0
- package/esm/model/store/unavailableObjects/copyBlockingReferences.d.ts.map +1 -0
- package/esm/model/store/unavailableObjects/copyBlockingReferences.js +79 -0
- package/esm/model/store/widgetDrills/drillRestrictionUtils.d.ts +9 -2
- package/esm/model/store/widgetDrills/drillRestrictionUtils.d.ts.map +1 -1
- package/esm/model/store/widgetDrills/drillRestrictionUtils.js +13 -6
- package/esm/presentation/localization/bundles/en-US.localization-bundle.js +1 -1
- package/esm/presentation/widget/common/configuration/FilterConfiguration.js +4 -4
- package/esm/presentation/widget/insight/DashboardInsight.d.ts.map +1 -1
- package/esm/presentation/widget/insight/DashboardInsight.js +7 -2
- package/esm/presentation/widget/insight/configuration/DrillTargets/DrillTargetUrlItem.d.ts.map +1 -1
- package/esm/presentation/widget/insight/configuration/DrillTargets/DrillTargetUrlItem.js +11 -5
- package/package.json +21 -21
- package/styles/css/main.css +19 -0
- package/styles/css/main.css.map +1 -1
- package/styles/css/sidebar.css +19 -0
- package/styles/css/sidebar.css.map +1 -1
- package/styles/scss/sidebar.scss +21 -0
package/esm/__version.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "11.61.0-alpha.
|
|
1
|
+
export declare const LIB_VERSION = "11.61.0-alpha.2";
|
|
2
2
|
export declare const LIB_DESCRIPTION = "GoodData SDK - Dashboard Component";
|
|
3
3
|
export declare const LIB_NAME = "@gooddata/sdk-ui-dashboard";
|
|
4
4
|
//# sourceMappingURL=__version.d.ts.map
|
package/esm/__version.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// (C) 2021 GoodData Corporation
|
|
2
2
|
// DO NOT CHANGE THIS FILE, IT IS RE-GENERATED ON EVERY BUILD
|
|
3
|
-
export const LIB_VERSION = "11.61.0-alpha.
|
|
3
|
+
export const LIB_VERSION = "11.61.0-alpha.2";
|
|
4
4
|
export const LIB_DESCRIPTION = "GoodData SDK - Dashboard Component";
|
|
5
5
|
export const LIB_NAME = "@gooddata/sdk-ui-dashboard";
|
package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"changeFilterContextSelectionHandler.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAwC/C,OAAO,EAAE,KAAK,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"changeFilterContextSelectionHandler.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAwC/C,OAAO,EAAE,KAAK,4BAA4B,EAAE,MAAM,2BAA2B,CAAC;AAqC9E,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAoGnE,wBAAiB,mCAAmC,CAChD,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,4BAA4B,GAClC,YAAY,CAAC,IAAI,CAAC,CA2LpB"}
|
|
@@ -7,10 +7,12 @@ import { areObjRefsEqual, attributeElementsIsEmpty, dashboardAttributeFilterItem
|
|
|
7
7
|
import { dashboardFilterToFilterContextItem } from "../../../_staging/dashboard/dashboardFilterContext.js";
|
|
8
8
|
import { invalidArgumentsProvided } from "../../events/general.js";
|
|
9
9
|
import { dispatchDashboardEvent } from "../../store/_infra/eventDispatcher.js";
|
|
10
|
+
import { isDashboardFilterRestricted } from "../../store/filtering/restrictedFilterUtils.js";
|
|
10
11
|
import { selectAttributeFilterConfigsOverrides, selectAttributeFilterConfigsOverridesByTab, selectAttributeFilterConfigsSelectionTypeMap, selectAttributeFilterConfigsSelectionTypeMapByTab, } from "../../store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
|
|
11
12
|
import { selectAttributeFilterDisplayFormsMap, selectFilterContextAttributeFilterByDisplayForm, selectFilterContextAttributeFilterByDisplayFormForTab, selectFilterContextAttributeFilterByLocalId, selectFilterContextAttributeFilterByLocalIdForTab, selectFilterContextAttributeFilterItemByDisplayForm, selectFilterContextAttributeFilterItemByDisplayFormForTab, selectFilterContextAttributeFilterItemByLocalId, selectFilterContextAttributeFilterItemByLocalIdForTab, selectFilterContextAttributeFilterItems, selectFilterContextAttributeFilterItemsForTab, selectFilterContextAttributeFilters, selectFilterContextAttributeFiltersForTab, selectFilterContextDateFilterByDataSet, selectFilterContextDateFilterByDataSetForTab, selectFilterContextDateFiltersWithDimension, selectFilterContextDateFiltersWithDimensionForTab, selectFilterContextMeasureValueFilters, } from "../../store/tabs/filterContext/filterContextSelectors.js";
|
|
12
13
|
import { tabsActions } from "../../store/tabs/index.js";
|
|
13
14
|
import { selectTabs } from "../../store/tabs/tabsSelectors.js";
|
|
15
|
+
import { selectUnavailableObjects } from "../../store/unavailableObjects/unavailableObjectsSelectors.js";
|
|
14
16
|
import { resolveAttributeMetadata } from "../../utils/attributeResolver.js";
|
|
15
17
|
import { resolveDisplayFormMetadata, } from "../../utils/displayFormResolver.js";
|
|
16
18
|
import { canApplyFilterTypeToTarget } from "../dashboard/common/attributeFilterSelectionTypeCompatibility.js";
|
|
@@ -79,6 +81,9 @@ export function* changeFilterContextSelectionHandler(ctx, cmd) {
|
|
|
79
81
|
}
|
|
80
82
|
// Cross-filtering is always compatible with dashboard tabs now
|
|
81
83
|
// (removed the check that prevented cross-filtering without tabs)
|
|
84
|
+
const unavailableObjects = yield select(selectUnavailableObjects);
|
|
85
|
+
// A restricted attribute filter keeps its stored selection: its label is never resolved, so the
|
|
86
|
+
// filter can be neither matched nor changed.
|
|
82
87
|
const normalizedFilters = compact(filters.map((filter) => {
|
|
83
88
|
if (isDashboardAttributeFilterItem(filter) ||
|
|
84
89
|
isDashboardDateFilter(filter) ||
|
|
@@ -86,7 +91,8 @@ export function* changeFilterContextSelectionHandler(ctx, cmd) {
|
|
|
86
91
|
return filter;
|
|
87
92
|
}
|
|
88
93
|
return dashboardFilterToFilterContextItem(filter, !!ctx.backend.capabilities.supportsMultipleDateFilters);
|
|
89
|
-
}))
|
|
94
|
+
})).filter((filter) => !(isDashboardAttributeFilterItem(filter) &&
|
|
95
|
+
isDashboardFilterRestricted(filter, unavailableObjects)));
|
|
90
96
|
const disabledComputedAttributeRef = yield call(findDisabledComputedAttributeRef, [
|
|
91
97
|
...normalizedFilters
|
|
92
98
|
.filter(isDashboardAttributeFilterItem)
|
|
@@ -134,7 +140,7 @@ export function* changeFilterContextSelectionHandler(ctx, cmd) {
|
|
|
134
140
|
const [[commonDateFilter], dateFiltersWithDimension] = partition(dateFilters, isDashboardCommonDateFilter);
|
|
135
141
|
const selectionTypeMap = yield call(selectAttributeFilterConfigsSelectionTypeMapTabAware, tabLocalIdentifier);
|
|
136
142
|
const [attributeFilterResult, commonDateFilterUpdateActions, dateFiltersUpdateActions, measureValueFilterUpdateActions,] = yield all([
|
|
137
|
-
call(getAttributeFiltersUpdateActions, [...attributeFilters].reverse(), textAttributeFilters, attributeFilterConfigs, resetOthers, ctx, tabLocalIdentifier, selectionTypeMap, matchByLocalIdentifier),
|
|
143
|
+
call(getAttributeFiltersUpdateActions, [...attributeFilters].reverse(), textAttributeFilters, attributeFilterConfigs, resetOthers, unavailableObjects, ctx, tabLocalIdentifier, selectionTypeMap, matchByLocalIdentifier),
|
|
138
144
|
call(getDateFilterUpdateActions, commonDateFilter, resetOthers, tabLocalIdentifier),
|
|
139
145
|
call(getDateFiltersUpdateActions, dateFiltersWithDimension, resetOthers, tabLocalIdentifier),
|
|
140
146
|
call(getMeasureValueFiltersUpdateActions, measureValueFilters, resetOthers),
|
|
@@ -229,7 +235,7 @@ function* findTargetFilterItemByDisplayForm(displayFormRef, tabLocalIdentifier)
|
|
|
229
235
|
}
|
|
230
236
|
return undefined;
|
|
231
237
|
}
|
|
232
|
-
function* getAttributeFiltersUpdateActions(attributeFilters, textAttributeFilters, attributeFilterConfigs, resetOthers, ctx, tabLocalIdentifier, selectionTypeMap, matchByLocalIdentifier) {
|
|
238
|
+
function* getAttributeFiltersUpdateActions(attributeFilters, textAttributeFilters, attributeFilterConfigs, resetOthers, unavailableObjects, ctx, tabLocalIdentifier, selectionTypeMap, matchByLocalIdentifier) {
|
|
233
239
|
const updateActions = [];
|
|
234
240
|
const displayFormsToResolve = [];
|
|
235
241
|
const handledLocalIds = new Set();
|
|
@@ -516,7 +522,8 @@ function* getAttributeFiltersUpdateActions(attributeFilters, textAttributeFilter
|
|
|
516
522
|
if (resetOthers) {
|
|
517
523
|
const currentAttributeFilters = yield call(selectFilterContextAttributeFiltersTabAware, tabLocalIdentifier);
|
|
518
524
|
// for element-based filters that have not been handled, create clear selection actions
|
|
519
|
-
const unhandledFilters = currentAttributeFilters.filter((filter) => !handledLocalIds.has(dashboardAttributeFilterItemLocalIdentifier(filter))
|
|
525
|
+
const unhandledFilters = currentAttributeFilters.filter((filter) => !handledLocalIds.has(dashboardAttributeFilterItemLocalIdentifier(filter)) &&
|
|
526
|
+
!isDashboardFilterRestricted(filter, unavailableObjects));
|
|
520
527
|
if (unhandledFilters.length > 0) {
|
|
521
528
|
updateActions.push(tabsActions.clearAttributeFiltersSelection({
|
|
522
529
|
filterLocalIds: unhandledFilters.map((filter) => dashboardAttributeFilterItemLocalIdentifier(filter)),
|
|
@@ -527,7 +534,8 @@ function* getAttributeFiltersUpdateActions(attributeFilters, textAttributeFilter
|
|
|
527
534
|
// (negative arbitrary filter with empty selection)
|
|
528
535
|
const currentAllFilterItems = yield call(selectFilterContextAttributeFilterItemsTabAware, tabLocalIdentifier);
|
|
529
536
|
const unhandledTextFilters = currentAllFilterItems.filter((filter) => isDashboardTextAttributeFilter(filter) &&
|
|
530
|
-
!handledLocalIds.has(dashboardAttributeFilterItemLocalIdentifier(filter))
|
|
537
|
+
!handledLocalIds.has(dashboardAttributeFilterItemLocalIdentifier(filter)) &&
|
|
538
|
+
!isDashboardFilterRestricted(filter, unavailableObjects));
|
|
531
539
|
for (const textFilter of unhandledTextFilters) {
|
|
532
540
|
const localId = dashboardAttributeFilterItemLocalIdentifier(textFilter);
|
|
533
541
|
const resetFilter = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"topBarSelectors.d.ts","sourceRoot":"","sources":["../../../../src/model/store/topBar/topBarSelectors.ts"],"names":[],"mappings":"AAoCA,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"topBarSelectors.d.ts","sourceRoot":"","sources":["../../../../src/model/store/topBar/topBarSelectors.ts"],"names":[],"mappings":"AAoCA,OAAO,EAAE,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AAI1E;;GAEG;AACH,eAAO,MAAM,sBAAsB,EAAE,iBAAiB,CAAC,OAAO,CAO7D,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iCAAiC,EAAE,iBAAiB,CAAC,OAAO,CAIxE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBAAiB,CAAC,OAAO,CAI/D,CAAC;AAEF;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,cAAc,WAE3D;AAED;;GAEG;AACH,eAAO,MAAM,qCAAqC,EAAE,iBAAiB,CAAC,OAAO,CAK5E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uCAAuC,EAAE,iBAAiB,CAAC,OAAO,CAM9E,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,iBAAiB,CAAC,OAAO,CAMhE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,yBAAyB,EAAE,iBAAiB,CAAC,OAAO,CAOhE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iCAAiC,EAAE,iBAAiB,CAAC,OAAO,CAIxE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,0BAA0B,EAAE,iBAAiB,CAAC,OAAO,CAuBjE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,8BAA8B,EAAE,iBAAiB,CAAC,OAAO,CA8BrE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,EAAE,iBAAiB,CAAC,OAAO,CAMlE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,8BAA8B,EAAE,iBAAiB,CAAC,OAAO,CAMrE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,4BAA4B,EAAE,iBAAiB,CAAC,OAAO,CAYnE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,EAAE,iBAAiB,CAAC,OAAO,CAM7D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,iBAAiB,CAAC,OAAO,CAqB1D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,EAAE,iBAAiB,CAAC,OAAO,CAM5D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,EAAE,iBAAiB,CAAC,OAAO,CAM1D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,wBAAwB,EAAE,iBAAiB,CAAC,OAAO,CAK/D,CAAC"}
|
|
@@ -10,6 +10,7 @@ import { selectCanCreateAnalyticalDashboard, selectCanExportPdf, } from "../perm
|
|
|
10
10
|
import { selectIsInEditMode, selectIsInViewMode } from "../renderMode/renderModeSelectors.js";
|
|
11
11
|
import { selectIsLayoutEmpty } from "../tabs/layout/layoutSelectors.js";
|
|
12
12
|
import { selectMenuButtonItemsVisibility } from "../ui/uiSelectors.js";
|
|
13
|
+
import { selectHasCopyBlockingReferences } from "../unavailableObjects/copyBlockingReferences.js";
|
|
13
14
|
/**
|
|
14
15
|
* @internal
|
|
15
16
|
*/
|
|
@@ -65,7 +66,7 @@ export const selectIsShareButtonVisible = createSelector(selectHasSharePermissio
|
|
|
65
66
|
/**
|
|
66
67
|
* @internal
|
|
67
68
|
*/
|
|
68
|
-
export const selectIsSaveAsNewButtonVisible = createSelector(selectIsSaveAsNewButtonHidden, selectCanEnterEditModeAndIsLoaded, selectCanCreateAnalyticalDashboard, selectIsExport, selectIsReadOnly, (isSaveAsButtonHidden, isDashboardEditable, canCreateDashboard, isExport, isReadOnly) => {
|
|
69
|
+
export const selectIsSaveAsNewButtonVisible = createSelector(selectIsSaveAsNewButtonHidden, selectCanEnterEditModeAndIsLoaded, selectCanCreateAnalyticalDashboard, selectIsExport, selectIsReadOnly, selectHasCopyBlockingReferences, (isSaveAsButtonHidden, isDashboardEditable, canCreateDashboard, isExport, isReadOnly, isCopyBlocked) => {
|
|
69
70
|
/*
|
|
70
71
|
* The reasoning behind this condition is as follows. Do not show separate Save As button if:
|
|
71
72
|
*
|
|
@@ -77,8 +78,14 @@ export const selectIsSaveAsNewButtonVisible = createSelector(selectIsSaveAsNewBu
|
|
|
77
78
|
* 4. dashboard is not in export mode
|
|
78
79
|
* 5. If the user cannot create dashboards - e.g. does not have permissions to do so (is viewer for example).
|
|
79
80
|
* 6. If the dashboard is in read-only mode.
|
|
81
|
+
* 7. If the backend would refuse the copy because the dashboard references objects the user may not read.
|
|
80
82
|
*/
|
|
81
|
-
return (!isSaveAsButtonHidden &&
|
|
83
|
+
return (!isSaveAsButtonHidden &&
|
|
84
|
+
!isDashboardEditable &&
|
|
85
|
+
!isExport &&
|
|
86
|
+
canCreateDashboard &&
|
|
87
|
+
!isReadOnly &&
|
|
88
|
+
!isCopyBlocked);
|
|
82
89
|
});
|
|
83
90
|
/**
|
|
84
91
|
* Selects whether the common export is available.
|
|
@@ -121,10 +128,11 @@ export const selectPdfExportVisible = createSelector(selectCommonExportAvailable
|
|
|
121
128
|
*
|
|
122
129
|
* @internal
|
|
123
130
|
*/
|
|
124
|
-
export const selectSaveAsVisible = createSelector(selectIsSaveAsNewButtonVisible, selectCanCreateAnalyticalDashboard, selectIsSaveAsNewButtonHidden, selectMenuButtonItemsVisibility, (isStandaloneSaveAsNewButtonVisible, canCreateDashboard, isSaveAsNewHidden, menuButtonItemsVisibility) => {
|
|
131
|
+
export const selectSaveAsVisible = createSelector(selectIsSaveAsNewButtonVisible, selectCanCreateAnalyticalDashboard, selectIsSaveAsNewButtonHidden, selectMenuButtonItemsVisibility, selectHasCopyBlockingReferences, (isStandaloneSaveAsNewButtonVisible, canCreateDashboard, isSaveAsNewHidden, menuButtonItemsVisibility, isCopyBlocked) => {
|
|
125
132
|
return (!isStandaloneSaveAsNewButtonVisible &&
|
|
126
133
|
canCreateDashboard &&
|
|
127
134
|
!isSaveAsNewHidden &&
|
|
135
|
+
!isCopyBlocked &&
|
|
128
136
|
(menuButtonItemsVisibility.saveAsNewButton ?? true));
|
|
129
137
|
});
|
|
130
138
|
/**
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { IUnavailableDashboardReference } from "@gooddata/sdk-backend-spi";
|
|
2
|
+
import { type FilterContextItem, type IDashboardAttributeFilterConfig, type IDashboardLayout, type IInsight } from "@gooddata/sdk-model";
|
|
3
|
+
import { type ExtendedDashboardWidget } from "../../types/layoutTypes.js";
|
|
4
|
+
import { type DashboardSelector } from "../types.js";
|
|
5
|
+
/**
|
|
6
|
+
* The parts of one dashboard tab a copy of the dashboard is created from.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export interface IDashboardCopySourceTab {
|
|
11
|
+
layout?: IDashboardLayout<ExtendedDashboardWidget>;
|
|
12
|
+
filters: FilterContextItem[];
|
|
13
|
+
attributeFilterConfigs: IDashboardAttributeFilterConfig[];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Tells whether a copy of the dashboard would reference an object the current user may not read in a
|
|
17
|
+
* place the backend checks when it creates the copy, so it would refuse the copy.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* The backend accepts a copy that keeps a drill to a dashboard the user cannot open, an ignored
|
|
21
|
+
* drill-down hierarchy, or a metric the user may not read in a measure value filter or in the
|
|
22
|
+
* limit of a filter's values, so none of these count. A merely deleted object does not count either.
|
|
23
|
+
*
|
|
24
|
+
* @internal
|
|
25
|
+
*/
|
|
26
|
+
export declare function hasCopyBlockingReference(tabs: IDashboardCopySourceTab[], insights: IInsight[], unavailableObjects: IUnavailableDashboardReference[]): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Selects whether "Save as new" would fail because the dashboard, as it stands now, references objects
|
|
29
|
+
* the current user may not read in places the backend refuses to copy. Removing those references in
|
|
30
|
+
* edit mode clears it. The copy is made from every tab, and in view mode from the saved filters.
|
|
31
|
+
*
|
|
32
|
+
* @internal
|
|
33
|
+
*/
|
|
34
|
+
export declare const selectHasCopyBlockingReferences: DashboardSelector<boolean>;
|
|
35
|
+
//# sourceMappingURL=copyBlockingReferences.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copyBlockingReferences.d.ts","sourceRoot":"","sources":["../../../../src/model/store/unavailableObjects/copyBlockingReferences.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EACH,KAAK,iBAAiB,EAEtB,KAAK,+BAA+B,EACpC,KAAK,gBAAgB,EAErB,KAAK,QAAQ,EAehB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,KAAK,uBAAuB,EAAmC,MAAM,4BAA4B,CAAC;AAK3G,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAKrD;;;;GAIG;AACH,MAAM,WAAW,uBAAuB;IACpC,MAAM,CAAC,EAAE,gBAAgB,CAAC,uBAAuB,CAAC,CAAC;IACnD,OAAO,EAAE,iBAAiB,EAAE,CAAC;IAC7B,sBAAsB,EAAE,+BAA+B,EAAE,CAAC;CAC7D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACpC,IAAI,EAAE,uBAAuB,EAAE,EAC/B,QAAQ,EAAE,QAAQ,EAAE,EACpB,kBAAkB,EAAE,8BAA8B,EAAE,GACrD,OAAO,CAkET;AAED;;;;;;GAMG;AACH,eAAO,MAAM,+BAA+B,EAAE,iBAAiB,CAAC,OAAO,CAqBtE,CAAC"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { createSelector } from "@reduxjs/toolkit";
|
|
3
|
+
import { areObjRefsEqual, dashboardAttributeFilterItemDisplayForm, insightRef, isComputedAttributeRef, isDashboardAttributeFilterItem, isDashboardAttributeFilterReference, isDrillToDashboard, isInsightWidget, isKpiWidget, isRichTextWidget, isVisualizationSwitcherWidget, } from "@gooddata/sdk-model";
|
|
4
|
+
import { collectReferences } from "@gooddata/sdk-ui-kit";
|
|
5
|
+
import { isExtendedDashboardLayoutWidget } from "../../types/layoutTypes.js";
|
|
6
|
+
import { isDashboardObjectRestricted } from "../filtering/restrictedFilterUtils.js";
|
|
7
|
+
import { selectInsights } from "../insights/insightsSelectors.js";
|
|
8
|
+
import { selectIsInViewMode } from "../renderMode/renderModeSelectors.js";
|
|
9
|
+
import { selectTabs } from "../tabs/tabsSelectors.js";
|
|
10
|
+
import { isDrillRestricted } from "../widgetDrills/drillRestrictionUtils.js";
|
|
11
|
+
import { selectUnavailableObjects } from "./unavailableObjectsSelectors.js";
|
|
12
|
+
/**
|
|
13
|
+
* Tells whether a copy of the dashboard would reference an object the current user may not read in a
|
|
14
|
+
* place the backend checks when it creates the copy, so it would refuse the copy.
|
|
15
|
+
*
|
|
16
|
+
* @remarks
|
|
17
|
+
* The backend accepts a copy that keeps a drill to a dashboard the user cannot open, an ignored
|
|
18
|
+
* drill-down hierarchy, or a metric the user may not read in a measure value filter or in the
|
|
19
|
+
* limit of a filter's values, so none of these count. A merely deleted object does not count either.
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export function hasCopyBlockingReference(tabs, insights, unavailableObjects) {
|
|
24
|
+
const isForbidden = (ref, type) => ref !== undefined && isDashboardObjectRestricted(ref, type, unavailableObjects);
|
|
25
|
+
const isLabelForbidden = (ref) => ref !== undefined &&
|
|
26
|
+
isForbidden(ref, isComputedAttributeRef(ref) ? "computedAttribute" : "displayForm");
|
|
27
|
+
const isTextForbidden = (text) => Object.values(collectReferences(text ?? "")).some(({ ref, type }) => isForbidden(ref, type));
|
|
28
|
+
const isAnalyticalWidgetForbidden = (widget) => isTextForbidden(widget.description) ||
|
|
29
|
+
widget.ignoreDashboardFilters.some((reference) => isDashboardAttributeFilterReference(reference) && isLabelForbidden(reference.displayForm));
|
|
30
|
+
const isInsightWidgetForbidden = (widget) => {
|
|
31
|
+
// Save as new recomputes custom URL references from the insight as it is now, so resolve them the same way
|
|
32
|
+
const insight = insights.find((candidate) => areObjRefsEqual(insightRef(candidate), widget.insight));
|
|
33
|
+
return (isAnalyticalWidgetForbidden(widget) ||
|
|
34
|
+
isForbidden(widget.insight, "insight") ||
|
|
35
|
+
widget.drills.some((drill) => !isDrillToDashboard(drill) && isDrillRestricted(drill, unavailableObjects, insight)));
|
|
36
|
+
};
|
|
37
|
+
const isWidgetForbidden = (widget) => {
|
|
38
|
+
if (isExtendedDashboardLayoutWidget(widget)) {
|
|
39
|
+
return widget.sections.some(isSectionForbidden);
|
|
40
|
+
}
|
|
41
|
+
if (isInsightWidget(widget)) {
|
|
42
|
+
return isInsightWidgetForbidden(widget);
|
|
43
|
+
}
|
|
44
|
+
if (isVisualizationSwitcherWidget(widget)) {
|
|
45
|
+
return (isAnalyticalWidgetForbidden(widget) || widget.visualizations.some(isInsightWidgetForbidden));
|
|
46
|
+
}
|
|
47
|
+
if (isKpiWidget(widget)) {
|
|
48
|
+
return isAnalyticalWidgetForbidden(widget) || isForbidden(widget.kpi.metric, "measure");
|
|
49
|
+
}
|
|
50
|
+
if (isRichTextWidget(widget)) {
|
|
51
|
+
return isAnalyticalWidgetForbidden(widget) || isTextForbidden(widget.content);
|
|
52
|
+
}
|
|
53
|
+
return false;
|
|
54
|
+
};
|
|
55
|
+
const isSectionForbidden = (section) => isTextForbidden(section.header?.description) ||
|
|
56
|
+
section.items.some((item) => item.widget !== undefined && isWidgetForbidden(item.widget));
|
|
57
|
+
return tabs.some((tab) => (tab.layout?.sections ?? []).some(isSectionForbidden) ||
|
|
58
|
+
tab.attributeFilterConfigs.some((config) => isLabelForbidden(config.displayAsLabel)) ||
|
|
59
|
+
tab.filters.some((filter) => isDashboardAttributeFilterItem(filter) &&
|
|
60
|
+
isLabelForbidden(dashboardAttributeFilterItemDisplayForm(filter))));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Selects whether "Save as new" would fail because the dashboard, as it stands now, references objects
|
|
64
|
+
* the current user may not read in places the backend refuses to copy. Removing those references in
|
|
65
|
+
* edit mode clears it. The copy is made from every tab, and in view mode from the saved filters.
|
|
66
|
+
*
|
|
67
|
+
* @internal
|
|
68
|
+
*/
|
|
69
|
+
export const selectHasCopyBlockingReferences = createSelector(selectTabs, selectInsights, selectIsInViewMode, selectUnavailableObjects, (tabs, insights, isInViewMode, unavailableObjects) => unavailableObjects.length > 0 &&
|
|
70
|
+
hasCopyBlockingReference((tabs ?? []).map((tab) => {
|
|
71
|
+
const filterContext = isInViewMode
|
|
72
|
+
? tab.filterContext?.originalFilterContextDefinition
|
|
73
|
+
: tab.filterContext?.filterContextDefinition;
|
|
74
|
+
return {
|
|
75
|
+
layout: tab.layout?.layout,
|
|
76
|
+
filters: filterContext?.filters ?? [],
|
|
77
|
+
attributeFilterConfigs: tab.attributeFilterConfigs?.attributeFilterConfigs ?? [],
|
|
78
|
+
};
|
|
79
|
+
}), insights, unavailableObjects));
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { type IUnavailableDashboardReference } from "@gooddata/sdk-backend-spi";
|
|
2
|
+
import { type IInsightDefinition, type ObjRef } from "@gooddata/sdk-model";
|
|
2
3
|
import { type DashboardDrillDefinition } from "../../../types.js";
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
export declare function isLabelRestricted(ref: ObjRef, unavailable: IUnavailableDashboardReference[]): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* Identifies positively reported restrictions; missing metadata alone is not a permission signal.
|
|
7
|
+
*
|
|
8
|
+
* @param insight - the drilled widget's insight; custom URL placeholders that depend on it are then
|
|
9
|
+
* resolved from the insight as it is now rather than from the references stored on the drill
|
|
10
|
+
*/
|
|
11
|
+
export declare function isDrillRestricted(drill: DashboardDrillDefinition, unavailable: IUnavailableDashboardReference[], insight?: IInsightDefinition): boolean;
|
|
5
12
|
//# sourceMappingURL=drillRestrictionUtils.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"drillRestrictionUtils.d.ts","sourceRoot":"","sources":["../../../../src/model/store/widgetDrills/drillRestrictionUtils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"drillRestrictionUtils.d.ts","sourceRoot":"","sources":["../../../../src/model/store/widgetDrills/drillRestrictionUtils.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,8BAA8B,EAAE,MAAM,2BAA2B,CAAC;AAChF,OAAO,EACH,KAAK,kBAAkB,EACvB,KAAK,MAAM,EAOd,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAGlE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,8BAA8B,EAAE,GAAG,OAAO,CAMrG;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,wBAAwB,EAC/B,WAAW,EAAE,8BAA8B,EAAE,EAC7C,OAAO,CAAC,EAAE,kBAAkB,GAC7B,OAAO,CA2BT"}
|
|
@@ -2,8 +2,16 @@
|
|
|
2
2
|
import { isComputedAttributeRef, isDrillToAttributeUrl, isDrillToCustomUrl, isDrillToDashboard, isDrillToInsight, isIdentifierRef, } from "@gooddata/sdk-model";
|
|
3
3
|
import { getDrillToCustomUrlReferences } from "@gooddata/sdk-model/internal";
|
|
4
4
|
import { isDashboardObjectRestricted } from "../filtering/restrictedFilterUtils.js";
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
export function isLabelRestricted(ref, unavailable) {
|
|
6
|
+
return isDashboardObjectRestricted(ref, isComputedAttributeRef(ref) ? "computedAttribute" : "displayForm", unavailable);
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Identifies positively reported restrictions; missing metadata alone is not a permission signal.
|
|
10
|
+
*
|
|
11
|
+
* @param insight - the drilled widget's insight; custom URL placeholders that depend on it are then
|
|
12
|
+
* resolved from the insight as it is now rather than from the references stored on the drill
|
|
13
|
+
*/
|
|
14
|
+
export function isDrillRestricted(drill, unavailable, insight) {
|
|
7
15
|
if (unavailable.length === 0) {
|
|
8
16
|
return false;
|
|
9
17
|
}
|
|
@@ -13,13 +21,12 @@ export function isDrillRestricted(drill, unavailable) {
|
|
|
13
21
|
if (isDrillToDashboard(drill)) {
|
|
14
22
|
return (!!drill.target && isDashboardObjectRestricted(drill.target, "analyticalDashboard", unavailable));
|
|
15
23
|
}
|
|
16
|
-
const isLabelRestricted = (ref) => isDashboardObjectRestricted(ref, isComputedAttributeRef(ref) ? "computedAttribute" : "displayForm", unavailable);
|
|
17
24
|
if (isDrillToAttributeUrl(drill)) {
|
|
18
|
-
return (isLabelRestricted(drill.target.displayForm) ||
|
|
19
|
-
isLabelRestricted(drill.target.hyperlinkDisplayForm));
|
|
25
|
+
return (isLabelRestricted(drill.target.displayForm, unavailable) ||
|
|
26
|
+
isLabelRestricted(drill.target.hyperlinkDisplayForm, unavailable));
|
|
20
27
|
}
|
|
21
28
|
if (isDrillToCustomUrl(drill)) {
|
|
22
|
-
return getDrillToCustomUrlReferences(drill.target).some((ref) => isIdentifierRef(ref) &&
|
|
29
|
+
return getDrillToCustomUrlReferences(drill.target, insight).some((ref) => isIdentifierRef(ref) &&
|
|
23
30
|
ref.type !== undefined &&
|
|
24
31
|
isDashboardObjectRestricted(ref, ref.type, unavailable));
|
|
25
32
|
}
|
|
@@ -2627,7 +2627,7 @@ export const en_US = {
|
|
|
2627
2627
|
},
|
|
2628
2628
|
"drill_modal_picker.restricted": {
|
|
2629
2629
|
"text": "Restricted",
|
|
2630
|
-
"crowdinContext": "
|
|
2630
|
+
"crowdinContext": "Replaces the title of a drill target the user cannot access: a disabled drill menu item with a lock icon, or the drill to URL target button in the widget's Interactions settings"
|
|
2631
2631
|
},
|
|
2632
2632
|
"visualizationSwitcher.restrictedEntry": {
|
|
2633
2633
|
"text": "Restricted",
|
|
@@ -7,16 +7,16 @@ import { useAttributeFilterDisplayFormFromMap } from "../../../../_staging/share
|
|
|
7
7
|
import { useAttributes } from "../../../../_staging/sharedHooks/useAttributes.js";
|
|
8
8
|
import { useDashboardSelector } from "../../../../model/react/DashboardStoreProvider.js";
|
|
9
9
|
import { selectAllCatalogAttributesMap, selectAllCatalogDateDatasetsMap, selectAllCatalogMeasuresMap, selectCatalogIsLoaded, } from "../../../../model/store/catalog/catalogSelectors.js";
|
|
10
|
+
import { selectExecutableDashboardFilters } from "../../../../model/store/filtering/dashboardFilterSelectors.js";
|
|
10
11
|
import { selectInsightByRef } from "../../../../model/store/insights/insightsSelectors.js";
|
|
11
12
|
import { selectAttributeFilterConfigsDisplayAsLabelMap } from "../../../../model/store/tabs/attributeFilterConfigs/attributeFilterConfigsSelectors.js";
|
|
12
|
-
import { selectFilterContextFilters } from "../../../../model/store/tabs/filterContext/filterContextSelectors.js";
|
|
13
13
|
import { AttributeFilterConfigurationItem } from "./AttributeFilterConfigurationItem.js";
|
|
14
14
|
import { DateFilterConfigurationItem } from "./DateFilterConfigurationItem.js";
|
|
15
15
|
import { MeasureValueFilterConfigurationItem } from "./MeasureValueFilterConfigurationItem.js";
|
|
16
16
|
import { useMeasureValueFilterCompatibility } from "./useMeasureValueFilterCompatibility.js";
|
|
17
17
|
import { getAttributeByDisplayForm } from "./utils.js";
|
|
18
18
|
export function FilterConfiguration({ widget }) {
|
|
19
|
-
const
|
|
19
|
+
const filters = useDashboardSelector(selectExecutableDashboardFilters);
|
|
20
20
|
const getAttributeFilterDisplayFormFromMap = useAttributeFilterDisplayFormFromMap();
|
|
21
21
|
const attrMap = useDashboardSelector(selectAllCatalogAttributesMap);
|
|
22
22
|
const ddsMap = useDashboardSelector(selectAllCatalogDateDatasetsMap);
|
|
@@ -24,10 +24,10 @@ export function FilterConfiguration({ widget }) {
|
|
|
24
24
|
const isCatalogLoaded = useDashboardSelector(selectCatalogIsLoaded);
|
|
25
25
|
const displayAsLabelMap = useDashboardSelector(selectAttributeFilterConfigsDisplayAsLabelMap);
|
|
26
26
|
const draggableFilters = useMemo(() => {
|
|
27
|
-
return
|
|
27
|
+
return filters.filter((f) => isDashboardAttributeFilterItem(f) ||
|
|
28
28
|
isDashboardDateFilterWithDimension(f) ||
|
|
29
29
|
isDashboardMeasureValueFilter(f));
|
|
30
|
-
}, [
|
|
30
|
+
}, [filters]);
|
|
31
31
|
const attributeFilters = useMemo(() => {
|
|
32
32
|
return draggableFilters.filter(isDashboardAttributeFilterItem);
|
|
33
33
|
}, [draggableFilters]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DashboardInsight.d.ts","sourceRoot":"","sources":["../../../../src/presentation/widget/insight/DashboardInsight.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAW,MAAM,OAAO,CAAC;AAInD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"DashboardInsight.d.ts","sourceRoot":"","sources":["../../../../src/presentation/widget/insight/DashboardInsight.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAW,MAAM,OAAO,CAAC;AAInD,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAKpD,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD;;GAEG;AACH,wBAAgB,gBAAgB,CAC5B,KAAK,EAAE,IAAI,CAAC,sBAAsB,EAAE,SAAS,CAAC,GAAG;IAAE,OAAO,CAAC,EAAE,QAAQ,CAAA;CAAE,GACxE,YAAY,CAiCd"}
|
|
@@ -3,16 +3,21 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
3
3
|
import { useMemo } from "react";
|
|
4
4
|
import { useIntl } from "react-intl";
|
|
5
5
|
import { useDashboardComponentsContext } from "../../dashboardContexts/DashboardComponentsContext.js";
|
|
6
|
+
import { useVisualizationExportData } from "../../export/useExportData.js";
|
|
6
7
|
/**
|
|
7
8
|
* @internal
|
|
8
9
|
*/
|
|
9
10
|
export function DashboardInsight(props) {
|
|
10
|
-
const { insight, widget } = props;
|
|
11
|
+
const { insight, widget, exportData } = props;
|
|
11
12
|
const intl = useIntl();
|
|
12
13
|
const { InsightWidgetComponentSet, ErrorComponent } = useDashboardComponentsContext();
|
|
13
14
|
const InsightComponent = useMemo(() => (insight ? InsightWidgetComponentSet.MainComponentProvider(insight, widget) : null), [InsightWidgetComponentSet, insight, widget]);
|
|
15
|
+
const exportDataVis = useVisualizationExportData(exportData, false, true);
|
|
14
16
|
if (!insight || !InsightComponent) {
|
|
15
|
-
|
|
17
|
+
const error = (_jsx(ErrorComponent, { code: "404", message: intl.formatMessage({ id: "widget.error.missing_insight.message" }), description: intl.formatMessage({ id: "widget.error.missing_insight.description" }) }));
|
|
18
|
+
// slides export waits for every widget's content element and fails the whole export after
|
|
19
|
+
// its 180 s timeout when one is missing
|
|
20
|
+
return exportData && exportDataVis ? (_jsx("div", { className: "visualization-content", ...exportDataVis, children: error })) : (error);
|
|
16
21
|
}
|
|
17
22
|
return _jsx(InsightComponent, { ...props, insight: insight });
|
|
18
23
|
}
|
package/esm/presentation/widget/insight/configuration/DrillTargets/DrillTargetUrlItem.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DrillTargetUrlItem.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/widget/insight/configuration/DrillTargets/DrillTargetUrlItem.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"DrillTargetUrlItem.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/widget/insight/configuration/DrillTargets/DrillTargetUrlItem.tsx"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,oBAAoB,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAgB7E,OAAO,EACH,KAAK,cAAc,EAGtB,MAAM,4BAA4B,CAAC;AAiCpC,MAAM,WAAW,kBAAkB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,UAAU,EAAE,oBAAoB,EAAE,CAAC;IACnC,QAAQ,EAAE,CAAC,cAAc,EAAE,cAAc,KAAK,IAAI,CAAC;CACtD;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,kBAAkB,2CAiG3D"}
|
|
@@ -2,13 +2,14 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
2
2
|
// (C) 2020-2026 GoodData Corporation
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { useIntl } from "react-intl";
|
|
5
|
-
import { invariant } from "ts-invariant";
|
|
6
5
|
import { useClientWorkspaceIdentifiers } from "@gooddata/sdk-ui";
|
|
7
6
|
import { Button, Dropdown } from "@gooddata/sdk-ui-kit";
|
|
8
7
|
import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js";
|
|
9
8
|
import { selectBackendCapabilities } from "../../../../../model/store/backendCapabilities/backendCapabilitiesSelectors.js";
|
|
10
9
|
import { selectAllCatalogAttributesMap, selectAllCatalogDisplayFormsMap, } from "../../../../../model/store/catalog/catalogSelectors.js";
|
|
11
10
|
import { selectSettings } from "../../../../../model/store/config/configSelectors.js";
|
|
11
|
+
import { selectUnavailableObjects } from "../../../../../model/store/unavailableObjects/unavailableObjectsSelectors.js";
|
|
12
|
+
import { isLabelRestricted } from "../../../../../model/store/widgetDrills/drillRestrictionUtils.js";
|
|
12
13
|
import { AttributeUrlSection } from "../../../../drill/DrillConfigPanel/DrillToUrl/AttributeUrlSection.js";
|
|
13
14
|
import { CustomUrlEditor } from "../../../../drill/DrillConfigPanel/DrillToUrl/CustomUrlEditor.js";
|
|
14
15
|
import { CustomUrlSection } from "../../../../drill/DrillConfigPanel/DrillToUrl/CustomUrlSection.js";
|
|
@@ -19,15 +20,20 @@ function useButtonValue(urlDrillTarget) {
|
|
|
19
20
|
const intl = useIntl();
|
|
20
21
|
const displayForms = useDashboardSelector(selectAllCatalogDisplayFormsMap);
|
|
21
22
|
const attributes = useDashboardSelector(selectAllCatalogAttributesMap);
|
|
23
|
+
const unavailableObjects = useDashboardSelector(selectUnavailableObjects);
|
|
22
24
|
if (isDrillToCustomUrlConfig(urlDrillTarget) && urlDrillTarget.customUrl) {
|
|
23
25
|
return urlDrillTarget.customUrl;
|
|
24
26
|
}
|
|
25
27
|
if (isDrillToAttributeUrlConfig(urlDrillTarget) && urlDrillTarget.drillToAttributeDisplayForm) {
|
|
26
28
|
const displayForm = displayForms.get(urlDrillTarget.drillToAttributeDisplayForm);
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
const attribute = displayForm && attributes.get(displayForm.attribute);
|
|
30
|
+
if (displayForm && attribute) {
|
|
31
|
+
return `${attribute.attribute.title} (${displayForm.title})`;
|
|
32
|
+
}
|
|
33
|
+
// restricted or deleted labels are not in the catalog
|
|
34
|
+
if (isLabelRestricted(urlDrillTarget.drillToAttributeDisplayForm, unavailableObjects)) {
|
|
35
|
+
return intl.formatMessage({ id: "drill_modal_picker.restricted" });
|
|
36
|
+
}
|
|
31
37
|
}
|
|
32
38
|
return intl.formatMessage({ id: "configurationPanel.drillIntoUrl.defaultButtonValue" });
|
|
33
39
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-dashboard",
|
|
3
|
-
"version": "11.61.0-alpha.
|
|
3
|
+
"version": "11.61.0-alpha.2",
|
|
4
4
|
"description": "GoodData SDK - Dashboard Component",
|
|
5
5
|
"license": "LicenseRef-LICENSE",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -60,20 +60,20 @@
|
|
|
60
60
|
"ts-invariant": "0.10.3",
|
|
61
61
|
"tslib": "2.8.1",
|
|
62
62
|
"uuid": "11.1.1",
|
|
63
|
-
"@gooddata/sdk-backend-
|
|
64
|
-
"@gooddata/sdk-
|
|
65
|
-
"@gooddata/sdk-
|
|
66
|
-
"@gooddata/sdk-ui
|
|
67
|
-
"@gooddata/sdk-ui": "11.61.0-alpha.
|
|
68
|
-
"@gooddata/sdk-ui-ext": "11.61.0-alpha.
|
|
69
|
-
"@gooddata/sdk-ui-filters": "11.61.0-alpha.
|
|
70
|
-
"@gooddata/sdk-ui-geo": "11.61.0-alpha.
|
|
71
|
-
"@gooddata/sdk-ui-pivot": "11.61.0-alpha.
|
|
72
|
-
"@gooddata/sdk-ui-kit": "11.61.0-alpha.
|
|
73
|
-
"@gooddata/sdk-ui-semantic-search": "11.61.0-alpha.
|
|
74
|
-
"@gooddata/sdk-ui-theme-provider": "11.61.0-alpha.
|
|
75
|
-
"@gooddata/
|
|
76
|
-
"@gooddata/
|
|
63
|
+
"@gooddata/sdk-backend-base": "11.61.0-alpha.2",
|
|
64
|
+
"@gooddata/sdk-model": "11.61.0-alpha.2",
|
|
65
|
+
"@gooddata/sdk-backend-spi": "11.61.0-alpha.2",
|
|
66
|
+
"@gooddata/sdk-ui": "11.61.0-alpha.2",
|
|
67
|
+
"@gooddata/sdk-ui-charts": "11.61.0-alpha.2",
|
|
68
|
+
"@gooddata/sdk-ui-ext": "11.61.0-alpha.2",
|
|
69
|
+
"@gooddata/sdk-ui-filters": "11.61.0-alpha.2",
|
|
70
|
+
"@gooddata/sdk-ui-geo": "11.61.0-alpha.2",
|
|
71
|
+
"@gooddata/sdk-ui-pivot": "11.61.0-alpha.2",
|
|
72
|
+
"@gooddata/sdk-ui-kit": "11.61.0-alpha.2",
|
|
73
|
+
"@gooddata/sdk-ui-semantic-search": "11.61.0-alpha.2",
|
|
74
|
+
"@gooddata/sdk-ui-theme-provider": "11.61.0-alpha.2",
|
|
75
|
+
"@gooddata/sdk-ui-vis-commons": "11.61.0-alpha.2",
|
|
76
|
+
"@gooddata/util": "11.61.0-alpha.2"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@microsoft/api-documenter": "7.30.16",
|
|
@@ -115,12 +115,12 @@
|
|
|
115
115
|
"typescript": "7.0.2",
|
|
116
116
|
"vitest": "4.1.11",
|
|
117
117
|
"vitest-dom": "0.1.1",
|
|
118
|
-
"@gooddata/
|
|
119
|
-
"@gooddata/
|
|
120
|
-
"@gooddata/oxlint-config": "11.61.0-alpha.
|
|
121
|
-
"@gooddata/
|
|
122
|
-
"@gooddata/reference-workspace": "11.61.0-alpha.
|
|
123
|
-
"@gooddata/
|
|
118
|
+
"@gooddata/eslint-config": "11.61.0-alpha.2",
|
|
119
|
+
"@gooddata/i18n-toolkit": "11.61.0-alpha.2",
|
|
120
|
+
"@gooddata/oxlint-config": "11.61.0-alpha.2",
|
|
121
|
+
"@gooddata/sdk-backend-mockingbird": "11.61.0-alpha.2",
|
|
122
|
+
"@gooddata/reference-workspace": "11.61.0-alpha.2",
|
|
123
|
+
"@gooddata/stylelint-config": "11.61.0-alpha.2"
|
|
124
124
|
},
|
|
125
125
|
"peerDependencies": {
|
|
126
126
|
"react": "^18.0.0 || ^19.0.0",
|
package/styles/css/main.css
CHANGED
|
@@ -28987,6 +28987,25 @@ figure {
|
|
|
28987
28987
|
transition: opacity var(--sidebar-fade-duration) var(--sidebar-fade-delay);
|
|
28988
28988
|
}
|
|
28989
28989
|
|
|
28990
|
+
.gd-sidebar-container--rail.gd-sidebar-container--collapsed .gd-dropzone-delete {
|
|
28991
|
+
top: 48px;
|
|
28992
|
+
right: auto;
|
|
28993
|
+
width: 96px;
|
|
28994
|
+
}
|
|
28995
|
+
.gd-sidebar-container--rail.gd-sidebar-container--collapsed .gd-dropzone-delete .gd-dropzone-message {
|
|
28996
|
+
display: flex;
|
|
28997
|
+
align-items: center;
|
|
28998
|
+
gap: 10px;
|
|
28999
|
+
writing-mode: vertical-rl;
|
|
29000
|
+
transform: rotate(180deg);
|
|
29001
|
+
font-size: 12px;
|
|
29002
|
+
}
|
|
29003
|
+
.gd-sidebar-container--rail.gd-sidebar-container--collapsed .gd-dropzone-delete .gd-dropzone-message::before {
|
|
29004
|
+
line-height: 1;
|
|
29005
|
+
font-size: 24px;
|
|
29006
|
+
text-orientation: sideways;
|
|
29007
|
+
}
|
|
29008
|
+
|
|
28990
29009
|
.gd-sidebar-rail-search {
|
|
28991
29010
|
position: absolute;
|
|
28992
29011
|
top: 21px;
|