@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.
@@ -1,4 +1,4 @@
1
- export declare const LIB_VERSION = "11.41.0-alpha.5";
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
@@ -1 +1 @@
1
- {"version":3,"file":"__version.d.ts","sourceRoot":"","sources":["../src/__version.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,WAAW,oBAAoB,CAAC;AAE7C,eAAO,MAAM,eAAe,uCAAuC,CAAC;AAEpE,eAAO,MAAM,QAAQ,+BAA+B,CAAC"}
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-alpha.5";
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,CA6ChC"}
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,CA6B3B"}
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
- const resolvedFilterValues = yield call(resolveFilterValues, resolvableFilters, ctx.backend, ctx.workspace);
22
- return { filters, resolvedFilterValues };
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":"AAEA,OAAO,EAAE,KAAK,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,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,CAqBxB;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
+ {"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
- return validElementsQuery.items[0].title;
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,EAsB3B,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EACH,KAAK,WAAW,EAChB,KAAK,8BAA8B,EAEtC,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAkBjE,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAUnE,UAAU,iCAAiC;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,UAAU,kBAAkB;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,wBAAiB,gBAAgB,CAC7B,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,EACtB,GAAG,EAAE,gBAAgB,GACtB,YAAY,CAAC,kBAAkB,CAAC,CAYlC;AAED,wBAAiB,0BAA0B,CACvC,KAAK,EAAE,MAAM,EACb,iBAAiB,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EACpC,GAAG,EAAE,gBAAgB,GACtB,YAAY,CAAC,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CASpC;AAsBD,wBAAiB,0BAA0B,CACvC,sBAAsB,EAAE,mCAAmC,EAAE,EAC7D,GAAG,EAAE,gBAAgB,GACtB,YAAY,CAAC;IACZ,2BAA2B,EAAE,mCAAmC,EAAE,CAAC;IACnE,uBAAuB,EAAE,mCAAmC,EAAE,CAAC;CAClE,CAAC,CAuBD;AAED,wBAAiB,yCAAyC,CACtD,yBAAyB,EAAE,8BAA8B,EAAE,EAC3D,sBAAsB,EAAE,mCAAmC,EAAE,EAC7D,GAAG,EAAE,gBAAgB,GACtB,YAAY,CAAC,kBAAkB,EAAE,CAAC,CA8CpC;AAKD,wBAAgB,wBAAwB,CACpC,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EAAE,EACjB,GAAG,EAAE,gBAAgB,GACtB,OAAO,CAAC,mCAAmC,EAAE,CAAC,CAEhD;AAED,wBAAiB,mCAAmC,CAChD,GAAG,EAAE,MAAM,EACX,yBAAyB,EAAE,8BAA8B,EAAE,EAC3D,GAAG,EAAE,gBAAgB,GACtB,YAAY,CAAC,iCAAiC,EAAE,CAAC,CAkCnD;AAuED,wBAAiB,uCAAuC,CACpD,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,gBAAgB,GACtB,YAAY,CAAC,iCAAiC,EAAE,CAAC,CA8BnD;AAwBD,wBAAiB,0CAA0C,CACvD,GAAG,EAAE,MAAM,GACZ,YAAY,CAAC,iCAAiC,EAAE,CAAC,CAgBnD;AAsBD,wBAAiB,wCAAwC,CACrD,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAClB,YAAY,CAAC,iCAAiC,EAAE,CAAC,CAgBnD;AAED,wBAAiB,qCAAqC,CAClD,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,GAClB,YAAY,CAAC,iCAAiC,EAAE,CAAC,CAyCnD;AAOD,wBAAiB,iCAAiC,CAC9C,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,gBAAgB,GACtB,YAAY,CAAC,iCAAiC,EAAE,CAAC,CAwCnD;AAYD,wBAAiB,uBAAuB,CACpC,WAAW,EAAE,sBAAsB,EACnC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,WAAW,EAClB,GAAG,EAAE,gBAAgB,EACrB,GAAG,EAAE,iBAAiB,GACvB,YAAY,CAAC,MAAM,CAAC,CAuEtB;AAMD;;GAEG;AACH,wBAAgB,4BAA4B,CACxC,MAAM,EAAE,4BAA4B,GAAG,mBAAmB,GAC3D,MAAM,CAOR;AAcD;;GAEG;AACH,wBAAgB,oCAAoC,CAChD,UAAU,EAAE,2BAA2B,EAAE,GAAG,SAAS,GACtD,MAAM,CAgBR"}
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
- function findDrillIntersectionAttributeHeaderItem(drillIntersectionElements, attributeRef) {
36
- const intersectionForAttribute = drillIntersectionElements.find(({ header }) => isAttributeDescriptor(header) && areObjRefsEqual(attributeRef, header.attributeHeader.formOf.ref));
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, { id: dfIdentifier, attribute }) => {
63
- const attributeHeaderItem = findDrillIntersectionAttributeHeaderItem(drillIntersectionElements, attribute);
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: dfIdentifier,
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, attribute, ref: dfRef } = displayForm;
75
- const attributeHeaderItem = findDrillIntersectionAttributeHeaderItem(drillIntersectionElements, attribute);
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 missingReplacement = [
343
+ const missingReplacements = [
281
344
  ...attributeIdentifiersReplacements,
282
345
  ...dashboardAttributeFilterReplacements,
283
346
  ...insightAttributeFilterReplacements,
284
347
  ...dashboardMeasureValueFilterReplacements,
285
348
  ...insightMeasureValueFilterReplacements,
286
- ].find(({ replacement }) => replacement === undefined);
287
- if (missingReplacement) {
288
- throw invalidArgumentsProvided(ctx, cmd, `Drill to custom URL unable to resolve missing parameter ${missingReplacement.toBeReplaced}`);
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 ?? false;
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-alpha.5",
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-alpha.5",
64
- "@gooddata/sdk-backend-spi": "11.41.0-alpha.5",
65
- "@gooddata/sdk-ui": "11.41.0-alpha.5",
66
- "@gooddata/sdk-model": "11.41.0-alpha.5",
67
- "@gooddata/sdk-ui-charts": "11.41.0-alpha.5",
68
- "@gooddata/sdk-ui-ext": "11.41.0-alpha.5",
69
- "@gooddata/sdk-ui-filters": "11.41.0-alpha.5",
70
- "@gooddata/sdk-ui-geo": "11.41.0-alpha.5",
71
- "@gooddata/sdk-ui-kit": "11.41.0-alpha.5",
72
- "@gooddata/sdk-ui-pivot": "11.41.0-alpha.5",
73
- "@gooddata/sdk-ui-vis-commons": "11.41.0-alpha.5",
74
- "@gooddata/util": "11.41.0-alpha.5",
75
- "@gooddata/sdk-ui-theme-provider": "11.41.0-alpha.5"
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-alpha.5",
122
- "@gooddata/oxlint-config": "11.41.0-alpha.5",
123
- "@gooddata/i18n-toolkit": "11.41.0-alpha.5",
124
- "@gooddata/sdk-backend-mockingbird": "11.41.0-alpha.5",
125
- "@gooddata/reference-workspace": "11.41.0-alpha.5",
126
- "@gooddata/stylelint-config": "11.41.0-alpha.5"
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",
@@ -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-dropdown-button__next.gd-is-active .gd-ui-kit-control-button__subtitle-row::after {
6831
- right: 0;
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-dropdown-button__next.gd-is-active .gd-ui-kit-control-button__subtitle-row::after {
19137
- right: 0;
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
  }