@gooddata/sdk-ui-ext 11.52.0 → 11.53.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.
Files changed (39) hide show
  1. package/NOTICE +59 -9
  2. package/esm/index.d.ts +3 -0
  3. package/esm/index.d.ts.map +1 -1
  4. package/esm/index.js +2 -0
  5. package/esm/insightView/InsightRenderer.d.ts +6 -3
  6. package/esm/insightView/InsightRenderer.d.ts.map +1 -1
  7. package/esm/insightView/InsightRenderer.js +142 -165
  8. package/esm/internal/components/configurationControls/conditionalFormatting/ConditionEditor.d.ts +3 -1
  9. package/esm/internal/components/configurationControls/conditionalFormatting/ConditionEditor.d.ts.map +1 -1
  10. package/esm/internal/components/configurationControls/conditionalFormatting/ConditionEditor.js +20 -6
  11. package/esm/internal/components/configurationControls/conditionalFormatting/ConditionalFormattingDialog.d.ts +11 -1
  12. package/esm/internal/components/configurationControls/conditionalFormatting/ConditionalFormattingDialog.d.ts.map +1 -1
  13. package/esm/internal/components/configurationControls/conditionalFormatting/ConditionalFormattingDialog.js +25 -10
  14. package/esm/internal/components/configurationControls/conditionalFormatting/ConditionalFormattingSection.d.ts.map +1 -1
  15. package/esm/internal/components/configurationControls/conditionalFormatting/ConditionalFormattingSection.js +64 -5
  16. package/esm/internal/components/configurationControls/conditionalFormatting/ReorderList.d.ts +3 -1
  17. package/esm/internal/components/configurationControls/conditionalFormatting/ReorderList.d.ts.map +1 -1
  18. package/esm/internal/components/configurationControls/conditionalFormatting/ReorderList.js +2 -2
  19. package/esm/internal/components/configurationControls/conditionalFormatting/conditionalFormattingModel.d.ts +46 -8
  20. package/esm/internal/components/configurationControls/conditionalFormatting/conditionalFormattingModel.d.ts.map +1 -1
  21. package/esm/internal/components/configurationControls/conditionalFormatting/conditionalFormattingModel.js +94 -16
  22. package/esm/internal/components/configurationControls/conditionalFormatting/useCfDateFilterOptions.d.ts +2 -0
  23. package/esm/internal/components/configurationControls/conditionalFormatting/useCfDateFilterOptions.d.ts.map +1 -1
  24. package/esm/internal/components/configurationControls/conditionalFormatting/useCfDateFilterOptions.js +2 -0
  25. package/esm/internal/components/pluggableVisualizations/pivotTableNext/PluggablePivotTableNext.d.ts.map +1 -1
  26. package/esm/internal/components/pluggableVisualizations/pivotTableNext/PluggablePivotTableNext.js +8 -2
  27. package/esm/internal/translations/en-US.localization-bundle.d.ts +12 -0
  28. package/esm/internal/translations/en-US.localization-bundle.d.ts.map +1 -1
  29. package/esm/internal/translations/en-US.localization-bundle.js +12 -0
  30. package/esm/locales.d.ts +9 -0
  31. package/esm/locales.d.ts.map +1 -1
  32. package/esm/locales.js +3 -0
  33. package/esm/sdk-ui-ext.d.ts +86 -0
  34. package/package.json +21 -21
  35. package/styles/css/main.css +59 -0
  36. package/styles/css/main.css.map +1 -1
  37. package/styles/internal/css/conditional_formatting.css +59 -0
  38. package/styles/internal/css/conditional_formatting.css.map +1 -1
  39. package/styles/internal/scss/conditional_formatting.scss +78 -0
@@ -9,7 +9,7 @@ import { ColorDropdown } from "../colors/colorDropdown/ColorDropdown.js";
9
9
  import { CfDateValueDropdown } from "./CfDateValueDropdown.js";
10
10
  import { CfSelect } from "./CfSelect.js";
11
11
  import { CF_COLOR_PALETTE, colorToHex, hexToColor } from "./conditionalFormattingColors.js";
12
- import { displayToRawNumber, literalRaw, literalText, operatorIcon, operatorsForTarget, rangeRaw, rawToDisplayNumber, validateCondition, valueEditorKind, valueForOperator, } from "./conditionalFormattingModel.js";
12
+ import { displayToRawNumber, literalRaw, literalText, operatorIcon, operatorsForTarget, rangeRaw, rawToDisplayNumber, rawValueText, validateCondition, valueEditorKind, valueForOperator, valueMatchesEditorKind, } from "./conditionalFormattingModel.js";
13
13
  // InputPure's own contract for the same error state.
14
14
  const inputErrorProps = ({ hasError, errorId, }) => hasError ? { hasError, accessibilityConfig: { ariaDescribedBy: errorId, ariaInvalid: true } } : {};
15
15
  function CfMeasureValueInput({ raw, isPercent, separators, placeholder, onChangeRaw, ...field }) {
@@ -58,7 +58,7 @@ function CfFieldError({ id, error }) {
58
58
  message: intl.formatMessage(FIELD_ERROR_MESSAGE[error]),
59
59
  }) }));
60
60
  }
61
- function ConditionValueInput({ condition, editorKind, kind, isPercent, separators, suggestions, date, dateFilterOptions, dateSettings, onChange, }) {
61
+ function ConditionValueInput({ condition, editorKind, kind, isPercent, separators, suggestions, date, dateFilterOptions, dateSettings, readOnly, onChange, }) {
62
62
  const intl = useIntl();
63
63
  const errorId = useId();
64
64
  // Empty is only an error once the field has been visited, so authoring a rule top-down never reddens
@@ -77,6 +77,12 @@ function ConditionValueInput({ condition, editorKind, kind, isPercent, separator
77
77
  return { hasError, errorId: hasError ? errorId : undefined, onVisit: markVisited(field) };
78
78
  };
79
79
  const error = invalid ?? emptyIn("value") ?? emptyIn("from") ?? emptyIn("to");
80
+ // A read-only rule may pair a value shape its editor can't represent (e.g. a semantic-layer
81
+ // condition the pivot editor never authors) — fall back to raw text instead of a dead-ended
82
+ // control. Placed after every hook call above so it never changes the hooks called per render.
83
+ if (readOnly && !valueMatchesEditorKind(editorKind, condition.value)) {
84
+ return _jsx("span", { className: "gd-cf-condition__raw-value", children: rawValueText(condition.value) });
85
+ }
80
86
  const renderControl = () => {
81
87
  switch (editorKind) {
82
88
  case "none":
@@ -126,11 +132,19 @@ function FormatEditor({ format, onChange }) {
126
132
  ] })
127
133
  ] })) }));
