@gooddata/sdk-ui-ext 11.52.0-alpha.4 → 11.52.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +22 -22
- package/esm/insightView/InsightRenderer.d.ts +5 -5
- package/esm/insightView/InsightRenderer.d.ts.map +1 -1
- package/esm/insightView/InsightRenderer.js +164 -140
- package/esm/internal/components/configurationControls/conditionalFormatting/CfDateValueDropdown.d.ts +3 -4
- package/esm/internal/components/configurationControls/conditionalFormatting/CfDateValueDropdown.d.ts.map +1 -1
- package/esm/internal/components/configurationControls/conditionalFormatting/CfDateValueDropdown.js +9 -7
- package/esm/internal/components/configurationControls/conditionalFormatting/ConditionEditor.d.ts.map +1 -1
- package/esm/internal/components/configurationControls/conditionalFormatting/ConditionEditor.js +57 -37
- package/esm/internal/components/configurationControls/conditionalFormatting/cfFieldProps.d.ts +12 -0
- package/esm/internal/components/configurationControls/conditionalFormatting/cfFieldProps.d.ts.map +1 -0
- package/esm/internal/components/configurationControls/conditionalFormatting/cfFieldProps.js +2 -0
- package/esm/internal/components/configurationControls/conditionalFormatting/conditionalFormattingModel.d.ts +10 -10
- package/esm/internal/components/configurationControls/conditionalFormatting/conditionalFormattingModel.d.ts.map +1 -1
- package/esm/internal/components/configurationControls/conditionalFormatting/conditionalFormattingModel.js +11 -11
- package/esm/internal/components/configurationPanels/PivotTableConfigurationPanel.d.ts.map +1 -1
- package/esm/internal/components/configurationPanels/PivotTableConfigurationPanel.js +2 -1
- package/esm/internal/components/pluggableVisualizations/mekko/PluggableMekko.d.ts.map +1 -1
- package/esm/internal/components/pluggableVisualizations/mekko/PluggableMekko.js +14 -1
- package/esm/internal/components/pluggableVisualizations/pivotTableNext/PivotTableNextDescriptor.d.ts.map +1 -1
- package/esm/internal/components/pluggableVisualizations/pivotTableNext/PivotTableNextDescriptor.js +2 -9
- package/esm/internal/components/pluggableVisualizations/pivotTableNext/PluggablePivotTableNext.d.ts.map +1 -1
- package/esm/internal/components/pluggableVisualizations/pivotTableNext/PluggablePivotTableNext.js +2 -2
- package/esm/internal/components/pluggableVisualizations/pivotTableNext/pivotTableNextConfigFromInsight.d.ts +8 -3
- package/esm/internal/components/pluggableVisualizations/pivotTableNext/pivotTableNextConfigFromInsight.d.ts.map +1 -1
- package/esm/internal/components/pluggableVisualizations/pivotTableNext/pivotTableNextConfigFromInsight.js +41 -37
- package/esm/internal/translations/en-US.localization-bundle.d.ts +8 -0
- package/esm/internal/translations/en-US.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/en-US.localization-bundle.js +8 -0
- package/esm/internal/utils/bucketHelper.d.ts.map +1 -1
- package/esm/internal/utils/bucketHelper.js +7 -14
- package/esm/internal/utils/embeddingCodeGenerator/insightToPropsConverter/convertor.d.ts +2 -2
- package/esm/internal/utils/embeddingCodeGenerator/insightToPropsConverter/convertor.d.ts.map +1 -1
- package/esm/internal/utils/embeddingCodeGenerator/insightToPropsConverter/convertor.js +4 -2
- package/esm/internal/utils/propertiesHelper.d.ts +5 -0
- package/esm/internal/utils/propertiesHelper.d.ts.map +1 -1
- package/esm/internal/utils/propertiesHelper.js +7 -0
- package/esm/locales.d.ts +6 -0
- package/esm/locales.d.ts.map +1 -1
- package/esm/locales.js +2 -0
- package/package.json +21 -21
package/esm/internal/components/configurationControls/conditionalFormatting/ConditionEditor.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
// (C) 2026 GoodData Corporation
|
|
3
|
-
import { useId } from "react";
|
|
3
|
+
import { useId, useState } from "react";
|
|
4
4
|
import cx from "classnames";
|
|
5
5
|
import { useIntl } from "react-intl";
|
|
6
6
|
import { Button, Dropdown, Input, InputWithNumberFormat, UiButton, UiButtonSegmentedControl, UiCombobox, UiComboboxInput, UiComboboxList, UiComboboxListItem, UiComboboxListItemLabel, UiComboboxPopup, } from "@gooddata/sdk-ui-kit";
|
|
@@ -10,9 +10,12 @@ import { CfDateValueDropdown } from "./CfDateValueDropdown.js";
|
|
|
10
10
|
import { CfSelect } from "./CfSelect.js";
|
|
11
11
|
import { CF_COLOR_PALETTE, colorToHex, hexToColor } from "./conditionalFormattingColors.js";
|
|
12
12
|
import { displayToRawNumber, literalRaw, literalText, operatorIcon, operatorsForTarget, rangeRaw, rawToDisplayNumber, validateCondition, valueEditorKind, valueForOperator, } from "./conditionalFormattingModel.js";
|
|
13
|
-
|
|
13
|
+
// InputPure's own contract for the same error state.
|
|
14
|
+
const inputErrorProps = ({ hasError, errorId, }) => hasError ? { hasError, accessibilityConfig: { ariaDescribedBy: errorId, ariaInvalid: true } } : {};
|
|
15
|
+
function CfMeasureValueInput({ raw, isPercent, separators, placeholder, onChangeRaw, ...field }) {
|
|
14
16
|
const intl = useIntl();
|
|
15
|
-
|
|
17
|
+
const { accessibilityConfig, ...errorProps } = inputErrorProps(field);
|
|
18
|
+
return (_jsx(InputWithNumberFormat, { value: raw === null ? undefined : rawToDisplayNumber(raw, isPercent), suffix: isPercent ? "%" : undefined, separators: separators, placeholder: placeholder, onChange: (display) => onChangeRaw(display === null ? null : displayToRawNumber(display, isPercent)), onBlur: field.onVisit, ...errorProps, accessibilityConfig: {
|
|
16
19
|
// InputPure renders the suffix aria-hidden; this is its accessible name.
|
|
17
20
|
...(isPercent
|
|
18
21
|
? {
|
|
@@ -22,8 +25,11 @@ function CfMeasureValueInput({ raw, isPercent, separators, placeholder, onChange
|
|
|
22
25
|
...accessibilityConfig,
|
|
23
26
|
} }));
|
|
24
27
|
}
|
|
28
|
+
function CfTextValueInput({ value, placeholder, onChangeText, ...field }) {
|
|
29
|
+
return (_jsx(Input, { type: "text", value: value, placeholder: placeholder, onChange: (v) => onChangeText(String(v)), onBlur: field.onVisit, ...inputErrorProps(field) }));
|
|
30
|
+
}
|
|
25
31
|
// Free-text combobox suggesting current-result element values; `creatable` = typed text is a valid value.
|
|
26
|
-
function CfValueCombobox({ value, suggestions, placeholder, onChangeText }) {
|
|
32
|
+
function CfValueCombobox({ value, suggestions, placeholder, hasError, errorId, onChangeText, onVisit, }) {
|
|
27
33
|
const idPrefix = useId();
|
|
28
34
|
const options = suggestions.map((suggestion, index) => ({
|
|
29
35
|
// aria-activedescendant needs a valid, document-unique DOM id (element values aren't); matching is by label.
|
|
@@ -31,56 +37,69 @@ function CfValueCombobox({ value, suggestions, placeholder, onChangeText }) {
|
|
|
31
37
|
label: suggestion,
|
|
32
38
|
}));
|
|
33
39
|
return (_jsxs(UiCombobox, { options: options, value: value, creatable: true, onValueChange: onChangeText, children: [
|
|
34
|
-
_jsx(UiComboboxInput, { placeholder: placeholder,
|
|
40
|
+
_jsx(UiComboboxInput, { placeholder: placeholder, isError: hasError, accessibilityConfig: {
|
|
41
|
+
ariaLabel: placeholder,
|
|
42
|
+
...(errorId ? { ariaDescribedBy: errorId } : {}),
|
|
43
|
+
}, onBlur: onVisit }), _jsx(UiComboboxPopup, { children: _jsx(UiComboboxList, { children: (option, index) => (_jsx(UiComboboxListItem, { option: option, index: index, children: _jsx(UiComboboxListItemLabel, { children: option.label }) })) }) })
|
|
35
44
|
] }));
|
|
36
45
|
}
|
|
37
46
|
const FIELD_ERROR_MESSAGE = {
|
|
38
47
|
rangeOrder: conditionalFormattingMessages.dialogErrorRangeOrder,
|
|
39
48
|
dateUnresolvable: conditionalFormattingMessages.dialogErrorDateUnresolvable,
|
|
49
|
+
valueEmpty: conditionalFormattingMessages.dialogErrorValueEmpty,
|
|
40
50
|
};
|
|
51
|
+
// The "Error:" label wraps the message through ICU, so each locale controls its wording and punctuation.
|
|
41
52
|
function CfFieldError({ id, error }) {
|
|
42
53
|
const intl = useIntl();
|
|
43
54
|
if (!error) {
|
|
44
55
|
return null;
|
|
45
56
|
}
|
|
46
|
-
return (_jsx("span", { id: id, role: "alert", className: "gd-cf-condition__error", children: intl.formatMessage(
|
|
57
|
+
return (_jsx("span", { id: id, role: "alert", className: "gd-cf-condition__error", children: intl.formatMessage(conditionalFormattingMessages.dialogErrorWrapper, {
|
|
58
|
+
message: intl.formatMessage(FIELD_ERROR_MESSAGE[error]),
|
|
59
|
+
}) }));
|
|
47
60
|
}
|
|
48
|
-
function ConditionValueInput({ condition, kind, isPercent, separators, suggestions, date, dateFilterOptions, dateSettings, onChange, }) {
|
|
61
|
+
function ConditionValueInput({ condition, editorKind, kind, isPercent, separators, suggestions, date, dateFilterOptions, dateSettings, onChange, }) {
|
|
49
62
|
const intl = useIntl();
|
|
50
63
|
const errorId = useId();
|
|
64
|
+
// Empty is only an error once the field has been visited, so authoring a rule top-down never reddens
|
|
65
|
+
// fields not reached yet. A field a retarget clears stays visited on purpose (it explains the Save).
|
|
66
|
+
const [visited, setVisited] = useState({});
|
|
67
|
+
const markVisited = (field) => () => setVisited((current) => ({ ...current, [field]: true }));
|
|
51
68
|
const setValue = (value) => onChange({ ...condition, value });
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
69
|
+
const placeholder = intl.formatMessage(conditionalFormattingMessages.dialogValuePlaceholder);
|
|
70
|
+
const { missing, error: invalid } = validateCondition(condition, kind, date);
|
|
71
|
+
const isEmpty = (field) => field === "value" ? missing : rangeRaw(condition.value, field) === null;
|
|
72
|
+
const emptyIn = (field) => visited[field] && isEmpty(field) ? "valueEmpty" : undefined;
|
|
73
|
+
// Invalid input marks every field of the condition (the order error is relational); emptiness marks
|
|
74
|
+
// only the blank field. Fields the editor doesn't render never get visited, so they contribute nothing.
|
|
75
|
+
const fieldProps = (field) => {
|
|
76
|
+
const hasError = (invalid ?? emptyIn(field)) !== undefined;
|
|
77
|
+
return { hasError, errorId: hasError ? errorId : undefined, onVisit: markVisited(field) };
|
|
78
|
+
};
|
|
79
|
+
const error = invalid ?? emptyIn("value") ?? emptyIn("from") ?? emptyIn("to");
|
|
80
|
+
const renderControl = () => {
|
|
81
|
+
switch (editorKind) {
|
|
82
|
+
case "none":
|
|
57
83
|
return null;
|
|
84
|
+
case "date":
|
|
85
|
+
return date ? (_jsx(CfDateValueDropdown, { value: condition.value, date: date, catalogOptions: dateFilterOptions, dateSettings: dateSettings, onChange: setValue, ...fieldProps("value") })) : null;
|
|
86
|
+
case "number":
|
|
87
|
+
return (_jsx(CfMeasureValueInput, { raw: literalRaw(condition.value), isPercent: isPercent, separators: separators, placeholder: placeholder, onChangeRaw: (raw) => setValue({ kind: "literal", value: raw ?? "" }), ...fieldProps("value") }));
|
|
88
|
+
case "combobox":
|
|
89
|
+
return (_jsx(CfValueCombobox, { value: literalText(condition.value), suggestions: suggestions, placeholder: placeholder, onChangeText: (v) => setValue({ kind: "literal", value: v }), ...fieldProps("value") }));
|
|
90
|
+
case "text":
|
|
91
|
+
return (_jsx(CfTextValueInput, { value: literalText(condition.value), placeholder: placeholder, onChangeText: (v) => setValue({ kind: "literal", value: v }), ...fieldProps("value") }));
|
|
92
|
+
case "range": {
|
|
93
|
+
const range = condition.value.kind === "literalRange" ? condition.value : { from: NaN, to: NaN };
|
|
94
|
+
const setRange = (from, to) => setValue({ kind: "literalRange", from, to });
|
|
95
|
+
return (_jsxs("div", { className: "gd-cf-condition__range", children: [
|
|
96
|
+
_jsx(CfMeasureValueInput, { raw: rangeRaw(condition.value, "from"), isPercent: isPercent, separators: separators, placeholder: intl.formatMessage(conditionalFormattingMessages.dialogFromPlaceholder), onChangeRaw: (raw) => setRange(raw ?? NaN, range.to), ...fieldProps("from") }), _jsx(CfMeasureValueInput, { raw: rangeRaw(condition.value, "to"), isPercent: isPercent, separators: separators, placeholder: intl.formatMessage(conditionalFormattingMessages.dialogToPlaceholder), onChangeRaw: (raw) => setRange(range.from, raw ?? NaN), ...fieldProps("to") })
|
|
97
|
+
] }));
|
|
58
98
|
}
|
|
59
|
-
const { errors } = validateCondition(condition, kind, date);
|
|
60
|
-
return (_jsxs(_Fragment, { children: [
|
|
61
|
-
_jsx(CfDateValueDropdown, { value: condition.value, date: date, catalogOptions: dateFilterOptions, dateSettings: dateSettings, errorId: errors.date ? errorId : undefined, onChange: setValue }), _jsx(CfFieldError, { id: errorId, error: errors.date })
|
|
62
|
-
] }));
|
|
63
|
-
}
|
|
64
|
-
case "number":
|
|
65
|
-
return (_jsx(CfMeasureValueInput, { raw: literalRaw(condition.value), isPercent: isPercent, separators: separators, placeholder: intl.formatMessage(conditionalFormattingMessages.dialogValuePlaceholder), onChangeRaw: (raw) => setValue({ kind: "literal", value: raw ?? "" }) }));
|
|
66
|
-
case "combobox":
|
|
67
|
-
return (_jsx(CfValueCombobox, { value: literalText(condition.value), suggestions: suggestions, placeholder: intl.formatMessage(conditionalFormattingMessages.dialogValuePlaceholder), onChangeText: (v) => setValue({ kind: "literal", value: v }) }));
|
|
68
|
-
case "text":
|
|
69
|
-
return (_jsx(Input, { type: "text", value: literalText(condition.value), placeholder: intl.formatMessage(conditionalFormattingMessages.dialogValuePlaceholder), onChange: (v) => setValue({ kind: "literal", value: String(v) }) }));
|
|
70
|
-
case "range": {
|
|
71
|
-
const range = condition.value.kind === "literalRange" ? condition.value : { from: NaN, to: NaN };
|
|
72
|
-
const setRange = (from, to) => setValue({ kind: "literalRange", from, to });
|
|
73
|
-
const { errors } = validateCondition(condition, kind);
|
|
74
|
-
const invalidInputProps = (error) => error
|
|
75
|
-
? { hasError: true, accessibilityConfig: { ariaDescribedBy: errorId, ariaInvalid: true } }
|
|
76
|
-
: {};
|
|
77
|
-
return (_jsxs(_Fragment, { children: [
|
|
78
|
-
_jsxs("div", { className: "gd-cf-condition__range", children: [
|
|
79
|
-
_jsx(CfMeasureValueInput, { raw: rangeRaw(condition.value, "from"), isPercent: isPercent, separators: separators, placeholder: intl.formatMessage(conditionalFormattingMessages.dialogFromPlaceholder), onChangeRaw: (raw) => setRange(raw ?? NaN, range.to), ...invalidInputProps(errors.range) }), _jsx(CfMeasureValueInput, { raw: rangeRaw(condition.value, "to"), isPercent: isPercent, separators: separators, placeholder: intl.formatMessage(conditionalFormattingMessages.dialogToPlaceholder), onChangeRaw: (raw) => setRange(range.from, raw ?? NaN), ...invalidInputProps(errors.range) })
|
|
80
|
-
] }), _jsx(CfFieldError, { id: errorId, error: errors.range })
|
|
81
|
-
] }));
|
|
82
99
|
}
|
|
83
|
-
}
|
|
100
|
+
};
|
|
101
|
+
return (_jsxs(_Fragment, { children: [renderControl(), _jsx(CfFieldError, { id: errorId, error: error })
|
|
102
|
+
] }));
|
|
84
103
|
}
|
|
85
104
|
// The ColorDropdown trigger swatch. ColorDropdown clones it with selectable-child props the swatch
|
|
86
105
|
// ignores. No color renders a "none" slash rather than a misleading white.
|
|
@@ -118,6 +137,7 @@ export function ConditionEditor({ condition, kind, isPercent, separators, sugges
|
|
|
118
137
|
icon: isDate ? undefined : operatorIcon(operator),
|
|
119
138
|
}));
|
|
120
139
|
const setFormat = (format) => onChange({ ...condition, format });
|
|
140
|
+
const editorKind = valueEditorKind(condition, kind, suggestions.length > 0, isDate);
|
|
121
141
|
const previewStyle = {
|
|
122
142
|
...(condition.format.color ? { color: condition.format.color } : {}),
|
|
123
143
|
...(condition.format.backgroundColor ? { backgroundColor: condition.format.backgroundColor } : {}),
|
|
@@ -129,7 +149,7 @@ export function ConditionEditor({ condition, kind, isPercent, separators, sugges
|
|
|
129
149
|
...condition,
|
|
130
150
|
operator,
|
|
131
151
|
value: valueForOperator(operator, condition.value, isDate),
|
|
132
|
-
}) }), _jsx(ConditionValueInput, { condition: condition, kind: kind, isPercent: isPercent, separators: separators, suggestions: suggestions, date: date, dateFilterOptions: dateFilterOptions, dateSettings: dateSettings, onChange: onChange }), _jsxs("div", { className: "gd-cf-condition__format-row", children: [
|
|
152
|
+
}) }), _jsx(ConditionValueInput, { condition: condition, editorKind: editorKind, kind: kind, isPercent: isPercent, separators: separators, suggestions: suggestions, date: date, dateFilterOptions: dateFilterOptions, dateSettings: dateSettings, onChange: onChange }, editorKind), _jsxs("div", { className: "gd-cf-condition__format-row", children: [
|
|
133
153
|
_jsx("span", { className: "gd-cf-dialog__label", children: intl.formatMessage(conditionalFormattingMessages.dialogFormat) }), _jsx("div", { className: "gd-cf-preview", children: condition.format.scope === "row" ? (ROW_PREVIEW_SAMPLE.map((sample, index) => (_jsx("span", { className: "gd-cf-preview__cell", style: previewStyle, children: sample }, index)))) : (_jsx("span", { className: "gd-cf-preview__cell", style: previewStyle, children: PREVIEW_SAMPLE[kind] })) }), _jsx(FormatEditor, { format: condition.format, onChange: setFormat })
|
|
134
154
|
] })
|
|
135
155
|
] }));
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How every value editor of a condition takes its error state: one flag for the visuals, one id for the
|
|
3
|
+
* assistive-tech association, one "the user has been here" signal. Uniform across the inputs, the
|
|
4
|
+
* combobox and the date picker, so the editor can hand any control the same object.
|
|
5
|
+
*/
|
|
6
|
+
export interface ICfFieldProps {
|
|
7
|
+
hasError: boolean;
|
|
8
|
+
errorId: string | undefined;
|
|
9
|
+
/** The field was visited and left. Each control maps it to whatever that means for it. */
|
|
10
|
+
onVisit: () => void;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=cfFieldProps.d.ts.map
|
package/esm/internal/components/configurationControls/conditionalFormatting/cfFieldProps.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cfFieldProps.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/cfFieldProps.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,0FAA0F;IAC1F,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB"}
|
|
@@ -94,11 +94,10 @@ export declare const isPercentFormat: (format: string | undefined) => boolean;
|
|
|
94
94
|
export declare const rawToDisplayNumber: (raw: number, percent: boolean) => number;
|
|
95
95
|
/** Number entered in a percent input -> the raw number stored and compared (÷100). */
|
|
96
96
|
export declare const displayToRawNumber: (display: number, percent: boolean) => number;
|
|
97
|
-
|
|
98
|
-
export
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
97
|
+
/** Present-but-invalid input, detected by {@link validateCondition}. */
|
|
98
|
+
export type ConditionInvalidError = "rangeOrder" | "dateUnresolvable";
|
|
99
|
+
/** Everything the editor renders inline: the model's errors plus its own blank-visited-field state. */
|
|
100
|
+
export type ConditionalFormattingFieldError = ConditionInvalidError | "valueEmpty";
|
|
102
101
|
/**
|
|
103
102
|
* Coerces stored condition shapes the editor cannot represent so an AAC-authored rule opens editable
|
|
104
103
|
* instead of dead-ended (disabled Save then covers the cleared values). A non-numeric measure literal
|
|
@@ -107,14 +106,15 @@ export interface IConditionErrors {
|
|
|
107
106
|
*/
|
|
108
107
|
export declare const sanitizeRuleForEditing: (rule: IConditionalFormattingRule, isDate?: boolean) => IConditionalFormattingRule;
|
|
109
108
|
export interface IConditionValidation {
|
|
110
|
-
/** A required operand is absent — gates Save
|
|
109
|
+
/** A required operand is absent — gates Save; the editor shows it only on a visited field. */
|
|
111
110
|
missing: boolean;
|
|
112
|
-
/** Present-but-invalid input — surfaced inline by the editor (and also gates Save). */
|
|
113
|
-
|
|
111
|
+
/** Present-but-invalid input — surfaced inline by the editor immediately (and also gates Save). */
|
|
112
|
+
error?: ConditionInvalidError;
|
|
114
113
|
}
|
|
115
114
|
/**
|
|
116
|
-
* Single source for both validation surfaces
|
|
117
|
-
*
|
|
115
|
+
* Single source for both validation surfaces: {@link isRuleComplete} derives from the whole result,
|
|
116
|
+
* while the editor renders `error` unconditionally and `missing` only once the field has been
|
|
117
|
+
* visited (a value the user hasn't reached yet is incomplete, not wrong).
|
|
118
118
|
*/
|
|
119
119
|
export declare const validateCondition: (condition: IConditionalFormattingCondition, kind: "attribute" | "measure", date?: ICfDateMeta | undefined) => IConditionValidation;
|
|
120
120
|
/** A rule is saveable when every condition has a valid operand for its operator. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"conditionalFormattingModel.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/conditionalFormattingModel.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"conditionalFormattingModel.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/conditionalFormattingModel.ts"],"names":[],"mappings":"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"}
|
|
@@ -380,44 +380,44 @@ export const sanitizeRuleForEditing = (rule, isDate = false) => {
|
|
|
380
380
|
};
|
|
381
381
|
};
|
|
382
382
|
/**
|
|
383
|
-
* Single source for both validation surfaces
|
|
384
|
-
*
|
|
383
|
+
* Single source for both validation surfaces: {@link isRuleComplete} derives from the whole result,
|
|
384
|
+
* while the editor renders `error` unconditionally and `missing` only once the field has been
|
|
385
|
+
* visited (a value the user hasn't reached yet is incomplete, not wrong).
|
|
385
386
|
*/
|
|
386
387
|
export const validateCondition = (condition, kind, date) => {
|
|
387
388
|
const { value } = condition;
|
|
388
389
|
switch (operatorArity(condition.operator)) {
|
|
389
390
|
case "none":
|
|
390
|
-
return { missing: false
|
|
391
|
+
return { missing: false };
|
|
391
392
|
case "range": {
|
|
392
393
|
if (value.kind !== "literalRange") {
|
|
393
|
-
return { missing: true
|
|
394
|
+
return { missing: true };
|
|
394
395
|
}
|
|
395
396
|
const missing = !Number.isFinite(value.from) || !Number.isFinite(value.to);
|
|
396
|
-
return
|
|
397
|
+
return !missing && value.from > value.to ? { missing, error: "rangeOrder" } : { missing };
|
|
397
398
|
}
|
|
398
399
|
case "single":
|
|
399
400
|
if (date) {
|
|
400
401
|
if (!isDateConditionValue(value)) {
|
|
401
|
-
return { missing: true
|
|
402
|
+
return { missing: true };
|
|
402
403
|
}
|
|
403
404
|
// Unresolvable (malformed value, fiscal granularity) never matches — block Save.
|
|
404
405
|
const resolvable = resolveDateConditionBounds(value, date.granularity, date.timezone) !== null;
|
|
405
|
-
return { missing: false
|
|
406
|
+
return resolvable ? { missing: false } : { missing: false, error: "dateUnresolvable" };
|
|
406
407
|
}
|
|
407
408
|
if (value.kind !== "literal") {
|
|
408
|
-
return { missing: true
|
|
409
|
+
return { missing: true };
|
|
409
410
|
}
|
|
410
411
|
// Guard the empty string first: `Number("") === 0` (not NaN), which would otherwise let an
|
|
411
412
|
// empty measure threshold pass as a valid 0.
|
|
412
413
|
return {
|
|
413
414
|
missing: isBlank(value.value) || (kind === "measure" && Number.isNaN(Number(value.value))),
|
|
414
|
-
errors: {},
|
|
415
415
|
};
|
|
416
416
|
}
|
|
417
417
|
};
|
|
418
418
|
/** A rule is saveable when every condition has a valid operand for its operator. */
|
|
419
419
|
export const isRuleComplete = (rule, date) => rule.conditions.length > 0 &&
|
|
420
420
|
rule.conditions.every((condition) => {
|
|
421
|
-
const { missing,
|
|
422
|
-
return !missing &&
|
|
421
|
+
const { missing, error } = validateCondition(condition, rule.target.kind, date);
|
|
422
|
+
return !missing && !error;
|
|
423
423
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PivotTableConfigurationPanel.d.ts","sourceRoot":"","sources":["../../../../src/internal/components/configurationPanels/PivotTableConfigurationPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EACH,KAAK,WAAW,EAInB,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"PivotTableConfigurationPanel.d.ts","sourceRoot":"","sources":["../../../../src/internal/components/configurationPanels/PivotTableConfigurationPanel.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAKvC,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EACH,KAAK,WAAW,EAInB,MAAM,qBAAqB,CAAC;AAc7B,OAAO,EACH,KAAK,eAAe,EACpB,KAAK,aAAa,EACrB,MAAM,8EAA8E,CAAC;AAQtF,OAAO,EACH,yBAAyB,EACzB,KAAK,+BAA+B,EACvC,MAAM,gCAAgC,CAAC;AACxC,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAGpD,UAAU,kCAAmC,SAAQ,+BAA+B;IAChF,YAAY,CAAC,EAAE,aAAa,CAAC;IAC7B,6FAA6F;IAC7F,SAAS,CAAC,EAAE,kBAAkB,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,eAAe,CAAC;IACjC,UAAU,CAAC,EAAE,WAAW,CAAC;CAC5B;AAED,qBAAa,4BAA6B,SAAQ,yBAAyB,CAAC,kCAAkC,CAAC;IAC3G,UAAmB,iBAAiB,CAAC,WAAW,CAAC,EAAE,WAAW,GAAG,OAAO,CAgBvE;IAED,SAAS,CAAC,wBAAwB,IAAI,SAAS,CAwB9C;IAED,OAAO,CAAC,mBAAmB;IAS3B,OAAO,CAAC,yBAAyB;IAYjC,OAAO,CAAC,sCAAsC;IAU9C,OAAO,CAAC,mBAAmB;IAqD3B,OAAO,CAAC,kCAAkC;IA8B1C,OAAO,CAAC,mBAAmB;CAY9B"}
|
|
@@ -6,6 +6,7 @@ import { Bubble, BubbleHoverTrigger } from "@gooddata/sdk-ui-kit";
|
|
|
6
6
|
import { messages } from "../../../locales.js";
|
|
7
7
|
import { BUBBLE_ARROW_OFFSET_X, BUBBLE_ARROW_OFFSET_Y, HIDE_DELAY_DEFAULT, SHOW_DELAY_DEFAULT, } from "../../constants/bubble.js";
|
|
8
8
|
import { isSetColumnHeadersPositionToLeftAllowed } from "../../utils/controlsHelper.js";
|
|
9
|
+
import { isConditionalFormattingEnabled } from "../../utils/propertiesHelper.js";
|
|
9
10
|
import { CellsControl } from "../configurationControls/CellsControl.js";
|
|
10
11
|
import { ColumnHeadersPositionControl } from "../configurationControls/ColumnHeadersPositionControl.js";
|
|
11
12
|
import { ConditionalFormattingSection } from "../configurationControls/conditionalFormatting/ConditionalFormattingSection.js";
|
|
@@ -32,7 +33,7 @@ export class PivotTableConfigurationPanel extends ConfigurationPanelContent {
|
|
|
32
33
|
renderConfigurationPanel() {
|
|
33
34
|
const { featureFlags } = this.props;
|
|
34
35
|
const enableNewPivotTable = featureFlags?.enableNewPivotTable ?? true;
|
|
35
|
-
const enableConditionalFormatting = featureFlags
|
|
36
|
+
const enableConditionalFormatting = isConditionalFormattingEnabled(featureFlags);
|
|
36
37
|
return (_jsxs(BubbleHoverTrigger, { showDelay: SHOW_DELAY_DEFAULT, hideDelay: HIDE_DELAY_DEFAULT, children: [
|
|
37
38
|
_jsxs("div", { children: [this.renderInteractionsSection(), enableNewPivotTable ? this.renderPagingSection() : null, this.renderCanvasSection(), enableNewPivotTable && enableConditionalFormatting
|
|
38
39
|
? this.renderConditionalFormattingSection()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluggableMekko.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/pluggableVisualizations/mekko/PluggableMekko.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,WAAW,EAA0B,MAAM,mCAAmC,CAAC;AAC7F,OAAO,EACH,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,aAAa,EACrB,MAAM,sCAAsC,CAAC;AAU9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"PluggableMekko.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/pluggableVisualizations/mekko/PluggableMekko.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,KAAK,WAAW,EAA0B,MAAM,mCAAmC,CAAC;AAC7F,OAAO,EACH,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,aAAa,EACrB,MAAM,sCAAsC,CAAC;AAU9C,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAoBxE;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,cAAe,SAAQ,kBAAkB;IAClD,YAAY,KAAK,EAAE,aAAa,EAK/B;IAEe,yBAAyB,CACrC,cAAc,EAAE,eAAe,GAChC,OAAO,CAAC,uBAAuB,CAAC,CAyBlC;IAEe,aAAa,CAAC,cAAc,EAAE,eAAe,GAAG,OAAO,CAAC,WAAW,CAAC,CA6CnF;CACJ"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// (C) 2026 GoodData Corporation
|
|
2
|
-
import { cloneDeep, isEmpty } from "lodash-es";
|
|
2
|
+
import { cloneDeep, isEmpty, set } from "lodash-es";
|
|
3
3
|
import { newAttributeSort } from "@gooddata/sdk-model";
|
|
4
4
|
import { BucketNames, VisualizationTypes } from "@gooddata/sdk-ui";
|
|
5
5
|
import { BUCKETS } from "../../../constants/bucket.js";
|
|
@@ -12,6 +12,18 @@ import { getReferencePointWithSupportedProperties } from "../../../utils/propert
|
|
|
12
12
|
import { setMekkoUiConfig } from "../../../utils/uiConfigHelpers/mekkoUiConfigHelper.js";
|
|
13
13
|
import { PluggableBaseChart } from "../baseChart/PluggableBaseChart.js";
|
|
14
14
|
import { transformBuckets } from "./bucketHelper.js";
|
|
15
|
+
/** Width-only + Stack By locks "Stack to 100%" via uiConfig only — never the durable user property. */
|
|
16
|
+
function lockPercentStackingForWidthOnly(referencePoint) {
|
|
17
|
+
const buckets = referencePoint[BUCKETS];
|
|
18
|
+
const widthOnlyWithStack = !isEmpty(getBucketItems(buckets, BucketNames.MEASURES)) &&
|
|
19
|
+
isEmpty(getBucketItems(buckets, BucketNames.SECONDARY_MEASURES)) &&
|
|
20
|
+
!isEmpty(getBucketItems(buckets, BucketNames.STACK));
|
|
21
|
+
if (widthOnlyWithStack) {
|
|
22
|
+
set(referencePoint, ["uiConfig", "optionalStacking", "disabled"], true);
|
|
23
|
+
set(referencePoint, ["uiConfig", "optionalStacking", "stackMeasuresToPercent"], true);
|
|
24
|
+
}
|
|
25
|
+
return referencePoint;
|
|
26
|
+
}
|
|
15
27
|
/**
|
|
16
28
|
* PluggableMekko
|
|
17
29
|
*
|
|
@@ -55,6 +67,7 @@ export class PluggableMekko extends PluggableBaseChart {
|
|
|
55
67
|
newReferencePoint = removeAllDerivedMeasures(newReferencePoint);
|
|
56
68
|
newReferencePoint[BUCKETS] = transformBuckets(newReferencePoint.buckets);
|
|
57
69
|
newReferencePoint = setMekkoUiConfig(newReferencePoint, this.intl, this.type);
|
|
70
|
+
newReferencePoint = lockPercentStackingForWidthOnly(newReferencePoint);
|
|
58
71
|
newReferencePoint = configurePercent(newReferencePoint, true);
|
|
59
72
|
newReferencePoint = configureOverTimeComparison(newReferencePoint);
|
|
60
73
|
newReferencePoint = getReferencePointWithSupportedProperties(newReferencePoint, this.supportedPropertiesList);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PivotTableNextDescriptor.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/pluggableVisualizations/pivotTableNext/PivotTableNextDescriptor.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,SAAS,EAGjB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACtF,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EACH,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EACrC,MAAM,gDAAgD,CAAC;AAgBxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"PivotTableNextDescriptor.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/pluggableVisualizations/pivotTableNext/PivotTableNextDescriptor.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,SAAS,EAGjB,MAAM,qBAAqB,CAAC;AAI7B,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,yCAAyC,CAAC;AACtF,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EACH,KAAK,wBAAwB,EAC7B,KAAK,kBAAkB,EACvB,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EACrC,MAAM,gDAAgD,CAAC;AAgBxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAe1E,qBAAa,wBAAyB,SAAQ,mBAAoB,YAAW,wBAAwB;IAC1F,UAAU,IAAI,6BAA6B,CAEjD;IAEe,WAAW,CACvB,QAAQ,EAAE,kBAAkB,EAC5B,gBAAgB,EAAE,sBAAsB,EACxC,QAAQ,EAAE,SAAS,GACpB,sBAAsB,CAaxB;IAED,UAAmB,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAG5D;IAEe,cAAc,CAC1B,OAAO,EAAE,QAAQ,EACjB,gBAAgB,EAAE,iBAAiB,EACnC,0BAA0B,EAAE,OAAO,GACpC,QAAQ,CAWV;IAEM,gBAAgB,8IA4BpB;IAEI,OAAO,IAAI,kBAAkB,CAOnC;CACJ"}
|
package/esm/internal/components/pluggableVisualizations/pivotTableNext/PivotTableNextDescriptor.js
CHANGED
|
@@ -9,7 +9,7 @@ import { BaseChartDescriptor } from "../baseChart/BaseChartDescriptor.js";
|
|
|
9
9
|
import { MIN_VISUALIZATION_HEIGHT_TABLE_REPEATER_FLEXIBLE_LAYOUT } from "../constants.js";
|
|
10
10
|
import { addIntersectionFiltersToInsight, modifyBucketsAttributesForDrillDown, sanitizeTableProperties, } from "../drillDownUtil.js";
|
|
11
11
|
import { pivotTableNextAdditionalFactories } from "./pivotTableNextAdditionalFactories.js";
|
|
12
|
-
import { pivotTableNextConfigFromInsight } from "./pivotTableNextConfigFromInsight.js";
|
|
12
|
+
import { pivotTableNextConfigFromInsight, pivotTableNextConfigPropMeta, } from "./pivotTableNextConfigFromInsight.js";
|
|
13
13
|
import { PluggablePivotTableNext } from "./PluggablePivotTableNext.js";
|
|
14
14
|
export class PivotTableNextDescriptor extends BaseChartDescriptor {
|
|
15
15
|
getFactory() {
|
|
@@ -51,14 +51,7 @@ export class PivotTableNextDescriptor extends BaseChartDescriptor {
|
|
|
51
51
|
filters: filtersInsightConversion("filters"),
|
|
52
52
|
sortBy: sortsInsightConversion("sortBy"),
|
|
53
53
|
totals: totalsInsightConversion("totals"),
|
|
54
|
-
config: insightConversion("config",
|
|
55
|
-
typeImport: {
|
|
56
|
-
importType: "named",
|
|
57
|
-
name: "PivotTableNextConfig",
|
|
58
|
-
package: "@gooddata/sdk-ui-pivot/next",
|
|
59
|
-
},
|
|
60
|
-
cardinality: "scalar",
|
|
61
|
-
}, pivotTableNextConfigFromInsight),
|
|
54
|
+
config: insightConversion("config", pivotTableNextConfigPropMeta, pivotTableNextConfigFromInsight),
|
|
62
55
|
pageSize: insightConversion("pageSize", { cardinality: "scalar" }, (insight) => {
|
|
63
56
|
const pagination = getPaginationFromProperties(insightProperties(insight));
|
|
64
57
|
const pageSize = getPageSizeFromProperties(insightProperties(insight));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PluggablePivotTableNext.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/pluggableVisualizations/pivotTableNext/PluggablePivotTableNext.tsx"],"names":[],"mappings":"AAIA,OAAO,EAGH,KAAK,iBAAiB,EACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,SAAS,EAYjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAIH,KAAK,wBAAwB,EAEhC,MAAM,kBAAkB,CAAC;AAM1B,OAAO,
|
|
1
|
+
{"version":3,"file":"PluggablePivotTableNext.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/pluggableVisualizations/pivotTableNext/PluggablePivotTableNext.tsx"],"names":[],"mappings":"AAIA,OAAO,EAGH,KAAK,iBAAiB,EACzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EACH,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,kBAAkB,EACvB,KAAK,SAAS,EAYjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAIH,KAAK,wBAAwB,EAEhC,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EAGH,KAAK,oBAAoB,EAE5B,MAAM,6BAA6B,CAAC;AAKrC,OAAO,EAEH,KAAK,iBAAiB,EACtB,KAAK,uBAAuB,EAC5B,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,SAAS,EACd,KAAK,wBAAwB,EAGhC,MAAM,sCAAsC,CAAC;AAoC9C,OAAO,EAAE,8BAA8B,EAAE,MAAM,sCAAsC,CAAC;AAiBtF,wBAAgB,0BAA0B,CACtC,MAAM,EAAE,UAAU,EAClB,WAAW,EAAE,wBAAwB,EACrC,QAAQ,EAAE,SAAS,GACpB,oBAAoB,CAoBtB;AAED;;;;;GAKG;AACH,qBAAa,uBAAwB,SAAQ,8BAA8B;IACvE,OAAO,CAAC,SAAS,CAAiB;IAClC,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAY;IACrC,OAAO,CAAC,mBAAmB,CAAuB;IAElD,OAAO,CAAC,SAAS,CAAqB;IACtC,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,WAAW,CAAuC;IAE1D,OAAO,CAAC,YAAY,CAAqB;IAEzC,YAAY,KAAK,EAAE,aAAa,EAqB/B;IAEM,OAAO,IAAI,IAAI,CAErB;IAEM,yBAAyB,CAC5B,cAAc,EAAE,eAAe,EAC/B,sBAAsB,CAAC,EAAE,eAAe,GACzC,OAAO,CAAC,uBAAuB,CAAC,CA8GlC;IAEe,8BAA8B,CAC1C,mBAAmB,EAAE,QAAQ,EAC7B,gBAAgB,EAAE,iBAAiB,EACnC,0BAA0B,EAAE,OAAO,GACpC,QAAQ,CAWV;IAED,OAAO,CAAC,kBAAkB;IAInB,YAAY,CACf,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,kBAAkB,EAC3B,gBAAgB,EAAE,iBAAiB,0DActC;IAED,SAAS,CAAC,oBAAoB,CAAC,uBAAuB,EAAE,wBAAwB,GAAG,IAAI,CActF;IAKD,OAAO,CAAC,cAAc,CAIpB;IAIF,OAAO,CAAC,oBAAoB,CAO1B;IAEF,OAAO,CAAC,yBAAyB,CAe/B;IAEF,UAAmB,wBAAwB,CACvC,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,kBAAkB,EAC3B,qBAAqB,EAAE,GAAG,GAC3B,IAAI,CASN;IAED,UAAmB,iBAAiB,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAOzE;IAED,SAAS,CAAC,mBAAmB,CACzB,OAAO,EAAE,SAAS,EAClB,OAAO,EAAE,kBAAkB,EAC3B,gBAAgB,EAAE,iBAAiB,GACpC,IAAI,CAmFN;IAED,SAAS,CAAC,wBAAwB,CAAC,OAAO,EAAE,kBAAkB,EAAE,OAAO,EAAE,SAAS,GAAG,IAAI,CA6BxF;IAED,SAAS,CAAC,aAAa,CAAC,OAAO,EAAE,kBAAkB,EAAE,yBAAyB,CAAC,EAAE,GAAG,GAAG,UAAU,EAAE,CAElG;IAED,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,oBAAoB;IA8B5B,OAAO,CAAC,eAAe;IAavB,OAAO,CAAC,cAAc;CAmCzB"}
|
package/esm/internal/components/pluggableVisualizations/pivotTableNext/PluggablePivotTableNext.js
CHANGED
|
@@ -11,7 +11,7 @@ import { configureOverTimeComparison, configurePercent } from "../../../utils/bu
|
|
|
11
11
|
import { getAllItemsByType, getTotalsFromBucket, limitNumberOfMeasuresInBuckets, removeDuplicateBucketItems, sanitizeFilters, } from "../../../utils/bucketHelper.js";
|
|
12
12
|
import { isSetColumnHeadersPositionToLeftAllowed } from "../../../utils/controlsHelper.js";
|
|
13
13
|
import { generateDimensions } from "../../../utils/dimensions.js";
|
|
14
|
-
import { getColumnHeadersPositionFromProperties, getColumnWidthsFromProperties, getConditionalFormattingFromProperties, getGrandTotalsPositionFromProperties, getMeasureGroupDimensionFromProperties, getPageSizeFromProperties, getPaginationFromProperties, getPivotTableProperties, getReferencePointWithSupportedProperties, getSupportedPropertiesControls, getTextWrappingFromProperties, } from "../../../utils/propertiesHelper.js";
|
|
14
|
+
import { getColumnHeadersPositionFromProperties, getColumnWidthsFromProperties, getConditionalFormattingFromProperties, getGrandTotalsPositionFromProperties, getMeasureGroupDimensionFromProperties, getPageSizeFromProperties, getPaginationFromProperties, getPivotTableProperties, getReferencePointWithSupportedProperties, getSupportedPropertiesControls, getTextWrappingFromProperties, isConditionalFormattingEnabled, } from "../../../utils/propertiesHelper.js";
|
|
15
15
|
import { getPivotTableNextDefaultUiConfig, getPivotTableNextMeasuresLimit, setPivotTableNextUiConfig, } from "../../../utils/uiConfigHelpers/pivotTableNextUiConfigHelper.js";
|
|
16
16
|
import { buildCfTargetData, } from "../../configurationControls/conditionalFormatting/conditionalFormattingModel.js";
|
|
17
17
|
import { PivotTableConfigurationPanel } from "../../configurationPanels/PivotTableConfigurationPanel.js";
|
|
@@ -264,7 +264,7 @@ export class PluggablePivotTableNext extends AbstractPluggableVisualization {
|
|
|
264
264
|
const growToFit = this.environment === DASHBOARDS_ENVIRONMENT;
|
|
265
265
|
const isInEditMode = config?.isInEditMode;
|
|
266
266
|
const pagination = getPaginationFromProperties(insightProperties(insight));
|
|
267
|
-
const enableConditionalFormatting = this.settings
|
|
267
|
+
const enableConditionalFormatting = isConditionalFormattingEnabled(this.settings);
|
|
268
268
|
const tableConfig = {
|
|
269
269
|
...createPivotTableNextConfig(config, this.environment, this.settings),
|
|
270
270
|
...customVisualizationConfig,
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import { type IInsightDefinition, type ISettings } from "@gooddata/sdk-model";
|
|
2
|
-
import { type PivotTableNextConfig } from "@gooddata/sdk-ui-pivot/next";
|
|
2
|
+
import { type PivotTableNextConfig, type PivotTableNextConfigWithConditionalFormatting } from "@gooddata/sdk-ui-pivot/next";
|
|
3
3
|
import { type IEmbeddingCodeContext } from "../../../interfaces/VisualizationDescriptor.js";
|
|
4
|
-
import { type PropWithMeta } from "../../../utils/embeddingCodeGenerator/types.js";
|
|
4
|
+
import { type PropMeta, type PropWithMeta } from "../../../utils/embeddingCodeGenerator/types.js";
|
|
5
|
+
/**
|
|
6
|
+
* Only a config that actually carries conditional formatting references the `@alpha` extended
|
|
7
|
+
* type; every other snippet stays on the `@public` {@link PivotTableNextConfig}.
|
|
8
|
+
*/
|
|
9
|
+
export declare function pivotTableNextConfigPropMeta(config: unknown): PropMeta;
|
|
5
10
|
export declare function isPivotTableNext(insightDefinition: IInsightDefinition, settings: ISettings | undefined): boolean;
|
|
6
|
-
export declare function pivotTableNextConfigFromInsight(insight: IInsightDefinition, ctx: IEmbeddingCodeContext | undefined):
|
|
11
|
+
export declare function pivotTableNextConfigFromInsight(insight: IInsightDefinition, ctx: IEmbeddingCodeContext | undefined): PivotTableNextConfigWithConditionalFormatting;
|
|
7
12
|
export declare function pivotTableNextConfigForInsightViewComponent(): PropWithMeta<PivotTableNextConfig>;
|
|
8
13
|
//# sourceMappingURL=pivotTableNextConfigFromInsight.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pivotTableNextConfigFromInsight.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/pluggableVisualizations/pivotTableNext/pivotTableNextConfigFromInsight.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pivotTableNextConfigFromInsight.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/pluggableVisualizations/pivotTableNext/pivotTableNextConfigFromInsight.ts"],"names":[],"mappings":"AAEA,OAAO,EACH,KAAK,kBAAkB,EACvB,KAAK,SAAS,EAGjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAEH,KAAK,oBAAoB,EACzB,KAAK,6CAA6C,EACrD,MAAM,6BAA6B,CAAC;AAErC,OAAO,EAAE,KAAK,qBAAqB,EAAE,MAAM,gDAAgD,CAAC;AAC5F,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,gDAAgD,CAAC;AA2BlG;;;GAGG;AACH,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,OAAO,GAAG,QAAQ,CAMtE;AAED,wBAAgB,gBAAgB,CAC5B,iBAAiB,EAAE,kBAAkB,EACrC,QAAQ,EAAE,SAAS,GAAG,SAAS,GAChC,OAAO,CAGT;AAED,wBAAgB,+BAA+B,CAC3C,OAAO,EAAE,kBAAkB,EAC3B,GAAG,EAAE,qBAAqB,GAAG,SAAS,GACvC,6CAA6C,CA0B/C;AAED,wBAAgB,2CAA2C,IAAI,YAAY,CAAC,oBAAoB,CAAC,CAKhG"}
|
|
@@ -1,57 +1,61 @@
|
|
|
1
1
|
// (C) 2025-2026 GoodData Corporation
|
|
2
|
-
import { isEmpty } from "lodash-es";
|
|
3
2
|
import { insightProperties, insightVisualizationUrl, } from "@gooddata/sdk-model";
|
|
4
|
-
import { getPaginationFromProperties, getTextWrappingFromProperties, } from "../../../utils/propertiesHelper.js";
|
|
3
|
+
import { getConditionalFormattingFromProperties, getPaginationFromProperties, getTextWrappingFromProperties, isConditionalFormattingEnabled, } from "../../../utils/propertiesHelper.js";
|
|
4
|
+
import { removeUseless } from "../../../utils/removeUseless.js";
|
|
5
5
|
import { createPivotTableNextConfig } from "../pivotTableNext/PluggablePivotTableNext.js";
|
|
6
6
|
const AG_GRID_TOKEN_PLACEHOLDER = {
|
|
7
7
|
agGridToken: "<fill your AG Grid Enterprise license token here>",
|
|
8
8
|
};
|
|
9
|
+
function pivotTableNextConfigMeta(name) {
|
|
10
|
+
return {
|
|
11
|
+
typeImport: {
|
|
12
|
+
importType: "named",
|
|
13
|
+
name,
|
|
14
|
+
package: "@gooddata/sdk-ui-pivot/next",
|
|
15
|
+
},
|
|
16
|
+
cardinality: "scalar",
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Only a config that actually carries conditional formatting references the `@alpha` extended
|
|
21
|
+
* type; every other snippet stays on the `@public` {@link PivotTableNextConfig}.
|
|
22
|
+
*/
|
|
23
|
+
export function pivotTableNextConfigPropMeta(config) {
|
|
24
|
+
const hasConditionalFormatting = typeof config === "object" && config !== null && "conditionalFormatting" in config;
|
|
25
|
+
return pivotTableNextConfigMeta(hasConditionalFormatting ? "PivotTableNextConfigWithConditionalFormatting" : "PivotTableNextConfig");
|
|
26
|
+
}
|
|
9
27
|
export function isPivotTableNext(insightDefinition, settings) {
|
|
10
28
|
const uri = insightVisualizationUrl(insightDefinition);
|
|
11
29
|
return !!settings?.enableNewPivotTable && uri === "local:table";
|
|
12
30
|
}
|
|
13
31
|
export function pivotTableNextConfigFromInsight(insight, ctx) {
|
|
14
32
|
const baseConfig = ctx?.settings && ctx.backend
|
|
15
|
-
? createPivotTableNextConfig({ separators: ctx
|
|
33
|
+
? createPivotTableNextConfig({ separators: ctx.settings.separators }, "none", ctx.settings)
|
|
16
34
|
: {};
|
|
17
|
-
const
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
...separatorsProp,
|
|
36
|
-
...metricsPositionProp,
|
|
37
|
-
...columnHeadersPositionProp,
|
|
38
|
-
...grandTotalsPositionProp,
|
|
39
|
-
...paginationProp,
|
|
40
|
-
columnSizing,
|
|
41
|
-
textWrapping,
|
|
35
|
+
const properties = insightProperties(insight);
|
|
36
|
+
const controls = properties?.["controls"];
|
|
37
|
+
return removeUseless({
|
|
38
|
+
menu: baseConfig.menu,
|
|
39
|
+
separators: baseConfig.separators,
|
|
40
|
+
measureGroupDimension: controls?.measureGroupDimension,
|
|
41
|
+
columnHeadersPosition: controls?.columnHeadersPosition,
|
|
42
|
+
grandTotalsPosition: controls?.grandTotalsPosition,
|
|
43
|
+
pagination: getPaginationFromProperties(properties),
|
|
44
|
+
textWrapping: getTextWrappingFromProperties(properties),
|
|
45
|
+
conditionalFormatting: isConditionalFormattingEnabled(ctx?.settings)
|
|
46
|
+
? getConditionalFormattingFromProperties(properties)
|
|
47
|
+
: undefined,
|
|
48
|
+
columnSizing: {
|
|
49
|
+
columnWidths: controls?.columnWidths,
|
|
50
|
+
defaultWidth: "autoresizeAll",
|
|
51
|
+
growToFit: true,
|
|
52
|
+
},
|
|
42
53
|
...AG_GRID_TOKEN_PLACEHOLDER,
|
|
43
|
-
};
|
|
54
|
+
});
|
|
44
55
|
}
|
|
45
56
|
export function pivotTableNextConfigForInsightViewComponent() {
|
|
46
57
|
return {
|
|
47
58
|
value: AG_GRID_TOKEN_PLACEHOLDER,
|
|
48
|
-
meta:
|
|
49
|
-
cardinality: "scalar",
|
|
50
|
-
typeImport: {
|
|
51
|
-
importType: "named",
|
|
52
|
-
name: "PivotTableNextConfig",
|
|
53
|
-
package: "@gooddata/sdk-ui-pivot/next",
|
|
54
|
-
},
|
|
55
|
-
},
|
|
59
|
+
meta: pivotTableNextConfigMeta("PivotTableNextConfig"),
|
|
56
60
|
};
|
|
57
61
|
}
|
|
@@ -2659,10 +2659,18 @@ export declare const en_US: {
|
|
|
2659
2659
|
text: string;
|
|
2660
2660
|
crowdinContext: string;
|
|
2661
2661
|
};
|
|
2662
|
+
"properties.conditionalFormatting.dialog.error.wrapper": {
|
|
2663
|
+
text: string;
|
|
2664
|
+
crowdinContext: string;
|
|
2665
|
+
};
|
|
2662
2666
|
"properties.conditionalFormatting.dialog.error.rangeOrder": {
|
|
2663
2667
|
text: string;
|
|
2664
2668
|
crowdinContext: string;
|
|
2665
2669
|
};
|
|
2670
|
+
"properties.conditionalFormatting.dialog.error.valueEmpty": {
|
|
2671
|
+
text: string;
|
|
2672
|
+
crowdinContext: string;
|
|
2673
|
+
};
|
|
2666
2674
|
"properties.conditionalFormatting.dialog.selectPeriod": {
|
|
2667
2675
|
text: string;
|
|
2668
2676
|
crowdinContext: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en-US.localization-bundle.d.ts","sourceRoot":"","sources":["../../../src/internal/translations/en-US.localization-bundle.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK
|
|
1
|
+
{"version":3,"file":"en-US.localization-bundle.d.ts","sourceRoot":"","sources":["../../../src/internal/translations/en-US.localization-bundle.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAytFjB,CAAC"}
|