@gooddata/sdk-ui-dashboard 11.41.0-alpha.5 → 11.41.0
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.d.ts.map +1 -1
- package/esm/__version.js +1 -1
- package/esm/model/commandHandlers/drill/common/filterValuesResolver.d.ts.map +1 -1
- package/esm/model/commandHandlers/drill/common/filterValuesResolver.js +6 -1
- package/esm/model/commandHandlers/drill/getDrillToUrlFilters.d.ts.map +1 -1
- package/esm/model/commandHandlers/drill/getDrillToUrlFilters.js +12 -2
- package/esm/model/commandHandlers/drill/getElementTitle.d.ts.map +1 -1
- package/esm/model/commandHandlers/drill/getElementTitle.js +12 -1
- package/esm/model/commandHandlers/drill/resolveDrillToCustomUrl.d.ts +4 -0
- package/esm/model/commandHandlers/drill/resolveDrillToCustomUrl.d.ts.map +1 -1
- package/esm/model/commandHandlers/drill/resolveDrillToCustomUrl.js +80 -12
- package/esm/model/store/config/configSelectors.js +1 -1
- package/package.json +20 -20
- package/styles/css/main.css +48 -64
- package/styles/css/main.css.map +1 -1
package/esm/__version.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const LIB_VERSION = "11.41.0
|
|
1
|
+
export declare const LIB_VERSION = "11.41.0";
|
|
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.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"__version.d.ts","sourceRoot":"","sources":["../src/__version.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"__version.d.ts","sourceRoot":"","sources":["../src/__version.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC,eAAO,MAAM,eAAe,uCAAuC,CAAC;AAEpE,eAAO,MAAM,QAAQ,+BAA+B,CAAC"}
|
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.41.0
|
|
3
|
+
export const LIB_VERSION = "11.41.0";
|
|
4
4
|
export const LIB_DESCRIPTION = "GoodData SDK - Dashboard Component";
|
|
5
5
|
export const LIB_NAME = "@gooddata/sdk-ui-dashboard";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filterValuesResolver.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/drill/common/filterValuesResolver.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAgBpE,OAAO,EAGH,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACxB,MAAM,+BAA+B,CAAC;AAIvC;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACrC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,OAAO,CAAC,EAAE,kBAAkB,EAC5B,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,qBAAqB,CAAC,
|
|
1
|
+
{"version":3,"file":"filterValuesResolver.d.ts","sourceRoot":"","sources":["../../../../../src/model/commandHandlers/drill/common/filterValuesResolver.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAgBpE,OAAO,EAGH,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,EACxB,MAAM,+BAA+B,CAAC;AAIvC;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACrC,OAAO,EAAE,gBAAgB,EAAE,EAC3B,OAAO,CAAC,EAAE,kBAAkB,EAC5B,SAAS,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,qBAAqB,CAAC,CA4ChC"}
|
|
@@ -77,6 +77,11 @@ async function resolveRelativeDateFilterValues(filter, backend, workspace) {
|
|
|
77
77
|
const attributesService = backend.workspace(workspace).attributes();
|
|
78
78
|
const elementsQuery = attributesService.elements().forFilter(filter, foundDayDisplayForm?.ref);
|
|
79
79
|
const elements = await elementsQuery.query();
|
|
80
|
+
// No matching elements (e.g. the filter resolves to an empty range) — skip this filter rather
|
|
81
|
+
// than crashing on items[0], which would fail the whole drill with a generic "Failed to load URL".
|
|
82
|
+
if (elements.items.length === 0) {
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
80
85
|
// check for next page to see if we need to use skipped response
|
|
81
86
|
const hasNextPage = elements.limit + elements.offset < elements.totalCount;
|
|
82
87
|
// last page of the response to get last element
|
|
@@ -123,5 +128,5 @@ function getResolvedFilterValues(array, filter, index) {
|
|
|
123
128
|
return array[index];
|
|
124
129
|
}
|
|
125
130
|
function getLastTitle(items) {
|
|
126
|
-
return items[items.length - 1].title;
|
|
131
|
+
return items.length > 0 ? items[items.length - 1].title : null;
|
|
127
132
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getDrillToUrlFilters.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/drill/getDrillToUrlFilters.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAEH,KAAK,MAAM,EAId,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAyB,MAAM,4BAA4B,CAAC;AAI5G,wBAAiB,sCAAsC,CACnD,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,GAClB,YAAY,CAAC,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"getDrillToUrlFilters.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/drill/getDrillToUrlFilters.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAEH,KAAK,MAAM,EAId,MAAM,qBAAqB,CAAC;AAM7B,OAAO,EAAE,KAAK,gBAAgB,EAAE,KAAK,WAAW,EAAyB,MAAM,4BAA4B,CAAC;AAI5G,wBAAiB,sCAAsC,CACnD,GAAG,EAAE,gBAAgB,EACrB,SAAS,EAAE,MAAM,GAClB,YAAY,CAAC,WAAW,CAAC,CAyC3B"}
|
|
@@ -18,8 +18,18 @@ export function* getDrillToUrlFiltersWithResolvedValues(ctx, widgetRef) {
|
|
|
18
18
|
const enableFilterValuesResolutionInDrillEvents = yield select(selectEnableFilterValuesResolutionInDrillEvents);
|
|
19
19
|
if (enableFilterValuesResolutionInDrillEvents) {
|
|
20
20
|
const resolvableFilters = filters.filter((f) => isAttributeFilter(f) || isDateFilter(f));
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
try {
|
|
22
|
+
const resolvedFilterValues = yield call(resolveFilterValues, resolvableFilters, ctx.backend, ctx.workspace);
|
|
23
|
+
return { filters, resolvedFilterValues };
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
// Deliberately fail the drill rather than open it: if the filter values cannot be resolved
|
|
27
|
+
// (e.g. a bounded "month to date" date filter the backend cannot resolve), the target page
|
|
28
|
+
// would receive incomplete/incorrect filtering and could send the user somewhere wrong.
|
|
29
|
+
// Log the cause for diagnosability, then re-throw so the redirect is blocked.
|
|
30
|
+
console.error("Drill to URL: failed to resolve filter values; the drill will not open to avoid navigating to an incorrectly filtered page.", error);
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
23
33
|
}
|
|
24
34
|
return { filters };
|
|
25
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getElementTitle.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/drill/getElementTitle.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"getElementTitle.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/drill/getElementTitle.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,MAAM,EAAkB,MAAM,qBAAqB,CAAC;AAElE,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,wBAAsB,eAAe,CACjC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,4BAA4B,EAAE,MAAM,EACpC,GAAG,EAAE,gBAAgB,GACtB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAiCxB;AAED;;;;;;;GAOG;AACH,wBAAsB,0BAA0B,CAC5C,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,EACzB,sBAAsB,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EACzC,GAAG,EAAE,gBAAgB,GACtB,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAiB/B"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// (C) 2020-2026 GoodData Corporation
|
|
2
|
+
import { objRefToString } from "@gooddata/sdk-model";
|
|
1
3
|
export async function getElementTitle(projectId, dfRef, attrElementUriOrPrimaryLabel, ctx) {
|
|
2
4
|
const queryOptions = {
|
|
3
5
|
elements: ctx.backend.capabilities.supportsElementUris
|
|
@@ -16,7 +18,16 @@ export async function getElementTitle(projectId, dfRef, attrElementUriOrPrimaryL
|
|
|
16
18
|
.withLimit(1)
|
|
17
19
|
.withOptions(queryOptions)
|
|
18
20
|
.query();
|
|
19
|
-
|
|
21
|
+
const element = validElementsQuery.items[0];
|
|
22
|
+
if (!element) {
|
|
23
|
+
// The drilled value has no matching element on this display form (the elements query returned
|
|
24
|
+
// nothing). Fail with a descriptive message instead of a raw "items[0] is undefined" TypeError,
|
|
25
|
+
// so the resulting "Failed to load URL" is diagnosable from the console.
|
|
26
|
+
const message = `Drill to custom URL: no attribute element found for display form ${objRefToString(dfRef)} and value "${attrElementUriOrPrimaryLabel}"; the attribute_title placeholder cannot be resolved.`;
|
|
27
|
+
console.warn(message);
|
|
28
|
+
throw new Error(message);
|
|
29
|
+
}
|
|
30
|
+
return element.title;
|
|
20
31
|
}
|
|
21
32
|
/**
|
|
22
33
|
* For set of primary label elements and secondary label ref resolves element titles in this label
|
|
@@ -14,6 +14,10 @@ interface IDrillToUrlElement {
|
|
|
14
14
|
}
|
|
15
15
|
export declare function loadElementTitle(dfRef: ObjRef, dfIdentifier: string, attrElementUri: string, ctx: DashboardContext): SagaIterator<IDrillToUrlElement>;
|
|
16
16
|
export declare function loadSecondaryElementTitles(dfRef: ObjRef, attrElementValues: (string | null)[], ctx: DashboardContext): SagaIterator<Array<string | null>>;
|
|
17
|
+
/**
|
|
18
|
+
* @internal
|
|
19
|
+
*/
|
|
20
|
+
export declare function findDrillIntersectionAttributeHeaderItem(drillIntersectionElements: IDrillEventIntersectionElement[], displayForm: IAttributeDisplayFormMetadataObject): import("@gooddata/sdk-model").IResultAttributeHeaderItem | undefined;
|
|
17
21
|
export declare function splitDFToLoadingAndMapping(attributesDisplayForms: IAttributeDisplayFormMetadataObject[], ctx: DashboardContext): SagaIterator<{
|
|
18
22
|
displayFormsWithKnownValues: IAttributeDisplayFormMetadataObject[];
|
|
19
23
|
displayFormForValueLoad: IAttributeDisplayFormMetadataObject[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolveDrillToCustomUrl.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/drill/resolveDrillToCustomUrl.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAG/C,OAAO,EAEH,KAAK,4BAA4B,EACjC,KAAK,mCAAmC,EAExC,KAAK,iBAAiB,IAAI,sBAAsB,EAKhD,KAAK,2BAA2B,EAChC,KAAK,MAAM,EACX,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"resolveDrillToCustomUrl.d.ts","sourceRoot":"","sources":["../../../../src/model/commandHandlers/drill/resolveDrillToCustomUrl.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import stringify from "json-stable-stringify";
|
|
3
3
|
import { groupBy } from "lodash-es";
|
|
4
4
|
import { all, call, select } from "redux-saga/effects";
|
|
5
|
-
import { areObjRefsEqual, dashboardAttributeFilterItemDisplayForm, dashboardFilterObjRef, filterAttributeElements, filterObjRef, idRef, insightFilters as insightDefinitionFilters, insightId, isArbitraryAttributeFilter, isAttributeDescriptor, isAttributeElementsByValue, isComparisonCondition, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardTextAttributeFilter, isMeasureValueFilter, isNegativeAttributeFilter, isRangeCondition, isTextAttributeFilter, measureValueFilterConditions, measureValueFilterMeasure, } from "@gooddata/sdk-model";
|
|
5
|
+
import { areObjRefsEqual, dashboardAttributeFilterItemDisplayForm, dashboardFilterObjRef, filterAttributeElements, filterObjRef, idRef, insightFilters as insightDefinitionFilters, insightId, isArbitraryAttributeFilter, isAttributeDescriptor, isAttributeElementsByValue, isComparisonCondition, isDashboardArbitraryAttributeFilter, isDashboardAttributeFilter, isDashboardTextAttributeFilter, isIdentifierRef, isMeasureValueFilter, isNegativeAttributeFilter, isRangeCondition, isTextAttributeFilter, isUriRef, measureValueFilterConditions, measureValueFilterMeasure, } from "@gooddata/sdk-model";
|
|
6
6
|
import { getAttributeIdentifiersPlaceholdersFromUrl, getDashboardAttributeFilterPlaceholdersFromUrl, getDashboardMeasureValueFilterPlaceholdersFromUrl, getInsightAttributeFilterPlaceholdersFromUrl, getInsightMeasureValueFilterPlaceholdersFromUrl, } from "@gooddata/sdk-model/internal";
|
|
7
7
|
import { isDrillIntersectionAttributeItem, } from "@gooddata/sdk-ui";
|
|
8
8
|
import { invalidArgumentsProvided } from "../../events/general.js";
|
|
@@ -32,11 +32,74 @@ export function* loadSecondaryElementTitles(dfRef, attrElementValues, ctx) {
|
|
|
32
32
|
function isInRefList(list, ref) {
|
|
33
33
|
return list.some((itemRef) => areObjRefsEqual(itemRef, ref));
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
/**
|
|
36
|
+
* Tolerant ObjRef match used when resolving drill-to-URL placeholders against a drill intersection.
|
|
37
|
+
*
|
|
38
|
+
* The intersection comes from the execution result while the display-form metadata comes from the
|
|
39
|
+
* metadata API; the two can describe the same object with refs that differ in shape (idRef vs uriRef)
|
|
40
|
+
* or in `type`. The strict {@link areObjRefsEqual} then returns false and silently breaks
|
|
41
|
+
* `attribute_title(...)` resolution. This compares by the underlying identifier/uri, ignoring those
|
|
42
|
+
* representational differences.
|
|
43
|
+
*/
|
|
44
|
+
function refsMatchTolerant(a, b) {
|
|
45
|
+
if (!a || !b) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
if (areObjRefsEqual(a, b)) {
|
|
49
|
+
return true;
|
|
50
|
+
}
|
|
51
|
+
const keyOf = (ref) => isIdentifierRef(ref) ? ref.identifier : isUriRef(ref) ? ref.uri : undefined;
|
|
52
|
+
const keyA = keyOf(a);
|
|
53
|
+
return keyA !== undefined && keyA === keyOf(b);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
export function findDrillIntersectionAttributeHeaderItem(drillIntersectionElements, displayForm) {
|
|
59
|
+
const intersectionForAttribute = drillIntersectionElements.find(({ header }) => {
|
|
60
|
+
if (!isAttributeDescriptor(header)) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
const { identifier, ref: labelRef, formOf } = header.attributeHeader;
|
|
64
|
+
// A placeholder names a display form by identifier. Match that identifier string directly —
|
|
65
|
+
// it is immune to ObjRef shape/type differences between the execution result and the
|
|
66
|
+
// metadata API. Fall back to tolerant ref matches on the display form and its parent
|
|
67
|
+
// attribute so a differently-labelled column on the same attribute still resolves.
|
|
68
|
+
return (displayForm.id === identifier ||
|
|
69
|
+
refsMatchTolerant(displayForm.ref, labelRef) ||
|
|
70
|
+
refsMatchTolerant(displayForm.attribute, formOf.ref));
|
|
71
|
+
});
|
|
37
72
|
if (intersectionForAttribute && isDrillIntersectionAttributeItem(intersectionForAttribute.header)) {
|
|
73
|
+
const { attributeHeader } = intersectionForAttribute.header;
|
|
74
|
+
// Tripwire: if the strict comparison the resolver relied on before (attribute ref equality)
|
|
75
|
+
// would NOT have matched this element, the tolerant fallback / identifier match rescued it.
|
|
76
|
+
// That means the execution result and the metadata API disagree on the attribute's ObjRef
|
|
77
|
+
// representation — the drill still works, but the underlying (likely backend) mismatch should
|
|
78
|
+
// be known and fixed at the source.
|
|
79
|
+
if (!areObjRefsEqual(displayForm.attribute, attributeHeader.formOf.ref)) {
|
|
80
|
+
console.warn(`Drill to custom URL: attribute "${displayForm.id}" matched the drill intersection only via a tolerant reference comparison; the execution result and metadata report different references for the same attribute.`, {
|
|
81
|
+
displayFormAttributeRef: displayForm.attribute,
|
|
82
|
+
intersectionAttributeRef: attributeHeader.formOf.ref,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
38
85
|
return intersectionForAttribute.header.attributeHeaderItem;
|
|
39
86
|
}
|
|
87
|
+
// No matching attribute element in the intersection — the {attribute_title(...)} placeholder will
|
|
88
|
+
// stay unresolved and the drill will fail with "Failed to load URL". Log what we looked for vs. what
|
|
89
|
+
// the intersection actually carried, so the cause (cross-API ref differences, or a drilled column
|
|
90
|
+
// that does not carry the referenced attribute) is diagnosable from the console alone.
|
|
91
|
+
const intersectionAttributes = drillIntersectionElements
|
|
92
|
+
.map(({ header }) => (isAttributeDescriptor(header) ? header.attributeHeader : undefined))
|
|
93
|
+
.filter((attributeHeader) => !!attributeHeader)
|
|
94
|
+
.map((attributeHeader) => ({
|
|
95
|
+
identifier: attributeHeader.identifier,
|
|
96
|
+
ref: attributeHeader.ref,
|
|
97
|
+
attribute: attributeHeader.formOf.ref,
|
|
98
|
+
}));
|
|
99
|
+
console.warn(`Drill to custom URL: attribute "${displayForm.id}" referenced by an attribute_title placeholder was not found in the drill intersection.`, {
|
|
100
|
+
wanted: { id: displayForm.id, ref: displayForm.ref, attribute: displayForm.attribute },
|
|
101
|
+
intersectionAttributes,
|
|
102
|
+
});
|
|
40
103
|
return undefined;
|
|
41
104
|
}
|
|
42
105
|
export function* splitDFToLoadingAndMapping(attributesDisplayForms, ctx) {
|
|
@@ -59,20 +122,20 @@ export function* splitDFToLoadingAndMapping(attributesDisplayForms, ctx) {
|
|
|
59
122
|
export function* loadAttributeElementsForDrillIntersection(drillIntersectionElements, attributesDisplayForms, ctx) {
|
|
60
123
|
const splitDisplayForms = yield call(splitDFToLoadingAndMapping, attributesDisplayForms, ctx);
|
|
61
124
|
const { displayFormsWithKnownValues, displayFormForValueLoad } = splitDisplayForms;
|
|
62
|
-
const mappedElements = displayFormsWithKnownValues.reduce((acc,
|
|
63
|
-
const attributeHeaderItem = findDrillIntersectionAttributeHeaderItem(drillIntersectionElements,
|
|
125
|
+
const mappedElements = displayFormsWithKnownValues.reduce((acc, displayForm) => {
|
|
126
|
+
const attributeHeaderItem = findDrillIntersectionAttributeHeaderItem(drillIntersectionElements, displayForm);
|
|
64
127
|
if (!attributeHeaderItem) {
|
|
65
128
|
return acc;
|
|
66
129
|
}
|
|
67
130
|
acc.push({
|
|
68
|
-
identifier:
|
|
131
|
+
identifier: displayForm.id,
|
|
69
132
|
elementTitle: attributeHeaderItem.uri,
|
|
70
133
|
});
|
|
71
134
|
return acc;
|
|
72
135
|
}, []);
|
|
73
136
|
const loadedElement = yield all(displayFormForValueLoad.reduce((acc, displayForm) => {
|
|
74
|
-
const { id: dfIdentifier,
|
|
75
|
-
const attributeHeaderItem = findDrillIntersectionAttributeHeaderItem(drillIntersectionElements,
|
|
137
|
+
const { id: dfIdentifier, ref: dfRef } = displayForm;
|
|
138
|
+
const attributeHeaderItem = findDrillIntersectionAttributeHeaderItem(drillIntersectionElements, displayForm);
|
|
76
139
|
if (!attributeHeaderItem) {
|
|
77
140
|
return acc;
|
|
78
141
|
}
|
|
@@ -277,15 +340,20 @@ export function* resolveDrillToCustomUrl(drillConfig, widgetRef, event, ctx, cmd
|
|
|
277
340
|
toBeReplaced: placeholder,
|
|
278
341
|
replacement: undefined,
|
|
279
342
|
}));
|
|
280
|
-
const
|
|
343
|
+
const missingReplacements = [
|
|
281
344
|
...attributeIdentifiersReplacements,
|
|
282
345
|
...dashboardAttributeFilterReplacements,
|
|
283
346
|
...insightAttributeFilterReplacements,
|
|
284
347
|
...dashboardMeasureValueFilterReplacements,
|
|
285
348
|
...insightMeasureValueFilterReplacements,
|
|
286
|
-
].
|
|
287
|
-
if (
|
|
288
|
-
|
|
349
|
+
].filter(({ replacement }) => replacement === undefined);
|
|
350
|
+
if (missingReplacements.length > 0) {
|
|
351
|
+
// Surface every unresolved placeholder (not just the first) and the URL, so a "Failed to load
|
|
352
|
+
// URL" is diagnosable from the console without a debugger.
|
|
353
|
+
console.warn(`Drill to custom URL: could not resolve parameter(s) ${missingReplacements
|
|
354
|
+
.map(({ toBeReplaced }) => toBeReplaced)
|
|
355
|
+
.join(", ")} in URL "${customUrl}". The drill cannot open.`);
|
|
356
|
+
throw invalidArgumentsProvided(ctx, cmd, `Drill to custom URL unable to resolve missing parameter ${missingReplacements[0].toBeReplaced}`);
|
|
289
357
|
}
|
|
290
358
|
const insightIdentifiersReplacements = yield call(getInsightIdentifiersReplacements, customUrl, widgetRef, ctx);
|
|
291
359
|
const replacements = [
|
|
@@ -575,7 +575,7 @@ export const selectEnableSlideshowExports = createSelector(selectConfig, (state)
|
|
|
575
575
|
* @internal
|
|
576
576
|
*/
|
|
577
577
|
export const selectEnableExportTemplateSelection = createSelector(selectConfig, (state) => {
|
|
578
|
-
return state.settings?.enableExportTemplateSelection ??
|
|
578
|
+
return state.settings?.enableExportTemplateSelection ?? true;
|
|
579
579
|
});
|
|
580
580
|
/**
|
|
581
581
|
* @internal
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-dashboard",
|
|
3
|
-
"version": "11.41.0
|
|
3
|
+
"version": "11.41.0",
|
|
4
4
|
"description": "GoodData SDK - Dashboard Component",
|
|
5
5
|
"license": "LicenseRef-LICENSE",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -60,19 +60,19 @@
|
|
|
60
60
|
"ts-invariant": "0.10.3",
|
|
61
61
|
"tslib": "2.8.1",
|
|
62
62
|
"uuid": "11.1.1",
|
|
63
|
-
"@gooddata/sdk-backend-base": "11.41.0
|
|
64
|
-
"@gooddata/sdk-backend-spi": "11.41.0
|
|
65
|
-
"@gooddata/sdk-
|
|
66
|
-
"@gooddata/sdk-
|
|
67
|
-
"@gooddata/sdk-ui-charts": "11.41.0
|
|
68
|
-
"@gooddata/sdk-ui-ext": "11.41.0
|
|
69
|
-
"@gooddata/sdk-ui-filters": "11.41.0
|
|
70
|
-
"@gooddata/sdk-ui-geo": "11.41.0
|
|
71
|
-
"@gooddata/sdk-ui-kit": "11.41.0
|
|
72
|
-
"@gooddata/sdk-ui-pivot": "11.41.0
|
|
73
|
-
"@gooddata/sdk-ui-
|
|
74
|
-
"@gooddata/
|
|
75
|
-
"@gooddata/
|
|
63
|
+
"@gooddata/sdk-backend-base": "11.41.0",
|
|
64
|
+
"@gooddata/sdk-backend-spi": "11.41.0",
|
|
65
|
+
"@gooddata/sdk-model": "11.41.0",
|
|
66
|
+
"@gooddata/sdk-ui": "11.41.0",
|
|
67
|
+
"@gooddata/sdk-ui-charts": "11.41.0",
|
|
68
|
+
"@gooddata/sdk-ui-ext": "11.41.0",
|
|
69
|
+
"@gooddata/sdk-ui-filters": "11.41.0",
|
|
70
|
+
"@gooddata/sdk-ui-geo": "11.41.0",
|
|
71
|
+
"@gooddata/sdk-ui-kit": "11.41.0",
|
|
72
|
+
"@gooddata/sdk-ui-pivot": "11.41.0",
|
|
73
|
+
"@gooddata/sdk-ui-theme-provider": "11.41.0",
|
|
74
|
+
"@gooddata/sdk-ui-vis-commons": "11.41.0",
|
|
75
|
+
"@gooddata/util": "11.41.0"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@microsoft/api-documenter": "^7.17.0",
|
|
@@ -118,12 +118,12 @@
|
|
|
118
118
|
"typescript": "5.9.3",
|
|
119
119
|
"vitest": "4.1.8",
|
|
120
120
|
"vitest-dom": "0.1.1",
|
|
121
|
-
"@gooddata/eslint-config": "11.41.0
|
|
122
|
-
"@gooddata/
|
|
123
|
-
"@gooddata/
|
|
124
|
-
"@gooddata/
|
|
125
|
-
"@gooddata/
|
|
126
|
-
"@gooddata/stylelint-config": "11.41.0
|
|
121
|
+
"@gooddata/eslint-config": "11.41.0",
|
|
122
|
+
"@gooddata/i18n-toolkit": "11.41.0",
|
|
123
|
+
"@gooddata/oxlint-config": "11.41.0",
|
|
124
|
+
"@gooddata/reference-workspace": "11.41.0",
|
|
125
|
+
"@gooddata/sdk-backend-mockingbird": "11.41.0",
|
|
126
|
+
"@gooddata/stylelint-config": "11.41.0"
|
|
127
127
|
},
|
|
128
128
|
"peerDependencies": {
|
|
129
129
|
"react": "^18.0.0 || ^19.0.0",
|
package/styles/css/main.css
CHANGED
|
@@ -6725,9 +6725,6 @@ input[type=search]::-webkit-search-cancel-button {
|
|
|
6725
6725
|
.gd-attribute-filter-dropdown-button__next,
|
|
6726
6726
|
.gd-mvf-dashboard-filter-button__next {
|
|
6727
6727
|
position: relative;
|
|
6728
|
-
max-width: 230px;
|
|
6729
|
-
padding: 5px 10px;
|
|
6730
|
-
font-size: 12px;
|
|
6731
6728
|
line-height: 16px;
|
|
6732
6729
|
}
|
|
6733
6730
|
|
|
@@ -6796,6 +6793,18 @@ input[type=search]::-webkit-search-cancel-button {
|
|
|
6796
6793
|
font-weight: 400;
|
|
6797
6794
|
}
|
|
6798
6795
|
|
|
6796
|
+
.gd-attribute-filter-dropdown-button__next:not(.gd-ui-kit-control-button),
|
|
6797
|
+
.gd-mvf-dashboard-filter-button__next:not(.gd-ui-kit-control-button) {
|
|
6798
|
+
max-width: 230px;
|
|
6799
|
+
padding: 5px 10px;
|
|
6800
|
+
font-size: 12px;
|
|
6801
|
+
}
|
|
6802
|
+
|
|
6803
|
+
.gd-attribute-filter-dropdown-button__next:not(.gd-ui-kit-control-button).gd-is-draggable,
|
|
6804
|
+
.gd-mvf-dashboard-filter-button__next:not(.gd-ui-kit-control-button).gd-is-draggable {
|
|
6805
|
+
padding-left: 23px;
|
|
6806
|
+
}
|
|
6807
|
+
|
|
6799
6808
|
.gd-attribute-filter-mobile-button-wrapper {
|
|
6800
6809
|
display: flex;
|
|
6801
6810
|
align-items: center;
|
|
@@ -6808,7 +6817,6 @@ input[type=search]::-webkit-search-cancel-button {
|
|
|
6808
6817
|
}
|
|
6809
6818
|
|
|
6810
6819
|
.gd-is-mobile .gd-attribute-filter-dropdown-button__next .gd-ui-kit-control-button__content {
|
|
6811
|
-
padding-right: 20px;
|
|
6812
6820
|
flex-direction: row;
|
|
6813
6821
|
align-items: center;
|
|
6814
6822
|
}
|
|
@@ -6827,8 +6835,14 @@ input[type=search]::-webkit-search-cancel-button {
|
|
|
6827
6835
|
background-image: none;
|
|
6828
6836
|
}
|
|
6829
6837
|
|
|
6830
|
-
.gd-is-mobile .gd-attribute-filter-
|
|
6831
|
-
|
|
6838
|
+
.gd-is-mobile .gd-attribute-filter-button-wrapper {
|
|
6839
|
+
flex: 1;
|
|
6840
|
+
min-width: 0;
|
|
6841
|
+
}
|
|
6842
|
+
|
|
6843
|
+
.gd-is-mobile .gd-attribute-filter-button-wrapper .gd-bubble-trigger {
|
|
6844
|
+
display: block;
|
|
6845
|
+
width: 100%;
|
|
6832
6846
|
}
|
|
6833
6847
|
|
|
6834
6848
|
.gd-is-mobile--with-menu {
|
|
@@ -6837,8 +6851,6 @@ input[type=search]::-webkit-search-cancel-button {
|
|
|
6837
6851
|
}
|
|
6838
6852
|
|
|
6839
6853
|
.gd-is-mobile--with-menu .gd-attribute-filter-dropdown-button__next.gd-is-active {
|
|
6840
|
-
height: 45px;
|
|
6841
|
-
padding: 0 10px;
|
|
6842
6854
|
border-radius: 0;
|
|
6843
6855
|
background-color: var(--gd-palette-complementary-0, #fff);
|
|
6844
6856
|
}
|
|
@@ -6903,30 +6915,6 @@ input[type=search]::-webkit-search-cancel-button {
|
|
|
6903
6915
|
display: none;
|
|
6904
6916
|
}
|
|
6905
6917
|
|
|
6906
|
-
.overlay .gd-attribute-filter-dropdown-button__next .gd-ui-kit-control-button__title {
|
|
6907
|
-
flex: 0 0 auto;
|
|
6908
|
-
max-width: 100%;
|
|
6909
|
-
margin-right: 5px;
|
|
6910
|
-
color: var(--gd-palette-complementary-7, #6d7680);
|
|
6911
|
-
}
|
|
6912
|
-
|
|
6913
|
-
.overlay .gd-attribute-filter-dropdown-button__next .gd-ui-kit-control-button__title::after {
|
|
6914
|
-
content: ":";
|
|
6915
|
-
}
|
|
6916
|
-
|
|
6917
|
-
.overlay .gd-attribute-filter-dropdown-button__next .gd-ui-kit-control-button__subtitle-row {
|
|
6918
|
-
flex: 1 1 auto;
|
|
6919
|
-
max-width: none;
|
|
6920
|
-
}
|
|
6921
|
-
|
|
6922
|
-
.overlay .gd-attribute-filter-dropdown-button__next .gd-ui-kit-control-button__subtitle-row::after {
|
|
6923
|
-
position: absolute;
|
|
6924
|
-
top: 50%;
|
|
6925
|
-
right: -20px;
|
|
6926
|
-
font-size: 18px;
|
|
6927
|
-
transform: translateY(-50%);
|
|
6928
|
-
}
|
|
6929
|
-
|
|
6930
6918
|
.gd-attribute-filter-dropdown-button-selected-items__next,
|
|
6931
6919
|
.gd-measure-value-filter-dropdown-button-selected-items__next {
|
|
6932
6920
|
display: inline-block;
|
|
@@ -7338,6 +7326,10 @@ div.gd-empty-item-bubble {
|
|
|
7338
7326
|
opacity: 1;
|
|
7339
7327
|
}
|
|
7340
7328
|
|
|
7329
|
+
.gd-is-mobile .gd-attribute-filter-dropdown-button__next.gd-message.error {
|
|
7330
|
+
width: 100%;
|
|
7331
|
+
}
|
|
7332
|
+
|
|
7341
7333
|
.overlay.dropdown-body:has(.gd-filter-menu__dropdown) {
|
|
7342
7334
|
width: max-content;
|
|
7343
7335
|
}
|
|
@@ -19031,9 +19023,6 @@ a.gd-button-link:hover .gd-button-text, a.gd-button-link-dimmed:hover .gd-button
|
|
|
19031
19023
|
.gd-attribute-filter-dropdown-button__next,
|
|
19032
19024
|
.gd-mvf-dashboard-filter-button__next {
|
|
19033
19025
|
position: relative;
|
|
19034
|
-
max-width: 230px;
|
|
19035
|
-
padding: 5px 10px;
|
|
19036
|
-
font-size: 12px;
|
|
19037
19026
|
line-height: 16px;
|
|
19038
19027
|
}
|
|
19039
19028
|
|
|
@@ -19102,6 +19091,18 @@ a.gd-button-link:hover .gd-button-text, a.gd-button-link-dimmed:hover .gd-button
|
|
|
19102
19091
|
font-weight: 400;
|
|
19103
19092
|
}
|
|
19104
19093
|
|
|
19094
|
+
.gd-attribute-filter-dropdown-button__next:not(.gd-ui-kit-control-button),
|
|
19095
|
+
.gd-mvf-dashboard-filter-button__next:not(.gd-ui-kit-control-button) {
|
|
19096
|
+
max-width: 230px;
|
|
19097
|
+
padding: 5px 10px;
|
|
19098
|
+
font-size: 12px;
|
|
19099
|
+
}
|
|
19100
|
+
|
|
19101
|
+
.gd-attribute-filter-dropdown-button__next:not(.gd-ui-kit-control-button).gd-is-draggable,
|
|
19102
|
+
.gd-mvf-dashboard-filter-button__next:not(.gd-ui-kit-control-button).gd-is-draggable {
|
|
19103
|
+
padding-left: 23px;
|
|
19104
|
+
}
|
|
19105
|
+
|
|
19105
19106
|
.gd-attribute-filter-mobile-button-wrapper {
|
|
19106
19107
|
display: flex;
|
|
19107
19108
|
align-items: center;
|
|
@@ -19114,7 +19115,6 @@ a.gd-button-link:hover .gd-button-text, a.gd-button-link-dimmed:hover .gd-button
|
|
|
19114
19115
|
}
|
|
19115
19116
|
|
|
19116
19117
|
.gd-is-mobile .gd-attribute-filter-dropdown-button__next .gd-ui-kit-control-button__content {
|
|
19117
|
-
padding-right: 20px;
|
|
19118
19118
|
flex-direction: row;
|
|
19119
19119
|
align-items: center;
|
|
19120
19120
|
}
|
|
@@ -19133,8 +19133,14 @@ a.gd-button-link:hover .gd-button-text, a.gd-button-link-dimmed:hover .gd-button
|
|
|
19133
19133
|
background-image: none;
|
|
19134
19134
|
}
|
|
19135
19135
|
|
|
19136
|
-
.gd-is-mobile .gd-attribute-filter-
|
|
19137
|
-
|
|
19136
|
+
.gd-is-mobile .gd-attribute-filter-button-wrapper {
|
|
19137
|
+
flex: 1;
|
|
19138
|
+
min-width: 0;
|
|
19139
|
+
}
|
|
19140
|
+
|
|
19141
|
+
.gd-is-mobile .gd-attribute-filter-button-wrapper .gd-bubble-trigger {
|
|
19142
|
+
display: block;
|
|
19143
|
+
width: 100%;
|
|
19138
19144
|
}
|
|
19139
19145
|
|
|
19140
19146
|
.gd-is-mobile--with-menu {
|
|
@@ -19143,8 +19149,6 @@ a.gd-button-link:hover .gd-button-text, a.gd-button-link-dimmed:hover .gd-button
|
|
|
19143
19149
|
}
|
|
19144
19150
|
|
|
19145
19151
|
.gd-is-mobile--with-menu .gd-attribute-filter-dropdown-button__next.gd-is-active {
|
|
19146
|
-
height: 45px;
|
|
19147
|
-
padding: 0 10px;
|
|
19148
19152
|
border-radius: 0;
|
|
19149
19153
|
background-color: var(--gd-palette-complementary-0, #fff);
|
|
19150
19154
|
}
|
|
@@ -19209,30 +19213,6 @@ a.gd-button-link:hover .gd-button-text, a.gd-button-link-dimmed:hover .gd-button
|
|
|
19209
19213
|
display: none;
|
|
19210
19214
|
}
|
|
19211
19215
|
|
|
19212
|
-
.overlay .gd-attribute-filter-dropdown-button__next .gd-ui-kit-control-button__title {
|
|
19213
|
-
flex: 0 0 auto;
|
|
19214
|
-
max-width: 100%;
|
|
19215
|
-
margin-right: 5px;
|
|
19216
|
-
color: var(--gd-palette-complementary-7, #6d7680);
|
|
19217
|
-
}
|
|
19218
|
-
|
|
19219
|
-
.overlay .gd-attribute-filter-dropdown-button__next .gd-ui-kit-control-button__title::after {
|
|
19220
|
-
content: ":";
|
|
19221
|
-
}
|
|
19222
|
-
|
|
19223
|
-
.overlay .gd-attribute-filter-dropdown-button__next .gd-ui-kit-control-button__subtitle-row {
|
|
19224
|
-
flex: 1 1 auto;
|
|
19225
|
-
max-width: none;
|
|
19226
|
-
}
|
|
19227
|
-
|
|
19228
|
-
.overlay .gd-attribute-filter-dropdown-button__next .gd-ui-kit-control-button__subtitle-row::after {
|
|
19229
|
-
position: absolute;
|
|
19230
|
-
top: 50%;
|
|
19231
|
-
right: -20px;
|
|
19232
|
-
font-size: 18px;
|
|
19233
|
-
transform: translateY(-50%);
|
|
19234
|
-
}
|
|
19235
|
-
|
|
19236
19216
|
.gd-attribute-filter-dropdown-button-selected-items__next,
|
|
19237
19217
|
.gd-measure-value-filter-dropdown-button-selected-items__next {
|
|
19238
19218
|
display: inline-block;
|
|
@@ -19644,6 +19624,10 @@ div.gd-empty-item-bubble {
|
|
|
19644
19624
|
opacity: 1;
|
|
19645
19625
|
}
|
|
19646
19626
|
|
|
19627
|
+
.gd-is-mobile .gd-attribute-filter-dropdown-button__next.gd-message.error {
|
|
19628
|
+
width: 100%;
|
|
19629
|
+
}
|
|
19630
|
+
|
|
19647
19631
|
.overlay.dropdown-body:has(.gd-filter-menu__dropdown) {
|
|
19648
19632
|
width: max-content;
|
|
19649
19633
|
}
|