128
134
  }
129
- export function ConditionEditor({ condition, kind, isPercent, separators, suggestions, date, dateFilterOptions, dateSettings, removable, slot, onChange, onRemove, }) {
135
+ export function ConditionEditor({ condition, kind, isPercent, separators, suggestions, date, dateFilterOptions, dateSettings, removable, slot, readOnly = false, onChange, onRemove, }) {
130
136
  const intl = useIntl();
131
137
  const isDate = date !== undefined;
138
+ const curatedOperators = operatorsForTarget(kind, isDate);
139
+ // A read-only rule may carry an operator the editor doesn't curate for this target (e.g. a
140
+ // semantic-layer rule the pivot editor can't author); keep it selectable so its real label shows
141
+ // instead of leaving the picker blank. Gated on readOnly: sanitizeRuleForEditing normalizes the
142
+ // operator on the editable path, so this must never offer an uncurated choice a user could pick.
143
+ const operators = readOnly && !curatedOperators.includes(condition.operator)
144
+ ? [...curatedOperators, condition.operator]
145
+ : curatedOperators;
132
146
  // Date operators render label-only (per design), so no icon lookup on that path.
133
- const operatorItems = operatorsForTarget(kind, isDate).map((operator) => ({
147
+ const operatorItems = operators.map((operator) => ({
134
148
  value: operator,
135
149
  title: intl.formatMessage((isDate ? conditionalFormattingDateOperatorMessages[operator] : undefined) ??
136
150
  conditionalFormattingOperatorMessages[operator]),
@@ -143,13 +157,13 @@ export function ConditionEditor({ condition, kind, isPercent, separators, sugges
143
157
  ...(condition.format.backgroundColor ? { backgroundColor: condition.format.backgroundColor } : {}),
144
158
  };
145
159
  return (_jsxs("div", { className: cx("gd-cf-condition", slot.className), ...slot.rootProps, children: [slot.handle, _jsxs("div", { className: "gd-cf-condition__header", children: [
146
- _jsx("span", { className: "gd-cf-condition__title", children: intl.formatMessage(conditionalFormattingMessages.dialogCondition) }), removable ? (_jsx(Button, { className: "gd-button-link gd-button-icon-only gd-icon-cross", accessibilityConfig: {
160
+ _jsx("span", { className: "gd-cf-condition__title", children: intl.formatMessage(conditionalFormattingMessages.dialogCondition) }), removable ? (_jsx(Button, { className: "gd-button-link gd-button-icon-only gd-icon-cross gd-cf-condition__delete", accessibilityConfig: {
147
161
  ariaLabel: intl.formatMessage(conditionalFormattingMessages.dialogRemoveCondition),
148
162
  }, onClick: onRemove })) : null] }), _jsx(CfSelect, { value: condition.operator, items: operatorItems, onSelect: (operator) => onChange({
149
163
  ...condition,
150
164
  operator,
151
165
  value: valueForOperator(operator, condition.value, isDate),
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: [
166
+ }) }), _jsx(ConditionValueInput, { condition: condition, editorKind: editorKind, kind: kind, isPercent: isPercent, separators: separators, suggestions: suggestions, date: date, dateFilterOptions: dateFilterOptions, dateSettings: dateSettings, readOnly: readOnly, onChange: onChange }, editorKind), _jsxs("div", { className: "gd-cf-condition__format-row", children: [
153
167
  _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 })
154
168
  ] })
155
169
  ] }));
@@ -2,6 +2,9 @@ import { type ISeparators } from "@gooddata/sdk-model";
2
2
  import { type IDateFilterOptionsByType } from "@gooddata/sdk-ui-filters";
3
3
  import { type IConditionalFormattingRule } from "@gooddata/sdk-ui-pivot/next";
4
4
  import { type ICfDateSettings, type ITargetOption } from "./conditionalFormattingModel.js";
5
+ /**
6
+ * @internal
7
+ */
5
8
  export interface IConditionalFormattingDialogProps {
6
9
  rule: IConditionalFormattingRule;
7
10
  isNew: boolean;
@@ -14,8 +17,15 @@ export interface IConditionalFormattingDialogProps {
14
17
  dateSettings?: ICfDateSettings;
15
18
  /** CSS selector of a small, stable element the popover anchors to. */
16
19
  alignTo: string;
20
+ /** Renders the dialog non-interactively: no target picker, no editing, no Save button. */
21
+ readOnly?: boolean;
22
+ /** Renders a static "icon + title" header for the rule's target instead of the picker dropdown. */
23
+ fixedTarget?: boolean;
17
24
  onSave: (rule: IConditionalFormattingRule) => void;
18
25
  onClose: () => void;
19
26
  }
20
- export declare function ConditionalFormattingDialog({ rule: initialRule, isNew, targetOptions, separators, dateFilterOptions, dateSettings, alignTo, onSave, onClose }: IConditionalFormattingDialogProps): import("react/jsx-runtime").JSX.Element;
27
+ /**
28
+ * @internal
29
+ */
30
+ export declare function ConditionalFormattingDialog({ rule: initialRule, isNew, targetOptions, separators, dateFilterOptions, dateSettings, alignTo, readOnly, fixedTarget, onSave, onClose }: IConditionalFormattingDialogProps): import("react/jsx-runtime").JSX.Element;
21
31
  //# sourceMappingURL=ConditionalFormattingDialog.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ConditionalFormattingDialog.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/ConditionalFormattingDialog.tsx"],"names":[],"mappings":"AAOA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEzE,OAAO,EAEH,KAAK,0BAA0B,EAClC,MAAM,6BAA6B,CAAC;AAKrC,OAAO,EACH,KAAK,eAAe,EACpB,KAAK,aAAa,EAQrB,MAAM,iCAAiC,CAAC;AAWzC,MAAM,WAAW,iCAAiC;IAC9C,IAAI,EAAE,0BAA0B,CAAC;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,aAAa,EAAE,CAAC;IAC/B,uFAAuF;IACvF,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,mGAAmG;IACnG,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAC7C,uFAAuF;IACvF,YAAY,CAAC,EAAE,eAAe,CAAC;IAC/B,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACnD,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,wBAAgB,2BAA2B,CAAC,EACxC,IAAI,EAAE,WAAW,EACjB,KAAK,EACL,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,OAAO,EACP,MAAM,EACN,OAAO,EACV,EAAE,iCAAiC,2CAgInC"}
1
+ {"version":3,"file":"ConditionalFormattingDialog.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/ConditionalFormattingDialog.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEzE,OAAO,EAEH,KAAK,0BAA0B,EAClC,MAAM,6BAA6B,CAAC;AAKrC,OAAO,EACH,KAAK,eAAe,EACpB,KAAK,aAAa,EAQrB,MAAM,iCAAiC,CAAC;AAWzC;;GAEG;AACH,MAAM,WAAW,iCAAiC;IAC9C,IAAI,EAAE,0BAA0B,CAAC;IACjC,KAAK,EAAE,OAAO,CAAC;IACf,aAAa,EAAE,aAAa,EAAE,CAAC;IAC/B,uFAAuF;IACvF,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,mGAAmG;IACnG,iBAAiB,CAAC,EAAE,wBAAwB,CAAC;IAC7C,uFAAuF;IACvF,YAAY,CAAC,EAAE,eAAe,CAAC;IAC/B,sEAAsE;IACtE,OAAO,EAAE,MAAM,CAAC;IAChB,0FAA0F;IAC1F,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mGAAmG;IACnG,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,MAAM,EAAE,CAAC,IAAI,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACnD,OAAO,EAAE,MAAM,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CAAC,EACxC,IAAI,EAAE,WAAW,EACjB,KAAK,EACL,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,OAAO,EACP,QAAgB,EAChB,WAAmB,EACnB,MAAM,EACN,OAAO,EACV,EAAE,iCAAiC,2CAmKnC"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2026 GoodData Corporation
3
3
  import { useState } from "react";
4
+ import cx from "classnames";
4
5
  import { isEqual } from "lodash-es";
5
6
  import { useIntl } from "react-intl";
6
7
  import { Button, Overlay } from "@gooddata/sdk-ui-kit";
@@ -15,9 +16,14 @@ const POPOVER_ALIGN_POINTS = [
15
16
  { align: "cl cr", offset: { x: -5, y: 0 } },
16
17
  { align: "cr cl", offset: { x: 5, y: 0 } },
17
18
  ];
18
- export function ConditionalFormattingDialog({ rule: initialRule, isNew, targetOptions, separators, dateFilterOptions, dateSettings, alignTo, onSave, onClose, }) {
19
+ /**
20
+ * @internal
21
+ */
22
+ export function ConditionalFormattingDialog({ rule: initialRule, isNew, targetOptions, separators, dateFilterOptions, dateSettings, alignTo, readOnly = false, fixedTarget = false, onSave, onClose, }) {
19
23
  const intl = useIntl();
20
- const initial = sanitizeRuleForEditing(initialRule, isDateTarget(findTargetOption(targetOptions, initialRule.target)));
24
+ const initial = readOnly
25
+ ? initialRule
26
+ : sanitizeRuleForEditing(initialRule, isDateTarget(findTargetOption(targetOptions, initialRule.target)));
21
27
  const [rule, setRule] = useState(initial);
22
28
  const updateCondition = (id, next) => setRule((current) => ({
23
29
  ...current,
@@ -43,24 +49,33 @@ export function ConditionalFormattingDialog({ rule: initialRule, isNew, targetOp
43
49
  setRule((current) => ruleWithTarget(current, option, findTargetOption(targetOptions, current.target)));
44
50
  };
45
51
  const selectedTarget = findTargetOption(targetOptions, rule.target);
52
+ const singleTarget = fixedTarget ? selectedTarget : undefined;
46
53
  const isPercent = selectedTarget?.isPercent ?? false;
47
54
  const suggestions = selectedTarget?.elements ?? [];
48
55
  const complete = isRuleComplete(rule, selectedTarget?.date);
49
56
  const isDirty = isNew || !isEqual(rule, initial);
50
- const title = intl.formatMessage(isNew ? conditionalFormattingMessages.dialogAddTitle : conditionalFormattingMessages.dialogEditTitle);
57
+ const title = intl.formatMessage(readOnly
58
+ ? conditionalFormattingMessages.dialogViewTitle
59
+ : isNew
60
+ ? conditionalFormattingMessages.dialogAddTitle
61
+ : conditionalFormattingMessages.dialogEditTitle);
51
62
  return (_jsx(Overlay, { alignTo: alignTo, alignPoints: POPOVER_ALIGN_POINTS, closeOnParentScroll: true, closeOnMouseDrag: true, onClose: onClose, children: _jsxs("div", { className: "gd-cf-dialog", "aria-label": title, children: [
52
63
  _jsxs("div", { className: "gd-cf-dialog__header", children: [
53
64
  _jsx("h3", { className: "gd-cf-dialog__title", children: title }), _jsx(Button, { className: "gd-button-link gd-button-icon-only gd-icon-cross", accessibilityConfig: {
54
65
  ariaLabel: intl.formatMessage(conditionalFormattingMessages.dialogCancel),
55
66
  }, onClick: onClose })
56
67
  ] }), _jsxs("div", { className: "gd-cf-dialog__body", children: [
57
- _jsx("span", { className: "gd-cf-dialog__label", children: intl.formatMessage(conditionalFormattingMessages.dialogTarget) }), _jsx(CfSelect, { value: selectedTarget?.value, items: targetOptions.map((option) => ({
58
- value: option.value,
59
- title: option.title,
60
- icon: targetIcon(option.target.kind, isDateTarget(option)),
61
- })), onSelect: changeTarget, placeholder: intl.formatMessage(conditionalFormattingMessages.dialogSelectTarget) }), _jsx(ReorderList, { items: rule.conditions, getKey: (condition) => condition.id, onReorder: reorderConditions, renderItem: (condition, slot) => (_jsx(ConditionEditor, { condition: condition, kind: rule.target.kind, isPercent: isPercent, separators: separators, suggestions: suggestions, date: selectedTarget?.date, dateFilterOptions: dateFilterOptions, dateSettings: dateSettings, removable: rule.conditions.length > 1, slot: slot, onChange: (next) => updateCondition(condition.id, next), onRemove: () => removeCondition(condition.id) })) }), _jsx(Button, { className: "gd-button-secondary gd-cf-dialog__add-condition", iconLeft: "gd-icon-plus", value: intl.formatMessage(conditionalFormattingMessages.dialogAddCondition), onClick: addCondition })
68
+ _jsx("span", { className: "gd-cf-dialog__label", children: intl.formatMessage(conditionalFormattingMessages.dialogTarget) }), singleTarget ? (_jsxs("div", { className: "gd-cf-dialog__static-target", children: [
69
+ _jsx("span", { className: cx("gd-cf-type-icon", targetIcon(singleTarget.target.kind, isDateTarget(singleTarget))), "aria-hidden": "true" }), _jsx("span", { className: "gd-cf-dialog__static-target-title", children: singleTarget.title })
70
+ ] })) : (_jsx("fieldset", { className: "gd-cf-dialog__target-picker", disabled: readOnly, children: _jsx(CfSelect, { value: selectedTarget?.value, items: targetOptions.map((option) => ({
71
+ value: option.value,
72
+ title: option.title,
73
+ icon: targetIcon(option.target.kind, isDateTarget(option)),
74
+ })), onSelect: changeTarget, placeholder: intl.formatMessage(conditionalFormattingMessages.dialogSelectTarget) }) })), _jsxs("fieldset", { disabled: readOnly, className: cx("gd-cf-dialog__editable", {
75
+ "gd-cf-dialog__editable--readonly": readOnly,
76
+ }), children: [_jsx(ReorderList, { items: rule.conditions, getKey: (condition) => condition.id, onReorder: reorderConditions, disabled: readOnly, renderItem: (condition, slot) => (_jsx(ConditionEditor, { condition: condition, kind: rule.target.kind, isPercent: isPercent, separators: separators, suggestions: suggestions, date: selectedTarget?.date, dateFilterOptions: dateFilterOptions, dateSettings: dateSettings, removable: rule.conditions.length > 1, slot: slot, readOnly: readOnly, onChange: (next) => updateCondition(condition.id, next), onRemove: () => removeCondition(condition.id) })) }), _jsx(Button, { className: "gd-button-secondary gd-cf-dialog__add-condition", iconLeft: "gd-icon-plus", value: intl.formatMessage(conditionalFormattingMessages.dialogAddCondition), onClick: addCondition })
77
+ ] })
62
78
  ] }), _jsxs("div", { className: "gd-cf-dialog__footer", children: [
63
- _jsx(Button, { className: "gd-button-secondary", value: intl.formatMessage(conditionalFormattingMessages.dialogCancel), onClick: onClose }), _jsx(Button, { className: "gd-button-action", value: intl.formatMessage(conditionalFormattingMessages.dialogSave), disabled: !complete || !isDirty, onClick: () => onSave(rule) })
64
- ] })
79
+ _jsx(Button, { className: "gd-button-secondary", value: intl.formatMessage(conditionalFormattingMessages.dialogCancel), onClick: onClose }), readOnly ? null : (_jsx(Button, { className: "gd-button-action", value: intl.formatMessage(conditionalFormattingMessages.dialogSave), disabled: !complete || !isDirty, onClick: () => onSave(rule) }))] })
65
80
  ] }) }));
66
81
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ConditionalFormattingSection.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/ConditionalFormattingSection.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAKhF,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAIrF,OAAO,EACH,KAAK,eAAe,EACpB,KAAK,aAAa,EASrB,MAAM,iCAAiC,CAAC;AAWzC,MAAM,WAAW,kCAAkC;IAC/C,UAAU,CAAC,EAAE,wBAAwB,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,yFAAyF;IACzF,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,eAAe,CAAC;IAC/B,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC;AA0DD,wBAAgB,4BAA4B,CAAC,EACzC,UAAU,EACV,cAAc,EACd,OAAO,EACP,UAAU,EACV,OAAO,EACP,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,EACT,QAAQ,EACX,EAAE,kCAAkC,2CA4HpC"}
1
+ {"version":3,"file":"ConditionalFormattingSection.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/ConditionalFormattingSection.tsx"],"names":[],"mappings":"AAQA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EACH,KAAK,kBAAkB,EAEvB,KAAK,WAAW,EACnB,MAAM,qBAAqB,CAAC;AAK7B,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAIrF,OAAO,EACH,KAAK,eAAe,EACpB,KAAK,aAAa,EAWrB,MAAM,iCAAiC,CAAC;AAYzC,MAAM,WAAW,kCAAkC;IAC/C,UAAU,CAAC,EAAE,wBAAwB,CAAC;IACtC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,UAAU,CAAC,EAAE,aAAa,CAAC;IAC3B,yFAAyF;IACzF,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,eAAe,CAAC;IAC/B,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;CACtC;AA8GD,wBAAgB,4BAA4B,CAAC,EACzC,UAAU,EACV,cAAc,EACd,OAAO,EACP,UAAU,EACV,OAAO,EACP,SAAS,EACT,YAAY,EACZ,UAAU,EACV,SAAS,EACT,QAAQ,EACX,EAAE,kCAAkC,2CA+KpC"}
@@ -8,7 +8,7 @@ import { Button, UiIconButton } from "@gooddata/sdk-ui-kit";
8
8
  import { conditionalFormattingMessages } from "../../../../locales.js";
9
9
  import { ConfigSection } from "../ConfigSection.js";
10
10
  import { ConditionalFormattingDialog } from "./ConditionalFormattingDialog.js";
11
- import { buildTargetOptions, findTargetOption, isDateTarget, isRuleComplete, newRule, targetIcon, targetLocalId, } from "./conditionalFormattingModel.js";
11
+ import { buildTargetOptions, findTargetOption, isCustomTarget, isDateTarget, isRuleComplete, newRule, semanticRuleFor, targetIcon, targetLocalId, } from "./conditionalFormattingModel.js";
12
12
  import { ReorderList } from "./ReorderList.js";
13
13
  import { useCfDateFilterOptions } from "./useCfDateFilterOptions.js";
14
14
  const SECTION_ID = "conditionalFormatting_section";
@@ -18,6 +18,38 @@ function RuleChip({ rule, option, invalid, editable, labels, slot, onEdit, onDel
18
18
  _jsx("span", { className: `gd-cf-type-icon ${targetIcon(rule.target.kind, isDateTarget(option))}`, "aria-hidden": "true" }), _jsx("span", { className: "gd-cf-rule__title", children: option ? option.title : targetLocalId(rule.target) }), invalid ? (_jsx("span", { className: "gd-cf-rule__invalid", children: option ? labels.invalidValue : labels.invalid })) : null] }), _jsx("span", { className: "gd-cf-rule__delete", children: _jsx(UiIconButton, { icon: "trash", size: "small", variant: "tertiary", isDesctructive: true, label: labels.delete, onClick: onDelete }) })
19
19
  ] }));
20
20
  }
21
+ // A held-open semantic dialog is a snapshot from when "View" was clicked — re-derive it against the
22
+ // current semantic payload every render so it tracks edits, and disappears (rather than showing stale
23
+ // or unrelated rules) once loading clears `targetData.semantic`, the target stops being Inherited (its
24
+ // row left `semanticRows` because it became Custom), or its semantic rule itself is no longer present.
25
+ function resolveActiveDialog(dialog, semanticMap, config) {
26
+ if (dialog?.kind !== "semantic") {
27
+ return dialog;
28
+ }
29
+ if (isCustomTarget(config, dialog.option.target)) {
30
+ return null;
31
+ }
32
+ const current = semanticMap[targetLocalId(dialog.option.target)];
33
+ return current
34
+ ? { kind: "semantic", option: dialog.option, rule: semanticRuleFor(dialog.option, current) }
35
+ : null;
36
+ }
37
+ // `activeDialog.rule.id` alone is stable across a semantic-rule content change (it's target-based, not
38
+ // content-based, per semanticRuleFor) — ConditionalFormattingDialog seeds its local draft from `rule` via
39
+ // useState and won't re-sync on a prop change, so without remounting on content change too, a rule that
40
+ // changes while the (read-only) dialog is open would keep showing what it looked like when opened.
41
+ function dialogKey(dialog) {
42
+ return dialog.kind === "semantic"
43
+ ? `${dialog.rule.id}:${JSON.stringify(dialog.rule.conditions)}`
44
+ : dialog.rule.id;
45
+ }
46
+ // Read-only: no drag handle, no delete — nothing on the row is editable here, only the View
47
+ // button opens the (readOnly) dialog. Turning it off/customizing it is PR-6, not this one.
48
+ function SemanticRuleRow({ option, viewLabel, onView }) {
49
+ return (_jsxs("div", { className: "gd-cf-rule gd-cf-rule--semantic", children: [
50
+ _jsx("span", { className: `gd-cf-type-icon ${targetIcon(option.target.kind, isDateTarget(option))}`, "aria-hidden": "true" }), _jsx("span", { className: "gd-cf-rule__title", children: option.title }), _jsx(Button, { className: "gd-button-link gd-cf-rule__view", value: viewLabel, onClick: onView })
51
+ ] }));
52
+ }
21
53
  export function ConditionalFormattingSection({ properties, propertiesMeta, insight, targetData, backend, workspace, dateSettings, separators, isLoading, pushData, }) {
22
54
  const intl = useIntl();
23
55
  const [dialog, setDialog] = useState(null);
@@ -27,6 +59,22 @@ export function ConditionalFormattingSection({ properties, propertiesMeta, insig
27
59
  const targetOptions = insight ? buildTargetOptions(insight, targetData) : [];
28
60
  // Only date pickers consume the catalog — skip the backend query when no target is date-eligible.
29
61
  const dateFilterOptions = useCfDateFilterOptions(backend, workspace, targetOptions.some(isDateTarget));
62
+ // Targets inheriting a semantic-layer rule, minus any already Custom (an authored rule or a
63
+ // customTargets entry). NOT gated on the toggle above: the engine's `enabled` only ever
64
+ // deactivates the insight's OWN authored rules — an untouched (Inherited) target keeps
65
+ // painting regardless, so hiding it here would desync the panel from what's on screen.
66
+ const semanticMap = targetData?.semantic ?? {};
67
+ const semanticRows = targetOptions.flatMap((option) => {
68
+ const rule = semanticMap[targetLocalId(option.target)];
69
+ return !rule || isCustomTarget(config, option.target) ? [] : [{ option, semantic: rule }];
70
+ });
71
+ const activeDialog = resolveActiveDialog(dialog, semanticMap, config);
72
+ // `resolveActiveDialog` only hides an invalidated semantic dialog from render — without also
73
+ // clearing the underlying state here, a later data view that happens to carry a rule for the same
74
+ // (possibly stale) target would silently reopen it, with no new View click.
75
+ if (dialog?.kind === "semantic" && activeDialog === null) {
76
+ setDialog(null);
77
+ }
30
78
  // Completeness and authoring both need execution-resolved date metadata; before the first data view
31
79
  // it's unknown — don't flash a false "Invalid" badge, don't author a plain-text rule on a date attr.
32
80
  const targetDataReady = targetData?.dates !== undefined;
@@ -54,13 +102,24 @@ export function ConditionalFormattingSection({ properties, propertiesMeta, insig
54
102
  edit: intl.formatMessage(conditionalFormattingMessages.ruleEdit),
55
103
  delete: intl.formatMessage(conditionalFormattingMessages.ruleDelete),
56
104
  };
105
+ const viewLabel = intl.formatMessage(conditionalFormattingMessages.ruleView);
57
106
  return (_jsxs(ConfigSection, { id: SECTION_ID, className: "gd-cf-section", title: conditionalFormattingMessages.sectionTitle.id, propertiesMeta: propertiesMeta, properties: properties, pushData: pushData, canBeToggled: true, toggledOn: enabled, toggleDisabled: isLoading, onToggle: (checked) => commit(rules, checked), children: [
58
107
  _jsx("span", { className: "s-cf-popover-anchor gd-cf-section__anchor" }), _jsxs("div", { className: "gd-cf-section__subcategory", children: [
59
- _jsx("span", { className: "gd-cf-section__rules-label", children: intl.formatMessage(conditionalFormattingMessages.rulesLabel) }), _jsx("span", { className: "gd-cf-section__divider" }), _jsx(Button, { className: "gd-button-link gd-cf-section__add", iconLeft: "gd-icon-plus", value: intl.formatMessage(conditionalFormattingMessages.addRule), disabled: !canAddRule, onClick: () => setDialog({ rule: newRule(targetOptions[0]), isNew: true }) })
60
- ] }), rules.length === 0 ? (_jsx("div", { className: "gd-cf-section__empty", children: intl.formatMessage(conditionalFormattingMessages.empty) })) : (_jsx("div", { className: "gd-cf-section__rules", children: _jsx(ReorderList, { items: rules, getKey: (rule) => rule.id, onReorder: (next) => commit(next, enabled), renderItem: (rule, slot) => {
108
+ _jsx("span", { className: "gd-cf-section__rules-label", children: intl.formatMessage(conditionalFormattingMessages.rulesLabel) }), _jsx("span", { className: "gd-cf-section__divider" }), _jsx(Button, { className: "gd-button-link gd-cf-section__add", iconLeft: "gd-icon-plus", value: intl.formatMessage(conditionalFormattingMessages.addRule), disabled: !canAddRule, onClick: () => setDialog({ kind: "custom", rule: newRule(targetOptions[0]), isNew: true }) })
109
+ ] }), rules.length === 0 ? (
110
+ // The empty-state hint would contradict an inherited row rendered just below it.
111
+ semanticRows.length === 0 ? (_jsx("div", { className: "gd-cf-section__empty", children: intl.formatMessage(conditionalFormattingMessages.empty) })) : null) : (_jsx("div", { className: "gd-cf-section__rules", children: _jsx(ReorderList, { items: rules, getKey: (rule) => rule.id, onReorder: (next) => commit(next, enabled), renderItem: (rule, slot) => {
61
112
  const option = findTargetOption(targetOptions, rule.target);
62
113
  // A missing target flags immediately; value validation waits for date metadata.
63
114
  const invalid = !option || (targetDataReady && !isRuleComplete(rule, option.date));
64
- return (_jsx(RuleChip, { rule: rule, option: option, invalid: invalid, editable: targetDataReady, labels: chipLabels, slot: slot, onEdit: () => setDialog({ rule, isNew: false }), onDelete: () => deleteRule(rule.id) }));
65
- } }) })), dialog ? (_jsx(ConditionalFormattingDialog, { rule: dialog.rule, isNew: dialog.isNew, targetOptions: targetOptions, separators: separators, dateFilterOptions: dateFilterOptions, dateSettings: dateSettings, alignTo: ".s-cf-popover-anchor", onSave: (rule) => saveRule(rule, dialog.isNew), onClose: () => setDialog(null) }, dialog.rule.id)) : null] }));
115
+ return (_jsx(RuleChip, { rule: rule, option: option, invalid: invalid, editable: targetDataReady, labels: chipLabels, slot: slot, onEdit: () => setDialog({ kind: "custom", rule, isNew: false }), onDelete: () => deleteRule(rule.id) }));
116
+ } }) })), semanticRows.length > 0 ? (_jsxs("div", { className: "gd-cf-section__semantic", children: [
117
+ _jsxs("div", { className: "gd-cf-section__subcategory", children: [
118
+ _jsx("span", { className: "gd-cf-section__rules-label", children: intl.formatMessage(conditionalFormattingMessages.semanticLabel) }), _jsx("span", { className: "gd-cf-section__divider" })
119
+ ] }), _jsx("div", { className: "gd-cf-section__rules", children: semanticRows.map(({ option, semantic }) => (_jsx(SemanticRuleRow, { option: option, viewLabel: viewLabel, onView: () => setDialog({
120
+ kind: "semantic",
121
+ rule: semanticRuleFor(option, semantic),
122
+ option,
123
+ }) }, option.value))) })
124
+ ] })) : null, activeDialog ? (_jsx(ConditionalFormattingDialog, { rule: activeDialog.rule, isNew: activeDialog.kind === "custom" && activeDialog.isNew, readOnly: activeDialog.kind === "semantic", fixedTarget: activeDialog.kind === "semantic", targetOptions: targetOptions, separators: separators, dateFilterOptions: dateFilterOptions, dateSettings: dateSettings, alignTo: ".s-cf-popover-anchor", onSave: (rule) => activeDialog.kind === "custom" && saveRule(rule, activeDialog.isNew), onClose: () => setDialog(null) }, dialogKey(activeDialog))) : null] }));
66
125
  }
@@ -14,12 +14,14 @@ export interface IReorderListProps<T> {
14
14
  /** Receives the full reordered array. */
15
15
  onReorder: (items: T[]) => void;
16
16
  renderItem: (item: T, slot: IReorderSlot, index: number) => ReactNode;
17
+ /** Suppresses drag-to-reorder regardless of item count (e.g. a read-only view of the list). */
18
+ disabled?: boolean;
17
19
  }
18
20
  /**
19
21
  * Drag-to-reorder for a small vertical list, on native HTML5 DnD (no dependency, no provider).
20
22
  * The render prop keeps the consumer's own row markup; the whole row drags (the grip is a hover
21
23
  * affordance). Pointer-only — no keyboard reorder yet.
22
24
  */
23
- export declare function ReorderList<T>({ items, getKey, onReorder, renderItem }: IReorderListProps<T>): import("react/jsx-runtime").JSX.Element;
25
+ export declare function ReorderList<T>({ items, getKey, onReorder, renderItem, disabled }: IReorderListProps<T>): import("react/jsx-runtime").JSX.Element;
24
26
  export {};
25
27
  //# sourceMappingURL=ReorderList.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReorderList.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/ReorderList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,cAAc,EAAE,KAAK,SAAS,EAAoB,MAAM,OAAO,CAAC;AAMxF,KAAK,iBAAiB,GAAG,IAAI,CACzB,cAAc,CAAC,WAAW,CAAC,EACzB,WAAW,GACX,eAAe,GACf,aAAa,GACb,aAAa,GACb,YAAY,GACZ,aAAa,GACb,QAAQ,GACR,WAAW,CAChB,CAAC;AAEF,MAAM,WAAW,YAAY;IACzB,oFAAoF;IACpF,MAAM,EAAE,SAAS,CAAC;IAClB,wCAAwC;IACxC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAChC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAC5B,yCAAyC;IACzC,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAChC,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;CACzE;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC,2CA6F5F"}
1
+ {"version":3,"file":"ReorderList.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/ReorderList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAY,KAAK,cAAc,EAAE,KAAK,SAAS,EAAoB,MAAM,OAAO,CAAC;AAMxF,KAAK,iBAAiB,GAAG,IAAI,CACzB,cAAc,CAAC,WAAW,CAAC,EACzB,WAAW,GACX,eAAe,GACf,aAAa,GACb,aAAa,GACb,YAAY,GACZ,aAAa,GACb,QAAQ,GACR,WAAW,CAChB,CAAC;AAEF,MAAM,WAAW,YAAY;IACzB,oFAAoF;IACpF,MAAM,EAAE,SAAS,CAAC;IAClB,wCAAwC;IACxC,SAAS,EAAE,iBAAiB,CAAC;IAC7B,6DAA6D;IAC7D,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAChC,KAAK,EAAE,SAAS,CAAC,EAAE,CAAC;IACpB,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,MAAM,CAAC;IAC5B,yCAAyC;IACzC,SAAS,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,IAAI,CAAC;IAChC,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,KAAK,SAAS,CAAC;IACtE,+FAA+F;IAC/F,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,EAC3B,KAAK,EACL,MAAM,EACN,SAAS,EACT,UAAU,EACV,QAAgB,EACnB,EAAE,iBAAiB,CAAC,CAAC,CAAC,2CA6FtB"}
@@ -8,13 +8,13 @@ import { moveItem, resolveTarget, startsInFormField } from "./reorderListModel.j
8
8
  * The render prop keeps the consumer's own row markup; the whole row drags (the grip is a hover
9
9
  * affordance). Pointer-only — no keyboard reorder yet.
10
10
  */
11
- export function ReorderList({ items, getKey, onReorder, renderItem }) {
11
+ export function ReorderList({ items, getKey, onReorder, renderItem, disabled = false, }) {
12
12
  const [dragIndex, setDragIndex] = useState(null);
13
13
  // Insert gap (0..n), canonical: one gap = one indicator position.
14
14
  const [dropGap, setDropGap] = useState(null);
15
15
  // Enter/leave counter across all rows; at 0 the cursor is outside every row → hide the indicator.
16
16
  const overCount = useRef(0);
17
- const enabled = items.length > 1;
17
+ const enabled = items.length > 1 && !disabled;
18
18
  const reset = () => {
19
19
  setDragIndex(null);
20
20
  setDropGap(null);
@@ -1,21 +1,31 @@
1
- import { type DateFilterGranularity, type IInsightDefinition, type WeekStart } from "@gooddata/sdk-model";
1
+ import { type DateFilterGranularity, type IInsightDefinition, type ISemanticConditionalFormatting, type WeekStart } from "@gooddata/sdk-model";
2
2
  import { type DataViewFacade } from "@gooddata/sdk-ui";
3
- import { type ConditionalFormattingOperator, type ConditionalFormattingTarget, type ConditionalFormattingValue, type IConditionalFormattingCondition, type IConditionalFormattingRule } from "@gooddata/sdk-ui-pivot/next";
3
+ import { type ConditionalFormattingOperator, type ConditionalFormattingTarget, type ConditionalFormattingValue, type IConditionalFormatting, type IConditionalFormattingCondition, type IConditionalFormattingRule } from "@gooddata/sdk-ui-pivot/next";
4
4
  /**
5
5
  * Date-attribute metadata date conditions author and validate against. Present only for granularities
6
6
  * the evaluation engine supports (linear; fiscal joins once its labeling convention is verified).
7
+ *
8
+ * @internal
7
9
  */
8
10
  export interface ICfDateMeta {
9
11
  granularity: DateFilterGranularity;
10
12
  /** The column's timezone (descriptor `format.timezone`) — "today" resolves in it. */
11
13
  timezone?: string;
12
14
  }
13
- /** Workspace date-display settings the date value picker honors (derived by the host from settings). */
15
+ /**
16
+ * Workspace date-display settings the date value picker honors (derived by the host from settings).
17
+ *
18
+ * @internal
19
+ */
14
20
  export interface ICfDateSettings {
15
21
  dateFormat?: string;
16
22
  weekStart?: WeekStart;
17
23
  }
18
- /** A selectable measure/attribute for the rule's "applies to" dropdown. */
24
+ /**
25
+ * A selectable measure/attribute for the rule's "applies to" dropdown.
26
+ *
27
+ * @internal
28
+ */
19
29
  export interface ITargetOption {
20
30
  /** `measure:<localId>` | `attribute:<localId>` */
21
31
  value: string;
@@ -28,6 +38,7 @@ export interface ITargetOption {
28
38
  /** Present iff the attribute is a date-condition-eligible date attribute; switches the condition set. */
29
39
  date?: ICfDateMeta;
30
40
  }
41
+ export declare const targetToValue: (target: ConditionalFormattingTarget) => string;
31
42
  /** Execution-resolved data the CF UI needs per localId; flows as one object from the pluggable down. */
32
43
  export interface ICfTargetData {
33
44
  /** Data-view titles by localId; preferred over the insight's often-absent titles. Empty until first load. */
@@ -38,6 +49,8 @@ export interface ICfTargetData {
38
49
  elements?: Record<string, string[]>;
39
50
  /** Date metadata by localId for date-condition-eligible attributes (descriptor granularity/timezone). */
40
51
  dates?: Record<string, ICfDateMeta>;
52
+ /** Semantic-layer conditional formatting carried on the execution result header, by localId. */
53
+ semantic?: Record<string, ISemanticConditionalFormatting>;
41
54
  }
42
55
  /**
43
56
  * Extracts {@link ICfTargetData} from the executed data view. Titles must come from here — attribute
@@ -50,6 +63,21 @@ export declare const findTargetOption: (options: ITargetOption[], target: Condit
50
63
  /** Date-eligible target: the option carries execution-resolved date metadata. */
51
64
  export declare const isDateTarget: (option: ITargetOption | undefined) => boolean;
52
65
  export declare const targetLocalId: (target: ConditionalFormattingTarget) => string;
66
+ /**
67
+ * Whether `target` is already in Custom mode on this insight config — an insight rule targets it,
68
+ * or it's explicitly listed in `customTargets`. Mirrors the `customModeTargets` set built by
69
+ * sdk-ui-pivot's `resolvePerTargetConditionalFormatting` (semanticConditionalFormatting.ts); the two
70
+ * packages don't share this helper, so keep them in sync by hand if either changes. Honoring
71
+ * `customTargets` here matters even though this PR never writes it: if some other path already
72
+ * marked a target Custom, the semantic block must still hide it as Inherited would be wrong.
73
+ */
74
+ export declare const isCustomTarget: (config: IConditionalFormatting | undefined, target: ConditionalFormattingTarget) => boolean;
75
+ /**
76
+ * Synthesizes a read-only rule for the View dialog from an inherited semantic-layer condition set.
77
+ * The id mirrors the engine's own `semantic:<kind>:<localId>` convention (semanticConditionalFormatting.ts)
78
+ * for consistency only — it's never persisted or compared.
79
+ */
80
+ export declare const semanticRuleFor: (option: ITargetOption, semantic: ISemanticConditionalFormatting) => IConditionalFormattingRule;
53
81
  export declare const operatorsForTarget: (kind: "attribute" | "measure", isDate: boolean) => ConditionalFormattingOperator[];
54
82
  export declare const operatorIcon: (operator: ConditionalFormattingOperator) => string | undefined;
55
83
  export declare const targetIcon: (kind: "attribute" | "measure", isDate?: boolean) => string;
@@ -62,6 +90,15 @@ export type ConditionValueEditor = "none" | "number" | "combobox" | "text" | "ra
62
90
  * operand is always the period picker.
63
91
  */
64
92
  export declare const valueEditorKind: (condition: IConditionalFormattingCondition, kind: "attribute" | "measure", hasSuggestions: boolean, isDate: boolean) => ConditionValueEditor;
93
+ /**
94
+ * Whether a stored value's shape is one `editorKind`'s control can represent. Editing always keeps
95
+ * this true (operator changes normalize the value's shape, and {@link sanitizeRuleForEditing} clears
96
+ * what it can't fix), but a read-only semantic-layer rule may pair an operator with a value shape the
97
+ * pivot editor never authors — e.g. a text operator stored against a date target.
98
+ */
99
+ export declare const valueMatchesEditorKind: (editorKind: ConditionValueEditor, value: ConditionalFormattingValue) => boolean;
100
+ /** A plain-text rendering of a stored value, for the read-only fallback when it doesn't fit its editor. */
101
+ export declare const rawValueText: (value: ConditionalFormattingValue) => string;
65
102
  /** Fresh empty operand of the right shape for the operator. */
66
103
  export declare const emptyValueForOperator: (operator: ConditionalFormattingOperator, isDate?: boolean) => ConditionalFormattingValue;
67
104
  /**
@@ -99,10 +136,11 @@ export type ConditionInvalidError = "rangeOrder" | "dateUnresolvable";
99
136
  /** Everything the editor renders inline: the model's errors plus its own blank-visited-field state. */
100
137
  export type ConditionalFormattingFieldError = ConditionInvalidError | "valueEmpty";
101
138
  /**
102
- * Coerces stored condition shapes the editor cannot represent so an AAC-authored rule opens editable
103
- * instead of dead-ended (disabled Save then covers the cleared values). A non-numeric measure literal
104
- * clears to empty; on a date target, operators/values outside the date set reset to an unpicked
105
- * "Is on" (id and format survive). The engine keeps evaluating the stored original until Save.
139
+ * Coerces stored condition shapes the editor cannot represent so an AAC-authored (or inherited
140
+ * semantic-layer) rule opens editable instead of dead-ended (disabled Save then covers the cleared
141
+ * values). An operator outside the target's curated set resets to "Is on"/"Equal to" and its value
142
+ * shape follows; a non-numeric measure literal clears to empty. Id and format always survive. The
143
+ * engine keeps evaluating the stored original until Save.
106
144
  */
107
145
  export declare const sanitizeRuleForEditing: (rule: IConditionalFormattingRule, isDate?: boolean) => IConditionalFormattingRule;
108
146
  export interface IConditionValidation {
@@ -1 +1 @@
1
- {"version":3,"file":"conditionalFormattingModel.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/conditionalFormattingModel.ts"],"names":[],"mappings":"AAIA,OAAO,EACH,KAAK,qBAAqB,EAC1B,KAAK,kBAAkB,EACvB,KAAK,SAAS,EAajB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACpE,OAAO,EACH,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,0BAA0B,EAC/B,KAAK,+BAA+B,EACpC,KAAK,0BAA0B,EAIlC,MAAM,6BAA6B,CAAC;AAIrC;;;GAGG;AACH,MAAM,WAAW,WAAW;IACxB,WAAW,EAAE,qBAAqB,CAAC;IACnC,uFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wGAAwG;AACxG,MAAM,WAAW,eAAe;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,SAAS,CAAC;CACzB;AAED,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC1B,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,2BAA2B,CAAC;IACpC,sGAAsG;IACtG,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gHAA8G;IAC9G,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7B,yGAAyG;IACzG,IAAI,CAAC,EAAE,WAAW,CAAC;CACtB;AAUD,wGAAwG;AACxG,MAAM,WAAW,aAAa;IAC1B,6GAA6G;IAC7G,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,wFAAsF;IACtF,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,+EAA+E;IAC/E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC,yGAAyG;IACzG,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACvC;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,cAAc,GAAG,QAAQ,CAAC,aAAa,CAAC,CAwBnF;AAiCD,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,kBAAkB,EAAE,IAAI,GAAE,aAAkB,GAAG,aAAa,EAAE,CAmCzG;AAED,eAAO,MAAM,gBAAgB,8FAGmE,CAAC;AAEjG,iFAAiF;AACjF,eAAO,MAAM,YAAY,gDAA6E,CAAC;AAEvG,eAAO,MAAM,aAAa,iDAC2D,CAAC;AAuDtF,eAAO,MAAM,kBAAkB,qFAQ9B,CAAC;AAgBF,eAAO,MAAM,YAAY,iEAGxB,CAAC;AAIF,eAAO,MAAM,UAAU,6DAKtB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAExD,eAAO,MAAM,aAAa,4DAKzB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAK9F;;;;GAIG;AACH,eAAO,MAAM,eAAe,+IAoB3B,CAAC;AAIF,+DAA+D;AAC/D,eAAO,MAAM,qBAAqB,2FAgBjC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,gIAgB5B,CAAC;AAEF,wEAAwE;AACxE,eAAO,MAAM,WAAW,+CAC+B,CAAC;AAExD,6FAA6F;AAC7F,eAAO,MAAM,UAAU,sDAMtB,CAAC;AAEF,kEAAkE;AAClE,eAAO,MAAM,QAAQ,4EAMpB,CAAC;AAKF,eAAO,MAAM,YAAY,uDAMvB,CAAC;AAEH,eAAO,MAAM,OAAO,uDAIlB,CAAC;AAEH;;;;;GAKG;AACH,eAAO,MAAM,cAAc,4HA2C1B,CAAC;AAIF;;;;GAIG;AACH,eAAO,MAAM,eAAe,yCAKN,CAAC;AAKvB,gFAA+E;AAC/E,eAAO,MAAM,kBAAkB,2CACO,CAAC;AAEvC,uFAAsF;AACtF,eAAO,MAAM,kBAAkB,+CACe,CAAC;AAI/C,wEAAwE;AACxE,MAAM,MAAM,qBAAqB,GAAG,YAAY,GAAG,kBAAkB,CAAC;AAEtE,uGAAuG;AACvG,MAAM,MAAM,+BAA+B,GAAG,qBAAqB,GAAG,YAAY,CAAC;AAInF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,oFAqClC,CAAC;AAEF,MAAM,WAAW,oBAAoB;IACjC,gGAA8F;IAC9F,OAAO,EAAE,OAAO,CAAC;IACjB,qGAAmG;IACnG,KAAK,CAAC,EAAE,qBAAqB,CAAC;CACjC;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,qIAmC7B,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,cAAc,+EAKrB,CAAC"}
1
+ {"version":3,"file":"conditionalFormattingModel.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/configurationControls/conditionalFormatting/conditionalFormattingModel.ts"],"names":[],"mappings":"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"}