@gooddata/sdk-ui-vis-commons 11.41.0-alpha.0 → 11.41.0-alpha.1
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/customTooltip/composeSectionHtml.d.ts +2 -2
- package/esm/customTooltip/composeSectionHtml.js +2 -2
- package/esm/customTooltip/localizedStrings.d.ts +11 -0
- package/esm/customTooltip/localizedStrings.js +22 -0
- package/esm/customTooltip/referenceResolver.d.ts +5 -5
- package/esm/customTooltip/referenceResolver.js +24 -6
- package/esm/customTooltip/referenceStatus.d.ts +22 -0
- package/esm/customTooltip/referenceStatus.js +33 -0
- package/esm/customTooltip/tooltipExecution.d.ts +17 -1
- package/esm/customTooltip/tooltipExecution.js +40 -18
- package/esm/customTooltip/tooltipLookup.d.ts +3 -11
- package/esm/customTooltip/tooltipLookup.js +8 -25
- package/esm/customTooltip/types.d.ts +50 -2
- package/esm/customTooltip/types.js +15 -1
- package/esm/customTooltip/useTooltipLookupExecutions.d.ts +23 -12
- package/esm/customTooltip/useTooltipLookupExecutions.js +73 -23
- package/esm/index.d.ts +6 -4
- package/esm/index.js +3 -0
- package/esm/sdk-ui-vis-commons.d.ts +126 -20
- package/package.json +11 -11
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IResolvedReferenceValues } from "./types.js";
|
|
1
|
+
import { type IResolvedReferenceValues, type ITooltipLocalizedStrings } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Merge order matters: in-chart values override external ones, because the
|
|
4
4
|
* in-chart value is what the user already sees on the rendered point/feature.
|
|
@@ -7,4 +7,4 @@ import { type IResolvedReferenceValues } from "./types.js";
|
|
|
7
7
|
*
|
|
8
8
|
* @internal
|
|
9
9
|
*/
|
|
10
|
-
export declare function composeCustomTooltipSectionHtml(content: string, inChartValues: IResolvedReferenceValues, externalValues: IResolvedReferenceValues,
|
|
10
|
+
export declare function composeCustomTooltipSectionHtml(content: string, inChartValues: IResolvedReferenceValues, externalValues: IResolvedReferenceValues, localizedStrings: ITooltipLocalizedStrings): string;
|
|
@@ -9,8 +9,8 @@ import { resolveReferences } from "./referenceResolver.js";
|
|
|
9
9
|
*
|
|
10
10
|
* @internal
|
|
11
11
|
*/
|
|
12
|
-
export function composeCustomTooltipSectionHtml(content, inChartValues, externalValues,
|
|
12
|
+
export function composeCustomTooltipSectionHtml(content, inChartValues, externalValues, localizedStrings) {
|
|
13
13
|
const merged = { ...externalValues, ...inChartValues };
|
|
14
|
-
const resolved = resolveReferences(content, merged,
|
|
14
|
+
const resolved = resolveReferences(content, merged, localizedStrings);
|
|
15
15
|
return `<div class="gd-viz-tooltip-custom-section">${markdownToHtml(resolved)}</div>`;
|
|
16
16
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type IntlShape } from "react-intl";
|
|
2
|
+
import { type ITooltipLocalizedStrings } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Builds the localized placeholder strings for the non-value reference states,
|
|
5
|
+
* shared by every tooltip consumer (Highcharts, geo) so the wording and the
|
|
6
|
+
* message ids live in one place. `intl` is optional — the Highcharts tooltip
|
|
7
|
+
* formatter receives it optionally — and falls back to English.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildTooltipLocalizedStrings(intl?: IntlShape): ITooltipLocalizedStrings;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { defineMessages } from "react-intl";
|
|
3
|
+
const messages = defineMessages({
|
|
4
|
+
noFetch: { id: "richText.no_fetch" },
|
|
5
|
+
noData: { id: "richText.no_data" },
|
|
6
|
+
multipleItems: { id: "richText.multiple_data" },
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* Builds the localized placeholder strings for the non-value reference states,
|
|
10
|
+
* shared by every tooltip consumer (Highcharts, geo) so the wording and the
|
|
11
|
+
* message ids live in one place. `intl` is optional — the Highcharts tooltip
|
|
12
|
+
* formatter receives it optionally — and falls back to English.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export function buildTooltipLocalizedStrings(intl) {
|
|
17
|
+
return {
|
|
18
|
+
noFetch: intl ? `(${intl.formatMessage(messages.noFetch)})` : "(Data could not be retrieved)",
|
|
19
|
+
noData: intl ? `(${intl.formatMessage(messages.noData)})` : "(No data)",
|
|
20
|
+
multipleItems: intl ? `(${intl.formatMessage(messages.multipleItems)})` : "(Multiple items)",
|
|
21
|
+
};
|
|
22
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type IResolvedReferenceValues } from "./types.js";
|
|
1
|
+
import { type IResolvedReferenceValues, type ITooltipLocalizedStrings } from "./types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Substitutes `{metric/id}` and `{label/id}` references in markdown content
|
|
4
4
|
* with resolved values from the lookup table.
|
|
@@ -9,11 +9,11 @@ import { type IResolvedReferenceValues } from "./types.js";
|
|
|
9
9
|
* unintended formatting. `markdownToHtml` understands the backslash escapes.
|
|
10
10
|
*
|
|
11
11
|
* @param content - Markdown content with reference placeholders
|
|
12
|
-
* @param values - Lookup of `metric/id` and `label/id` keys to
|
|
12
|
+
* @param values - Lookup of `metric/id` and `label/id` keys to resolved statuses.
|
|
13
13
|
* Keys must use a lowercase prefix; LDM identifiers are case-sensitive.
|
|
14
|
-
* @param
|
|
15
|
-
*
|
|
14
|
+
* @param strings - Localized placeholders for the non-value states (no data,
|
|
15
|
+
* multiple items, could-not-retrieve).
|
|
16
16
|
*
|
|
17
17
|
* @internal
|
|
18
18
|
*/
|
|
19
|
-
export declare function resolveReferences(content: string, values: IResolvedReferenceValues,
|
|
19
|
+
export declare function resolveReferences(content: string, values: IResolvedReferenceValues, strings: ITooltipLocalizedStrings): string;
|
|
@@ -9,6 +9,24 @@ const MARKDOWN_METACHARS = /[\\*_`\[\]()!#~+\-]/g;
|
|
|
9
9
|
function escapeMarkdownMetachars(value) {
|
|
10
10
|
return value.replace(MARKDOWN_METACHARS, "\\$&");
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Renders a single resolved reference status to its display string. A reference
|
|
14
|
+
* with no status at this point (e.g. an in-chart sibling not present on the
|
|
15
|
+
* hovered series) is surfaced as unretrievable rather than masked as "no data".
|
|
16
|
+
*/
|
|
17
|
+
function renderReference(ref, strings) {
|
|
18
|
+
switch (ref?.kind) {
|
|
19
|
+
case "value":
|
|
20
|
+
return ref.text;
|
|
21
|
+
case "empty":
|
|
22
|
+
return strings.noData;
|
|
23
|
+
case "multiple":
|
|
24
|
+
return strings.multipleItems;
|
|
25
|
+
case "error":
|
|
26
|
+
default:
|
|
27
|
+
return strings.noFetch;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
12
30
|
/**
|
|
13
31
|
* Substitutes `{metric/id}` and `{label/id}` references in markdown content
|
|
14
32
|
* with resolved values from the lookup table.
|
|
@@ -19,14 +37,14 @@ function escapeMarkdownMetachars(value) {
|
|
|
19
37
|
* unintended formatting. `markdownToHtml` understands the backslash escapes.
|
|
20
38
|
*
|
|
21
39
|
* @param content - Markdown content with reference placeholders
|
|
22
|
-
* @param values - Lookup of `metric/id` and `label/id` keys to
|
|
40
|
+
* @param values - Lookup of `metric/id` and `label/id` keys to resolved statuses.
|
|
23
41
|
* Keys must use a lowercase prefix; LDM identifiers are case-sensitive.
|
|
24
|
-
* @param
|
|
25
|
-
*
|
|
42
|
+
* @param strings - Localized placeholders for the non-value states (no data,
|
|
43
|
+
* multiple items, could-not-retrieve).
|
|
26
44
|
*
|
|
27
45
|
* @internal
|
|
28
46
|
*/
|
|
29
|
-
export function resolveReferences(content, values,
|
|
47
|
+
export function resolveReferences(content, values, strings) {
|
|
30
48
|
if (!content) {
|
|
31
49
|
return "";
|
|
32
50
|
}
|
|
@@ -34,7 +52,7 @@ export function resolveReferences(content, values, fallbackText) {
|
|
|
34
52
|
// The regex matches the prefix case-insensitively; storage uses
|
|
35
53
|
// lowercase prefixes so users can write either `{metric/foo}` or
|
|
36
54
|
// `{Metric/foo}`. LDM identifiers stay as-is — they are case-sensitive.
|
|
37
|
-
const
|
|
38
|
-
return escapeMarkdownMetachars(
|
|
55
|
+
const ref = values[`${prefix.toLowerCase()}/${identifier}`];
|
|
56
|
+
return escapeMarkdownMetachars(renderReference(ref, strings));
|
|
39
57
|
});
|
|
40
58
|
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ISeparators } from "@gooddata/sdk-model";
|
|
2
|
+
import { type ResolvedReference } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Maps a raw measure value to a {@link ResolvedReference} status: `null`/
|
|
5
|
+
* `undefined` → empty ("No data"); otherwise the formatted (or stringified)
|
|
6
|
+
* value. Shared by every tooltip resolver so the value→status mapping has a
|
|
7
|
+
* single home. Callers whose source can yield non-numeric / non-finite values
|
|
8
|
+
* (e.g. geo feature payloads) normalize those to `null` before calling.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export declare function measureReference(rawValue: number | string | null | undefined, format: string | undefined, separators?: ISeparators): ResolvedReference;
|
|
13
|
+
/**
|
|
14
|
+
* Maps a label/attribute display value to a {@link ResolvedReference} status:
|
|
15
|
+
* `null` / `undefined` / empty string → empty ("No data"); otherwise the value.
|
|
16
|
+
* Shared by every tooltip resolver so empty-value handling can't drift between
|
|
17
|
+
* the in-chart and external paths. The count-based "multiple" case stays with
|
|
18
|
+
* the caller (only the lookup builder knows the per-row count).
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function labelReference(value: string | number | null | undefined): ResolvedReference;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// (C) 2026 GoodData Corporation
|
|
2
|
+
import { ClientFormatterFacade } from "@gooddata/number-formatter";
|
|
3
|
+
/**
|
|
4
|
+
* Maps a raw measure value to a {@link ResolvedReference} status: `null`/
|
|
5
|
+
* `undefined` → empty ("No data"); otherwise the formatted (or stringified)
|
|
6
|
+
* value. Shared by every tooltip resolver so the value→status mapping has a
|
|
7
|
+
* single home. Callers whose source can yield non-numeric / non-finite values
|
|
8
|
+
* (e.g. geo feature payloads) normalize those to `null` before calling.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export function measureReference(rawValue, format, separators) {
|
|
13
|
+
if (rawValue == null) {
|
|
14
|
+
return { kind: "empty" };
|
|
15
|
+
}
|
|
16
|
+
if (format) {
|
|
17
|
+
const { formattedValue } = ClientFormatterFacade.formatValue(Number(rawValue), format, separators);
|
|
18
|
+
return { kind: "value", text: formattedValue };
|
|
19
|
+
}
|
|
20
|
+
return { kind: "value", text: String(rawValue) };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Maps a label/attribute display value to a {@link ResolvedReference} status:
|
|
24
|
+
* `null` / `undefined` / empty string → empty ("No data"); otherwise the value.
|
|
25
|
+
* Shared by every tooltip resolver so empty-value handling can't drift between
|
|
26
|
+
* the in-chart and external paths. The count-based "multiple" case stays with
|
|
27
|
+
* the caller (only the lookup builder knows the per-row count).
|
|
28
|
+
*
|
|
29
|
+
* @internal
|
|
30
|
+
*/
|
|
31
|
+
export function labelReference(value) {
|
|
32
|
+
return value == null || value === "" ? { kind: "empty" } : { kind: "value", text: String(value) };
|
|
33
|
+
}
|
|
@@ -23,6 +23,20 @@ export interface ITooltipExecutionBundle {
|
|
|
23
23
|
execution: IPreparedExecution;
|
|
24
24
|
meta: ITooltipExecutionMeta;
|
|
25
25
|
}
|
|
26
|
+
/**
|
|
27
|
+
* A tooltip execution plan: one batched execution for all external references,
|
|
28
|
+
* plus per-reference bundles used as an isolation fallback. When the batch
|
|
29
|
+
* rejects (e.g. a single invalid reference 400s the whole AFM), the consumer
|
|
30
|
+
* re-runs the per-reference bundles so one bad reference can't suppress the
|
|
31
|
+
* rest. `perRef` is a thunk: the bundles are built lazily, only when the batch
|
|
32
|
+
* fails, so consumers that never fan out (e.g. geo) pay nothing for it.
|
|
33
|
+
*
|
|
34
|
+
* @internal
|
|
35
|
+
*/
|
|
36
|
+
export interface ITooltipExecution {
|
|
37
|
+
batch: ITooltipExecutionBundle;
|
|
38
|
+
perRef: () => readonly ITooltipExecutionBundle[];
|
|
39
|
+
}
|
|
26
40
|
/**
|
|
27
41
|
* @internal
|
|
28
42
|
*/
|
|
@@ -37,7 +51,9 @@ export interface IBuildTooltipExecutionOptions {
|
|
|
37
51
|
/**
|
|
38
52
|
* Returns `null` when the content has no references or all references are
|
|
39
53
|
* already in the chart (resolvable from drill data without a secondary call).
|
|
54
|
+
* Otherwise returns the batched execution plus per-reference bundles for the
|
|
55
|
+
* fan-out fallback (see {@link ITooltipExecution}).
|
|
40
56
|
*
|
|
41
57
|
* @internal
|
|
42
58
|
*/
|
|
43
|
-
export declare function buildTooltipExecution(executionFactory: IExecutionFactory, chartDefinition: IExecutionDefinition, tooltipContent: string, options?: IBuildTooltipExecutionOptions):
|
|
59
|
+
export declare function buildTooltipExecution(executionFactory: IExecutionFactory, chartDefinition: IExecutionDefinition, tooltipContent: string, options?: IBuildTooltipExecutionOptions): ITooltipExecution | null;
|
|
@@ -67,26 +67,27 @@ function getFilterDependencyMeasures(filters, chartMeasures) {
|
|
|
67
67
|
return chartMeasures.filter((m) => neededLocalIds.has(measureLocalId(m)));
|
|
68
68
|
}
|
|
69
69
|
/**
|
|
70
|
-
* Build tooltip-only measures for
|
|
71
|
-
* Labels get a max+count pair (mirrors the RichText
|
|
72
|
-
* lookup can render "(Multiple items)" when a label
|
|
70
|
+
* Build tooltip-only measures for the given references (already filtered to
|
|
71
|
+
* those not in the chart). Labels get a max+count pair (mirrors the RichText
|
|
72
|
+
* widget pattern) so the lookup can render "(Multiple items)" when a label
|
|
73
|
+
* resolves to >1 value per row.
|
|
73
74
|
*
|
|
74
75
|
* LocalId prefixes `tt_m_`, `tt_lv_`, `tt_lc_` are reserved — collision with
|
|
75
76
|
* chart-side measure localIds would break filter-dependency reuse.
|
|
76
77
|
*/
|
|
77
|
-
function buildTooltipItems(refs
|
|
78
|
+
function buildTooltipItems(refs) {
|
|
78
79
|
const measures = [];
|
|
79
80
|
const labelCountMap = {};
|
|
80
81
|
const labelIdMap = {};
|
|
81
82
|
const measureIdMap = {};
|
|
82
83
|
let idx = 0;
|
|
83
84
|
for (const ref of refs) {
|
|
84
|
-
if (ref.type === "metric"
|
|
85
|
+
if (ref.type === "metric") {
|
|
85
86
|
const localId = `tt_m_${idx++}`;
|
|
86
87
|
measures.push(newMeasure(idRef(ref.id, "measure"), (m) => m.localId(localId)));
|
|
87
88
|
measureIdMap[localId] = ref.id;
|
|
88
89
|
}
|
|
89
|
-
else
|
|
90
|
+
else {
|
|
90
91
|
const valueLocalId = `tt_lv_${idx}`;
|
|
91
92
|
const countLocalId = `tt_lc_${idx}`;
|
|
92
93
|
idx++;
|
|
@@ -119,19 +120,12 @@ function getSlicingAttributes(definition, slicingAttributeLocalIds) {
|
|
|
119
120
|
return out;
|
|
120
121
|
}
|
|
121
122
|
/**
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
* @internal
|
|
123
|
+
* Builds a single execution bundle for the given external references (slicing
|
|
124
|
+
* attributes + tooltip measures + filter-dependency measures). Returns `null`
|
|
125
|
+
* when there are no measures to fetch.
|
|
126
126
|
*/
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
if (refs.length === 0) {
|
|
130
|
-
return null;
|
|
131
|
-
}
|
|
132
|
-
const chartMetricIds = getChartMetricIds(chartDefinition);
|
|
133
|
-
const chartLabelIds = getChartLabelIds(chartDefinition);
|
|
134
|
-
const { measures, labelCountMap, labelIdMap, measureIdMap } = buildTooltipItems(refs, chartMetricIds, chartLabelIds);
|
|
127
|
+
function buildBundle(executionFactory, chartDefinition, externalRefs, options) {
|
|
128
|
+
const { measures, labelCountMap, labelIdMap, measureIdMap } = buildTooltipItems(externalRefs);
|
|
135
129
|
if (measures.length === 0) {
|
|
136
130
|
return null;
|
|
137
131
|
}
|
|
@@ -150,3 +144,31 @@ export function buildTooltipExecution(executionFactory, chartDefinition, tooltip
|
|
|
150
144
|
meta: { labelCountMap, measureIdMap, labelIdMap },
|
|
151
145
|
};
|
|
152
146
|
}
|
|
147
|
+
/**
|
|
148
|
+
* Returns `null` when the content has no references or all references are
|
|
149
|
+
* already in the chart (resolvable from drill data without a secondary call).
|
|
150
|
+
* Otherwise returns the batched execution plus per-reference bundles for the
|
|
151
|
+
* fan-out fallback (see {@link ITooltipExecution}).
|
|
152
|
+
*
|
|
153
|
+
* @internal
|
|
154
|
+
*/
|
|
155
|
+
export function buildTooltipExecution(executionFactory, chartDefinition, tooltipContent, options) {
|
|
156
|
+
const refs = parseReferences(tooltipContent);
|
|
157
|
+
if (refs.length === 0) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
const chartMetricIds = getChartMetricIds(chartDefinition);
|
|
161
|
+
const chartLabelIds = getChartLabelIds(chartDefinition);
|
|
162
|
+
// References not already resolvable from the chart's own drill data.
|
|
163
|
+
const externalRefs = refs.filter((ref) => (ref.type === "metric" && !chartMetricIds.has(ref.id)) ||
|
|
164
|
+
(ref.type === "label" && !chartLabelIds.has(ref.id)));
|
|
165
|
+
const batch = buildBundle(executionFactory, chartDefinition, externalRefs, options);
|
|
166
|
+
if (!batch) {
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
// Lazy: built only on batch failure (the Highcharts fan-out); geo never calls it.
|
|
170
|
+
const perRef = () => externalRefs
|
|
171
|
+
.map((ref) => buildBundle(executionFactory, chartDefinition, [ref], options))
|
|
172
|
+
.filter((bundle) => bundle !== null);
|
|
173
|
+
return { batch, perRef };
|
|
174
|
+
}
|
|
@@ -2,20 +2,12 @@ import { type IDataView } from "@gooddata/sdk-backend-spi";
|
|
|
2
2
|
import { type ISeparators } from "@gooddata/sdk-model";
|
|
3
3
|
import { type ITooltipExecutionMeta } from "./tooltipExecution.js";
|
|
4
4
|
import { type IResolvedReferenceValues } from "./types.js";
|
|
5
|
-
/**
|
|
6
|
-
* Localized placeholders for unresolved reference values. Mirrors the RichText
|
|
7
|
-
* widget's `richText.no_data` / `richText.multiple_data` messages.
|
|
8
|
-
*
|
|
9
|
-
* @internal
|
|
10
|
-
*/
|
|
11
|
-
export interface ITooltipLookupLocalizedStrings {
|
|
12
|
-
noData: string;
|
|
13
|
-
multipleItems: string;
|
|
14
|
-
}
|
|
15
5
|
/**
|
|
16
6
|
* Build a per-data-point lookup keyed by `${displayFormId}:${uri}` segments
|
|
17
7
|
* (joined by `|`, sorted). Iteration is orientation-agnostic via slices/series.
|
|
8
|
+
* Each reference is tagged with a {@link ResolvedReference} status; localized
|
|
9
|
+
* placeholder strings are applied later, at the render site.
|
|
18
10
|
*
|
|
19
11
|
* @internal
|
|
20
12
|
*/
|
|
21
|
-
export declare function buildLookupTable(dataView: IDataView, meta: ITooltipExecutionMeta, separators?: ISeparators
|
|
13
|
+
export declare function buildLookupTable(dataView: IDataView, meta: ITooltipExecutionMeta, separators?: ISeparators): Map<string, IResolvedReferenceValues>;
|
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
// (C) 2026 GoodData Corporation
|
|
2
|
-
import { ClientFormatterFacade } from "@gooddata/number-formatter";
|
|
3
2
|
import { isResultAttributeHeader } from "@gooddata/sdk-model";
|
|
4
3
|
import { DataViewFacade } from "@gooddata/sdk-ui";
|
|
4
|
+
import { labelReference, measureReference } from "./referenceStatus.js";
|
|
5
5
|
import { buildKeySegment, joinKeySegments } from "./tooltipKey.js";
|
|
6
|
-
|
|
7
|
-
noData: "(No data)",
|
|
8
|
-
multipleItems: "(Multiple items)",
|
|
9
|
-
};
|
|
6
|
+
import { labelKey, metricKey } from "./types.js";
|
|
10
7
|
/**
|
|
11
8
|
* Build a per-data-point lookup keyed by `${displayFormId}:${uri}` segments
|
|
12
9
|
* (joined by `|`, sorted). Iteration is orientation-agnostic via slices/series.
|
|
10
|
+
* Each reference is tagged with a {@link ResolvedReference} status; localized
|
|
11
|
+
* placeholder strings are applied later, at the render site.
|
|
13
12
|
*
|
|
14
13
|
* @internal
|
|
15
14
|
*/
|
|
16
|
-
export function buildLookupTable(dataView, meta, separators
|
|
15
|
+
export function buildLookupTable(dataView, meta, separators) {
|
|
17
16
|
const lookup = new Map();
|
|
18
17
|
const facade = DataViewFacade.for(dataView);
|
|
19
18
|
const slices = facade.data().slices().toArray();
|
|
@@ -51,30 +50,14 @@ export function buildLookupTable(dataView, meta, separators, localizedStrings =
|
|
|
51
50
|
const countValue = countSeries
|
|
52
51
|
? Number(countSeries.dataPoints()[sliceIdx]?.rawValue ?? 0)
|
|
53
52
|
: 1;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
else if (rawValue == null || rawValue === "") {
|
|
58
|
-
values[`label/${labelId}`] = localizedStrings.noData;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
values[`label/${labelId}`] = String(rawValue);
|
|
62
|
-
}
|
|
53
|
+
// count > 1 → "(Multiple items)"; else empty/value via the shared helper.
|
|
54
|
+
values[labelKey(labelId)] = countValue > 1 ? { kind: "multiple" } : labelReference(rawValue);
|
|
63
55
|
continue;
|
|
64
56
|
}
|
|
65
57
|
const metricId = meta.measureIdMap[localId];
|
|
66
58
|
if (metricId) {
|
|
67
59
|
const format = measureDesc.measureHeaderItem.format;
|
|
68
|
-
|
|
69
|
-
values[`metric/${metricId}`] = localizedStrings.noData;
|
|
70
|
-
}
|
|
71
|
-
else if (format) {
|
|
72
|
-
const { formattedValue } = ClientFormatterFacade.formatValue(Number(rawValue), format, separators);
|
|
73
|
-
values[`metric/${metricId}`] = formattedValue;
|
|
74
|
-
}
|
|
75
|
-
else {
|
|
76
|
-
values[`metric/${metricId}`] = String(rawValue);
|
|
77
|
-
}
|
|
60
|
+
values[metricKey(metricId)] = measureReference(rawValue, format, separators);
|
|
78
61
|
}
|
|
79
62
|
}
|
|
80
63
|
lookup.set(pointKey, values);
|
|
@@ -59,10 +59,58 @@ export interface ICustomTooltipConfig {
|
|
|
59
59
|
placement?: CustomTooltipPlacement;
|
|
60
60
|
}
|
|
61
61
|
/**
|
|
62
|
-
*
|
|
62
|
+
* Resolution outcome for a single `{metric/id}` / `{label/id}` reference at a
|
|
63
|
+
* data point. A discriminated union so the renderer maps each state to its own
|
|
64
|
+
* localized message instead of collapsing every "missing" case into one
|
|
65
|
+
* fallback: `empty` → "(No data)", `multiple` → "(Multiple items)", `error` →
|
|
66
|
+
* "(Data could not be retrieved)". `error` is emitted only when a value was
|
|
67
|
+
* genuinely unretrievable (e.g. a reference whose fetch failed); it is never a
|
|
68
|
+
* default for an unclassified value.
|
|
69
|
+
*
|
|
70
|
+
* @internal
|
|
71
|
+
*/
|
|
72
|
+
export type ResolvedReference = {
|
|
73
|
+
readonly kind: "value";
|
|
74
|
+
readonly text: string;
|
|
75
|
+
} | {
|
|
76
|
+
readonly kind: "empty";
|
|
77
|
+
} | {
|
|
78
|
+
readonly kind: "multiple";
|
|
79
|
+
} | {
|
|
80
|
+
readonly kind: "error";
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Lookup of resolved reference statuses keyed by `metric/id` or `label/id`.
|
|
63
84
|
*
|
|
64
85
|
* @internal
|
|
65
86
|
*/
|
|
66
87
|
export interface IResolvedReferenceValues {
|
|
67
|
-
[referenceKey: string]:
|
|
88
|
+
[referenceKey: string]: ResolvedReference | undefined;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Builds the `metric/<id>` lookup key for a metric reference. A reference key
|
|
92
|
+
* has exactly two shapes ({@link metricKey}, {@link labelKey}); keeping the
|
|
93
|
+
* convention here is the single source for every write site. The read side
|
|
94
|
+
* parses references via `REFERENCE_REGEX_MATCH` in `resolveReferences`.
|
|
95
|
+
*
|
|
96
|
+
* @internal
|
|
97
|
+
*/
|
|
98
|
+
export declare const metricKey: (id: string) => string;
|
|
99
|
+
/**
|
|
100
|
+
* Builds the `label/<id>` lookup key for a label reference. See {@link metricKey}.
|
|
101
|
+
*
|
|
102
|
+
* @internal
|
|
103
|
+
*/
|
|
104
|
+
export declare const labelKey: (id: string) => string;
|
|
105
|
+
/**
|
|
106
|
+
* Localized placeholder strings for the non-value reference states. Built once
|
|
107
|
+
* at the render site (where `intl` is available) and threaded into
|
|
108
|
+
* `resolveReferences`, so reference resolution stays free of i18n concerns.
|
|
109
|
+
*
|
|
110
|
+
* @internal
|
|
111
|
+
*/
|
|
112
|
+
export interface ITooltipLocalizedStrings {
|
|
113
|
+
readonly noData: string;
|
|
114
|
+
readonly multipleItems: string;
|
|
115
|
+
readonly noFetch: string;
|
|
68
116
|
}
|
|
@@ -1,2 +1,16 @@
|
|
|
1
1
|
// (C) 2026 GoodData Corporation
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Builds the `metric/<id>` lookup key for a metric reference. A reference key
|
|
4
|
+
* has exactly two shapes ({@link metricKey}, {@link labelKey}); keeping the
|
|
5
|
+
* convention here is the single source for every write site. The read side
|
|
6
|
+
* parses references via `REFERENCE_REGEX_MATCH` in `resolveReferences`.
|
|
7
|
+
*
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export const metricKey = (id) => `metric/${id}`;
|
|
11
|
+
/**
|
|
12
|
+
* Builds the `label/<id>` lookup key for a label reference. See {@link metricKey}.
|
|
13
|
+
*
|
|
14
|
+
* @internal
|
|
15
|
+
*/
|
|
16
|
+
export const labelKey = (id) => `label/${id}`;
|
|
@@ -1,8 +1,27 @@
|
|
|
1
1
|
import { type IPreparedExecution } from "@gooddata/sdk-backend-spi";
|
|
2
2
|
import { type ISeparators } from "@gooddata/sdk-model";
|
|
3
|
-
import { type
|
|
4
|
-
import { type ITooltipLookupLocalizedStrings } from "./tooltipLookup.js";
|
|
3
|
+
import { type ITooltipExecution, type ITooltipExecutionMeta } from "./tooltipExecution.js";
|
|
5
4
|
import { type IResolvedReferenceValues } from "./types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Built lookup plus references that could not be retrieved at all (their fetch
|
|
7
|
+
* rejected even in the per-reference fallback). Errored references render as
|
|
8
|
+
* "(Data could not be retrieved)" at every point.
|
|
9
|
+
*
|
|
10
|
+
* @internal
|
|
11
|
+
*/
|
|
12
|
+
export interface ITooltipLookupResult {
|
|
13
|
+
lookup: Map<string, IResolvedReferenceValues>;
|
|
14
|
+
erroredRefs: ReadonlySet<string>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Single-execution variant for chart families that have one tooltip execution
|
|
18
|
+
* per chart (e.g. Highcharts). Returns `undefined` while no execution is
|
|
19
|
+
* provided or before the first result lands; consumers handle that as "no
|
|
20
|
+
* external values".
|
|
21
|
+
*
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export declare function useTooltipLookup(execution: ITooltipExecution | undefined, separators?: ISeparators): ITooltipLookupResult | undefined;
|
|
6
25
|
/**
|
|
7
26
|
* One prepared tooltip execution paired with a caller-owned key and the
|
|
8
27
|
* context that travels with the built lookup.
|
|
@@ -25,19 +44,11 @@ export interface ITooltipLookupExecutionResult<TContext> {
|
|
|
25
44
|
context: TContext;
|
|
26
45
|
}
|
|
27
46
|
/**
|
|
28
|
-
*
|
|
29
|
-
* chart (e.g. Highcharts). Returns `undefined` while no bundle is provided or
|
|
30
|
-
* before the first result lands; consumers handle that as "no external values".
|
|
31
|
-
*
|
|
32
|
-
* @internal
|
|
33
|
-
*/
|
|
34
|
-
export declare function useTooltipLookup(bundle: ITooltipExecutionBundle | undefined, separators?: ISeparators, localizedStrings?: ITooltipLookupLocalizedStrings): Map<string, IResolvedReferenceValues> | undefined;
|
|
35
|
-
/**
|
|
36
|
-
* Multi-bundle variant for chart families that key tooltip executions per
|
|
47
|
+
* Multi-execution variant for chart families that key tooltip executions per
|
|
37
48
|
* sub-target (e.g. geo per-layer). `context` is required so the produced
|
|
38
49
|
* lookup carries whatever the caller needs to interpret the result —
|
|
39
50
|
* downstream code does not have to defensively check for missing context.
|
|
40
51
|
*
|
|
41
52
|
* @internal
|
|
42
53
|
*/
|
|
43
|
-
export declare function useTooltipLookupExecutions<TContext>(entries: readonly ITooltipLookupExecutionEntry<TContext>[], separators?: ISeparators
|
|
54
|
+
export declare function useTooltipLookupExecutions<TContext>(entries: readonly ITooltipLookupExecutionEntry<TContext>[], separators?: ISeparators): Map<string, ITooltipLookupExecutionResult<TContext>>;
|
|
@@ -2,47 +2,97 @@
|
|
|
2
2
|
import { useMemo } from "react";
|
|
3
3
|
import { useCancelablePromise } from "@gooddata/sdk-ui";
|
|
4
4
|
import { buildLookupTable } from "./tooltipLookup.js";
|
|
5
|
-
|
|
5
|
+
import { labelKey, metricKey } from "./types.js";
|
|
6
6
|
async function executeOne(execution) {
|
|
7
7
|
const result = await execution.execute();
|
|
8
8
|
return result.readAll();
|
|
9
9
|
}
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* Reference keys (`metric/id`, `label/id`) a bundle's meta covers. Used to mark
|
|
12
|
+
* a failed per-reference bundle's references as errored.
|
|
13
|
+
*/
|
|
14
|
+
function refKeysOfMeta(meta) {
|
|
15
|
+
return [
|
|
16
|
+
...Object.values(meta.measureIdMap).map(metricKey),
|
|
17
|
+
...Object.values(meta.labelIdMap).map(labelKey),
|
|
18
|
+
];
|
|
12
19
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
20
|
+
/**
|
|
21
|
+
* Execute the batch; on failure, fan out to per-reference bundles so a single
|
|
22
|
+
* bad reference (e.g. one that 400s the batched AFM) only errors itself while
|
|
23
|
+
* the rest still resolve. No reliance on parsing the backend error — failure is
|
|
24
|
+
* isolated structurally by which per-reference execution rejects.
|
|
25
|
+
*/
|
|
26
|
+
async function runWithFallback(execution) {
|
|
27
|
+
try {
|
|
28
|
+
const dataView = await executeOne(execution.batch.execution);
|
|
29
|
+
return { inputs: [{ dataView, meta: execution.batch.meta }], erroredRefs: new Set() };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Build the per-reference bundles now (lazy) and isolate each.
|
|
33
|
+
const perRef = execution.perRef();
|
|
34
|
+
const settled = await Promise.allSettled(perRef.map((bundle) => executeOne(bundle.execution)));
|
|
35
|
+
const inputs = [];
|
|
36
|
+
const erroredRefs = new Set();
|
|
37
|
+
settled.forEach((result, index) => {
|
|
38
|
+
const bundle = perRef[index];
|
|
39
|
+
if (result.status === "fulfilled") {
|
|
40
|
+
inputs.push({ dataView: result.value, meta: bundle.meta });
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
refKeysOfMeta(bundle.meta).forEach((key) => erroredRefs.add(key));
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
return { inputs, erroredRefs };
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Merge per-execution lookups into one map (by point key, shallow-merging the
|
|
51
|
+
* per-point reference statuses) and pair it with the errored references.
|
|
52
|
+
*/
|
|
53
|
+
function buildResult(outcome, separators) {
|
|
54
|
+
const lookup = new Map();
|
|
55
|
+
for (const { dataView, meta } of outcome.inputs) {
|
|
56
|
+
for (const [pointKey, values] of buildLookupTable(dataView, meta, separators)) {
|
|
57
|
+
const existing = lookup.get(pointKey);
|
|
58
|
+
lookup.set(pointKey, existing ? { ...existing, ...values } : values);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return { lookup, erroredRefs: outcome.erroredRefs };
|
|
17
62
|
}
|
|
18
63
|
/**
|
|
19
|
-
* Single-
|
|
20
|
-
* chart (e.g. Highcharts). Returns `undefined` while no
|
|
21
|
-
* before the first result lands; consumers handle that as "no
|
|
64
|
+
* Single-execution variant for chart families that have one tooltip execution
|
|
65
|
+
* per chart (e.g. Highcharts). Returns `undefined` while no execution is
|
|
66
|
+
* provided or before the first result lands; consumers handle that as "no
|
|
67
|
+
* external values".
|
|
22
68
|
*
|
|
23
69
|
* @internal
|
|
24
70
|
*/
|
|
25
|
-
export function useTooltipLookup(
|
|
26
|
-
const fingerprint =
|
|
71
|
+
export function useTooltipLookup(execution, separators) {
|
|
72
|
+
const fingerprint = execution?.batch.execution.fingerprint();
|
|
27
73
|
const { result } = useCancelablePromise({
|
|
28
|
-
promise:
|
|
74
|
+
promise: execution ? () => runWithFallback(execution) : undefined,
|
|
29
75
|
}, [fingerprint]);
|
|
30
|
-
return useMemo(() =>
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
76
|
+
return useMemo(() => (result ? buildResult(result, separators) : undefined), [result, separators]);
|
|
77
|
+
}
|
|
78
|
+
const EMPTY_LOOKUPS = new Map();
|
|
79
|
+
function getEntriesFingerprint(entries) {
|
|
80
|
+
return entries.map((entry) => `${entry.key}::${entry.execution.fingerprint()}`).join("||");
|
|
81
|
+
}
|
|
82
|
+
async function executeAll(entries) {
|
|
83
|
+
const settled = await Promise.allSettled(entries.map(async (entry) => ({ ...entry, dataView: await executeOne(entry.execution) })));
|
|
84
|
+
// Failed entries drop out silently; callers fall back when a lookup is missing.
|
|
85
|
+
return settled.flatMap((result) => (result.status === "fulfilled" ? [result.value] : []));
|
|
36
86
|
}
|
|
37
87
|
/**
|
|
38
|
-
* Multi-
|
|
88
|
+
* Multi-execution variant for chart families that key tooltip executions per
|
|
39
89
|
* sub-target (e.g. geo per-layer). `context` is required so the produced
|
|
40
90
|
* lookup carries whatever the caller needs to interpret the result —
|
|
41
91
|
* downstream code does not have to defensively check for missing context.
|
|
42
92
|
*
|
|
43
93
|
* @internal
|
|
44
94
|
*/
|
|
45
|
-
export function useTooltipLookupExecutions(entries, separators
|
|
95
|
+
export function useTooltipLookupExecutions(entries, separators) {
|
|
46
96
|
const fingerprint = getEntriesFingerprint(entries);
|
|
47
97
|
const { result } = useCancelablePromise({
|
|
48
98
|
promise: entries.length > 0 ? () => executeAll(entries) : undefined,
|
|
@@ -54,10 +104,10 @@ export function useTooltipLookupExecutions(entries, separators, localizedStrings
|
|
|
54
104
|
const lookups = new Map();
|
|
55
105
|
for (const entry of result) {
|
|
56
106
|
lookups.set(entry.key, {
|
|
57
|
-
lookup: buildLookupTable(entry.dataView, entry.meta, separators
|
|
107
|
+
lookup: buildLookupTable(entry.dataView, entry.meta, separators),
|
|
58
108
|
context: entry.context,
|
|
59
109
|
});
|
|
60
110
|
}
|
|
61
111
|
return lookups;
|
|
62
|
-
}, [result, separators
|
|
112
|
+
}, [result, separators]);
|
|
63
113
|
}
|
package/esm/index.d.ts
CHANGED
|
@@ -28,12 +28,14 @@ export { getHeadlineResponsiveClassName } from "./utils/headlineResponsiveClassN
|
|
|
28
28
|
export { getLegendDetails, type ILegendDetails, type ILegendDetailOptions, } from "./legend/PopUpLegend/helpers.js";
|
|
29
29
|
export { PATTERN_FILLS, getPatternFillByIndex, getPatternFillByName, getPatternFill, type IPatternFill, type PatternFillName, type IChartFillConfig, } from "./coloring/patternFills.js";
|
|
30
30
|
export { PatternFill, type IPatternFillProps } from "./coloring/PatternFill.js";
|
|
31
|
-
export { type ICustomTooltipConfig, type CustomTooltipPlacement, type IResolvedReferenceValues, } from "./customTooltip/types.js";
|
|
31
|
+
export { type ICustomTooltipConfig, type CustomTooltipPlacement, type IResolvedReferenceValues, type ResolvedReference, type ITooltipLocalizedStrings, metricKey, labelKey, } from "./customTooltip/types.js";
|
|
32
32
|
export { markdownToHtml } from "./customTooltip/markdownToHtml.js";
|
|
33
33
|
export { resolveReferences } from "./customTooltip/referenceResolver.js";
|
|
34
|
+
export { measureReference, labelReference } from "./customTooltip/referenceStatus.js";
|
|
35
|
+
export { buildTooltipLocalizedStrings } from "./customTooltip/localizedStrings.js";
|
|
34
36
|
export { resolveMeasureLdmIdentifier } from "./customTooltip/measureLdmIdentifier.js";
|
|
35
|
-
export { buildTooltipExecution, type IBuildTooltipExecutionOptions, type ITooltipExecutionBundle, type ITooltipExecutionMeta, } from "./customTooltip/tooltipExecution.js";
|
|
36
|
-
export { buildLookupTable
|
|
37
|
+
export { buildTooltipExecution, type IBuildTooltipExecutionOptions, type ITooltipExecution, type ITooltipExecutionBundle, type ITooltipExecutionMeta, } from "./customTooltip/tooltipExecution.js";
|
|
38
|
+
export { buildLookupTable } from "./customTooltip/tooltipLookup.js";
|
|
37
39
|
export { buildKeySegment, joinKeySegments } from "./customTooltip/tooltipKey.js";
|
|
38
40
|
export { composeCustomTooltipSectionHtml } from "./customTooltip/composeSectionHtml.js";
|
|
39
|
-
export { useTooltipLookup, useTooltipLookupExecutions, type ITooltipLookupExecutionEntry, type ITooltipLookupExecutionResult, } from "./customTooltip/useTooltipLookupExecutions.js";
|
|
41
|
+
export { useTooltipLookup, useTooltipLookupExecutions, type ITooltipLookupResult, type ITooltipLookupExecutionEntry, type ITooltipLookupExecutionResult, } from "./customTooltip/useTooltipLookupExecutions.js";
|
package/esm/index.js
CHANGED
|
@@ -29,8 +29,11 @@ export { getHeadlineResponsiveClassName } from "./utils/headlineResponsiveClassN
|
|
|
29
29
|
export { getLegendDetails, } from "./legend/PopUpLegend/helpers.js";
|
|
30
30
|
export { PATTERN_FILLS, getPatternFillByIndex, getPatternFillByName, getPatternFill, } from "./coloring/patternFills.js";
|
|
31
31
|
export { PatternFill } from "./coloring/PatternFill.js";
|
|
32
|
+
export { metricKey, labelKey, } from "./customTooltip/types.js";
|
|
32
33
|
export { markdownToHtml } from "./customTooltip/markdownToHtml.js";
|
|
33
34
|
export { resolveReferences } from "./customTooltip/referenceResolver.js";
|
|
35
|
+
export { measureReference, labelReference } from "./customTooltip/referenceStatus.js";
|
|
36
|
+
export { buildTooltipLocalizedStrings } from "./customTooltip/localizedStrings.js";
|
|
34
37
|
export { resolveMeasureLdmIdentifier } from "./customTooltip/measureLdmIdentifier.js";
|
|
35
38
|
export { buildTooltipExecution, } from "./customTooltip/tooltipExecution.js";
|
|
36
39
|
export { buildLookupTable } from "./customTooltip/tooltipLookup.js";
|
|
@@ -21,6 +21,7 @@ import { IExecutionFactory } from '@gooddata/sdk-backend-spi';
|
|
|
21
21
|
import { IHeaderPredicate } from '@gooddata/sdk-ui';
|
|
22
22
|
import { IMappingHeader } from '@gooddata/sdk-ui';
|
|
23
23
|
import { IMeasure } from '@gooddata/sdk-model';
|
|
24
|
+
import { IntlShape } from 'react-intl';
|
|
24
25
|
import { IPreparedExecution } from '@gooddata/sdk-backend-spi';
|
|
25
26
|
import { IRgbColorValue } from '@gooddata/sdk-model';
|
|
26
27
|
import { ISeparators } from '@gooddata/sdk-model';
|
|
@@ -58,18 +59,32 @@ export declare function buildKeySegment(displayFormId: string, uri: string): str
|
|
|
58
59
|
/**
|
|
59
60
|
* Build a per-data-point lookup keyed by `${displayFormId}:${uri}` segments
|
|
60
61
|
* (joined by `|`, sorted). Iteration is orientation-agnostic via slices/series.
|
|
62
|
+
* Each reference is tagged with a {@link ResolvedReference} status; localized
|
|
63
|
+
* placeholder strings are applied later, at the render site.
|
|
61
64
|
*
|
|
62
65
|
* @internal
|
|
63
66
|
*/
|
|
64
|
-
export declare function buildLookupTable(dataView: IDataView, meta: ITooltipExecutionMeta, separators?: ISeparators
|
|
67
|
+
export declare function buildLookupTable(dataView: IDataView, meta: ITooltipExecutionMeta, separators?: ISeparators): Map<string, IResolvedReferenceValues>;
|
|
65
68
|
|
|
66
69
|
/**
|
|
67
70
|
* Returns `null` when the content has no references or all references are
|
|
68
71
|
* already in the chart (resolvable from drill data without a secondary call).
|
|
72
|
+
* Otherwise returns the batched execution plus per-reference bundles for the
|
|
73
|
+
* fan-out fallback (see {@link ITooltipExecution}).
|
|
69
74
|
*
|
|
70
75
|
* @internal
|
|
71
76
|
*/
|
|
72
|
-
export declare function buildTooltipExecution(executionFactory: IExecutionFactory, chartDefinition: IExecutionDefinition, tooltipContent: string, options?: IBuildTooltipExecutionOptions):
|
|
77
|
+
export declare function buildTooltipExecution(executionFactory: IExecutionFactory, chartDefinition: IExecutionDefinition, tooltipContent: string, options?: IBuildTooltipExecutionOptions): ITooltipExecution | null;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Builds the localized placeholder strings for the non-value reference states,
|
|
81
|
+
* shared by every tooltip consumer (Highcharts, geo) so the wording and the
|
|
82
|
+
* message ids live in one place. `intl` is optional — the Highcharts tooltip
|
|
83
|
+
* formatter receives it optionally — and falls back to English.
|
|
84
|
+
*
|
|
85
|
+
* @internal
|
|
86
|
+
*/
|
|
87
|
+
export declare function buildTooltipLocalizedStrings(intl?: IntlShape): ITooltipLocalizedStrings;
|
|
73
88
|
|
|
74
89
|
/**
|
|
75
90
|
* @internal
|
|
@@ -129,7 +144,7 @@ export declare const ColorUtils: {
|
|
|
129
144
|
*
|
|
130
145
|
* @internal
|
|
131
146
|
*/
|
|
132
|
-
export declare function composeCustomTooltipSectionHtml(content: string, inChartValues: IResolvedReferenceValues, externalValues: IResolvedReferenceValues,
|
|
147
|
+
export declare function composeCustomTooltipSectionHtml(content: string, inChartValues: IResolvedReferenceValues, externalValues: IResolvedReferenceValues, localizedStrings: ITooltipLocalizedStrings): string;
|
|
133
148
|
|
|
134
149
|
/**
|
|
135
150
|
* Placement of the custom tooltip section relative to the default tooltip content.
|
|
@@ -679,12 +694,12 @@ export declare interface IRange {
|
|
|
679
694
|
}
|
|
680
695
|
|
|
681
696
|
/**
|
|
682
|
-
* Lookup of resolved reference
|
|
697
|
+
* Lookup of resolved reference statuses keyed by `metric/id` or `label/id`.
|
|
683
698
|
*
|
|
684
699
|
* @internal
|
|
685
700
|
*/
|
|
686
701
|
export declare interface IResolvedReferenceValues {
|
|
687
|
-
[referenceKey: string]:
|
|
702
|
+
[referenceKey: string]: ResolvedReference | undefined;
|
|
688
703
|
}
|
|
689
704
|
|
|
690
705
|
/**
|
|
@@ -784,6 +799,21 @@ export declare function isValidMappedColor(colorItem: IColor | null | undefined,
|
|
|
784
799
|
*/
|
|
785
800
|
export declare type ItemBorderRadiusPredicate = (item: any) => boolean;
|
|
786
801
|
|
|
802
|
+
/**
|
|
803
|
+
* A tooltip execution plan: one batched execution for all external references,
|
|
804
|
+
* plus per-reference bundles used as an isolation fallback. When the batch
|
|
805
|
+
* rejects (e.g. a single invalid reference 400s the whole AFM), the consumer
|
|
806
|
+
* re-runs the per-reference bundles so one bad reference can't suppress the
|
|
807
|
+
* rest. `perRef` is a thunk: the bundles are built lazily, only when the batch
|
|
808
|
+
* fails, so consumers that never fan out (e.g. geo) pay nothing for it.
|
|
809
|
+
*
|
|
810
|
+
* @internal
|
|
811
|
+
*/
|
|
812
|
+
export declare interface ITooltipExecution {
|
|
813
|
+
batch: ITooltipExecutionBundle;
|
|
814
|
+
perRef: () => readonly ITooltipExecutionBundle[];
|
|
815
|
+
}
|
|
816
|
+
|
|
787
817
|
/**
|
|
788
818
|
* Prepared tooltip execution paired with the meta needed to interpret its result.
|
|
789
819
|
* Carry them together — meta from one call mis-interprets results from another.
|
|
@@ -809,6 +839,19 @@ export declare interface ITooltipExecutionMeta {
|
|
|
809
839
|
labelIdMap: Record<string, string>;
|
|
810
840
|
}
|
|
811
841
|
|
|
842
|
+
/**
|
|
843
|
+
* Localized placeholder strings for the non-value reference states. Built once
|
|
844
|
+
* at the render site (where `intl` is available) and threaded into
|
|
845
|
+
* `resolveReferences`, so reference resolution stays free of i18n concerns.
|
|
846
|
+
*
|
|
847
|
+
* @internal
|
|
848
|
+
*/
|
|
849
|
+
export declare interface ITooltipLocalizedStrings {
|
|
850
|
+
readonly noData: string;
|
|
851
|
+
readonly multipleItems: string;
|
|
852
|
+
readonly noFetch: string;
|
|
853
|
+
}
|
|
854
|
+
|
|
812
855
|
/**
|
|
813
856
|
* One prepared tooltip execution paired with a caller-owned key and the
|
|
814
857
|
* context that travels with the built lookup.
|
|
@@ -833,14 +876,15 @@ export declare interface ITooltipLookupExecutionResult<TContext> {
|
|
|
833
876
|
}
|
|
834
877
|
|
|
835
878
|
/**
|
|
836
|
-
*
|
|
837
|
-
*
|
|
879
|
+
* Built lookup plus references that could not be retrieved at all (their fetch
|
|
880
|
+
* rejected even in the per-reference fallback). Errored references render as
|
|
881
|
+
* "(Data could not be retrieved)" at every point.
|
|
838
882
|
*
|
|
839
883
|
* @internal
|
|
840
884
|
*/
|
|
841
|
-
export declare interface
|
|
842
|
-
|
|
843
|
-
|
|
885
|
+
export declare interface ITooltipLookupResult {
|
|
886
|
+
lookup: Map<string, IResolvedReferenceValues>;
|
|
887
|
+
erroredRefs: ReadonlySet<string>;
|
|
844
888
|
}
|
|
845
889
|
|
|
846
890
|
/**
|
|
@@ -848,6 +892,24 @@ export declare interface ITooltipLookupLocalizedStrings {
|
|
|
848
892
|
*/
|
|
849
893
|
export declare function joinKeySegments(parts: readonly string[]): string;
|
|
850
894
|
|
|
895
|
+
/**
|
|
896
|
+
* Builds the `label/<id>` lookup key for a label reference. See {@link metricKey}.
|
|
897
|
+
*
|
|
898
|
+
* @internal
|
|
899
|
+
*/
|
|
900
|
+
export declare const labelKey: (id: string) => string;
|
|
901
|
+
|
|
902
|
+
/**
|
|
903
|
+
* Maps a label/attribute display value to a {@link ResolvedReference} status:
|
|
904
|
+
* `null` / `undefined` / empty string → empty ("No data"); otherwise the value.
|
|
905
|
+
* Shared by every tooltip resolver so empty-value handling can't drift between
|
|
906
|
+
* the in-chart and external paths. The count-based "multiple" case stays with
|
|
907
|
+
* the caller (only the lookup builder knows the per-row count).
|
|
908
|
+
*
|
|
909
|
+
* @internal
|
|
910
|
+
*/
|
|
911
|
+
export declare function labelReference(value: string | number | null | undefined): ResolvedReference;
|
|
912
|
+
|
|
851
913
|
/**
|
|
852
914
|
* @internal
|
|
853
915
|
*/
|
|
@@ -885,6 +947,27 @@ export declare const LegendPosition: {
|
|
|
885
947
|
*/
|
|
886
948
|
export declare function markdownToHtml(markdown: string): string;
|
|
887
949
|
|
|
950
|
+
/**
|
|
951
|
+
* Maps a raw measure value to a {@link ResolvedReference} status: `null`/
|
|
952
|
+
* `undefined` → empty ("No data"); otherwise the formatted (or stringified)
|
|
953
|
+
* value. Shared by every tooltip resolver so the value→status mapping has a
|
|
954
|
+
* single home. Callers whose source can yield non-numeric / non-finite values
|
|
955
|
+
* (e.g. geo feature payloads) normalize those to `null` before calling.
|
|
956
|
+
*
|
|
957
|
+
* @internal
|
|
958
|
+
*/
|
|
959
|
+
export declare function measureReference(rawValue: number | string | null | undefined, format: string | undefined, separators?: ISeparators): ResolvedReference;
|
|
960
|
+
|
|
961
|
+
/**
|
|
962
|
+
* Builds the `metric/<id>` lookup key for a metric reference. A reference key
|
|
963
|
+
* has exactly two shapes ({@link metricKey}, {@link labelKey}); keeping the
|
|
964
|
+
* convention here is the single source for every write site. The read side
|
|
965
|
+
* parses references via `REFERENCE_REGEX_MATCH` in `resolveReferences`.
|
|
966
|
+
*
|
|
967
|
+
* @internal
|
|
968
|
+
*/
|
|
969
|
+
export declare const metricKey: (id: string) => string;
|
|
970
|
+
|
|
888
971
|
/**
|
|
889
972
|
* @internal
|
|
890
973
|
*/
|
|
@@ -947,6 +1030,28 @@ export declare function PopUpLegend({ name, maxRows, enableBorderRadius, series,
|
|
|
947
1030
|
*/
|
|
948
1031
|
export declare type PositionType = "left" | "right" | "top" | "bottom" | "auto";
|
|
949
1032
|
|
|
1033
|
+
/**
|
|
1034
|
+
* Resolution outcome for a single `{metric/id}` / `{label/id}` reference at a
|
|
1035
|
+
* data point. A discriminated union so the renderer maps each state to its own
|
|
1036
|
+
* localized message instead of collapsing every "missing" case into one
|
|
1037
|
+
* fallback: `empty` → "(No data)", `multiple` → "(Multiple items)", `error` →
|
|
1038
|
+
* "(Data could not be retrieved)". `error` is emitted only when a value was
|
|
1039
|
+
* genuinely unretrievable (e.g. a reference whose fetch failed); it is never a
|
|
1040
|
+
* default for an unclassified value.
|
|
1041
|
+
*
|
|
1042
|
+
* @internal
|
|
1043
|
+
*/
|
|
1044
|
+
export declare type ResolvedReference = {
|
|
1045
|
+
readonly kind: "value";
|
|
1046
|
+
readonly text: string;
|
|
1047
|
+
} | {
|
|
1048
|
+
readonly kind: "empty";
|
|
1049
|
+
} | {
|
|
1050
|
+
readonly kind: "multiple";
|
|
1051
|
+
} | {
|
|
1052
|
+
readonly kind: "error";
|
|
1053
|
+
};
|
|
1054
|
+
|
|
950
1055
|
/**
|
|
951
1056
|
* Returns the LDM identifier the measure ultimately resolves to.
|
|
952
1057
|
*
|
|
@@ -968,14 +1073,14 @@ export declare function resolveMeasureLdmIdentifier(measure: IMeasure, allMeasur
|
|
|
968
1073
|
* unintended formatting. `markdownToHtml` understands the backslash escapes.
|
|
969
1074
|
*
|
|
970
1075
|
* @param content - Markdown content with reference placeholders
|
|
971
|
-
* @param values - Lookup of `metric/id` and `label/id` keys to
|
|
1076
|
+
* @param values - Lookup of `metric/id` and `label/id` keys to resolved statuses.
|
|
972
1077
|
* Keys must use a lowercase prefix; LDM identifiers are case-sensitive.
|
|
973
|
-
* @param
|
|
974
|
-
*
|
|
1078
|
+
* @param strings - Localized placeholders for the non-value states (no data,
|
|
1079
|
+
* multiple items, could-not-retrieve).
|
|
975
1080
|
*
|
|
976
1081
|
* @internal
|
|
977
1082
|
*/
|
|
978
|
-
export declare function resolveReferences(content: string, values: IResolvedReferenceValues,
|
|
1083
|
+
export declare function resolveReferences(content: string, values: IResolvedReferenceValues, strings: ITooltipLocalizedStrings): string;
|
|
979
1084
|
|
|
980
1085
|
/**
|
|
981
1086
|
* @internal
|
|
@@ -999,23 +1104,24 @@ export declare const StaticLegend: NamedExoticComponent<IStaticLegendProps>;
|
|
|
999
1104
|
export declare const SupportedLegendPositions: PositionType[];
|
|
1000
1105
|
|
|
1001
1106
|
/**
|
|
1002
|
-
* Single-
|
|
1003
|
-
* chart (e.g. Highcharts). Returns `undefined` while no
|
|
1004
|
-
* before the first result lands; consumers handle that as "no
|
|
1107
|
+
* Single-execution variant for chart families that have one tooltip execution
|
|
1108
|
+
* per chart (e.g. Highcharts). Returns `undefined` while no execution is
|
|
1109
|
+
* provided or before the first result lands; consumers handle that as "no
|
|
1110
|
+
* external values".
|
|
1005
1111
|
*
|
|
1006
1112
|
* @internal
|
|
1007
1113
|
*/
|
|
1008
|
-
export declare function useTooltipLookup(
|
|
1114
|
+
export declare function useTooltipLookup(execution: ITooltipExecution | undefined, separators?: ISeparators): ITooltipLookupResult | undefined;
|
|
1009
1115
|
|
|
1010
1116
|
/**
|
|
1011
|
-
* Multi-
|
|
1117
|
+
* Multi-execution variant for chart families that key tooltip executions per
|
|
1012
1118
|
* sub-target (e.g. geo per-layer). `context` is required so the produced
|
|
1013
1119
|
* lookup carries whatever the caller needs to interpret the result —
|
|
1014
1120
|
* downstream code does not have to defensively check for missing context.
|
|
1015
1121
|
*
|
|
1016
1122
|
* @internal
|
|
1017
1123
|
*/
|
|
1018
|
-
export declare function useTooltipLookupExecutions<TContext>(entries: readonly ITooltipLookupExecutionEntry<TContext>[], separators?: ISeparators
|
|
1124
|
+
export declare function useTooltipLookupExecutions<TContext>(entries: readonly ITooltipLookupExecutionEntry<TContext>[], separators?: ISeparators): Map<string, ITooltipLookupExecutionResult<TContext>>;
|
|
1019
1125
|
|
|
1020
1126
|
/**
|
|
1021
1127
|
* Returns the value if it is non-empty or a fallback text.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-vis-commons",
|
|
3
|
-
"version": "11.41.0-alpha.
|
|
3
|
+
"version": "11.41.0-alpha.1",
|
|
4
4
|
"description": "GoodData.UI SDK - common functionality for different types of visualizations",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"react-intl": "7.1.11",
|
|
37
37
|
"react-measure": "^2.5.2",
|
|
38
38
|
"tslib": "2.8.1",
|
|
39
|
-
"@gooddata/sdk-backend-spi": "11.41.0-alpha.
|
|
40
|
-
"@gooddata/sdk-model": "11.41.0-alpha.
|
|
41
|
-
"@gooddata/sdk-ui": "11.41.0-alpha.
|
|
42
|
-
"@gooddata/sdk-ui-
|
|
43
|
-
"@gooddata/sdk-ui-
|
|
39
|
+
"@gooddata/sdk-backend-spi": "11.41.0-alpha.1",
|
|
40
|
+
"@gooddata/sdk-model": "11.41.0-alpha.1",
|
|
41
|
+
"@gooddata/sdk-ui": "11.41.0-alpha.1",
|
|
42
|
+
"@gooddata/sdk-ui-theme-provider": "11.41.0-alpha.1",
|
|
43
|
+
"@gooddata/sdk-ui-kit": "11.41.0-alpha.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@microsoft/api-documenter": "^7.17.0",
|
|
@@ -81,11 +81,11 @@
|
|
|
81
81
|
"typescript": "5.9.3",
|
|
82
82
|
"vitest": "4.1.8",
|
|
83
83
|
"vitest-dom": "0.1.1",
|
|
84
|
-
"@gooddata/eslint-config": "11.41.0-alpha.
|
|
85
|
-
"@gooddata/oxlint-config": "11.41.0-alpha.
|
|
86
|
-
"@gooddata/
|
|
87
|
-
"@gooddata/
|
|
88
|
-
"@gooddata/
|
|
84
|
+
"@gooddata/eslint-config": "11.41.0-alpha.1",
|
|
85
|
+
"@gooddata/oxlint-config": "11.41.0-alpha.1",
|
|
86
|
+
"@gooddata/sdk-backend-mockingbird": "11.41.0-alpha.1",
|
|
87
|
+
"@gooddata/stylelint-config": "11.41.0-alpha.1",
|
|
88
|
+
"@gooddata/reference-workspace": "11.41.0-alpha.1"
|
|
89
89
|
},
|
|
90
90
|
"peerDependencies": {
|
|
91
91
|
"react": "^18.0.0 || ^19.0.0",
|