@gooddata/sdk-ui-dashboard 11.58.0-alpha.0 → 11.58.0-alpha.2

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 (82) hide show
  1. package/NOTICE +2322 -1761
  2. package/esm/__version.d.ts +1 -1
  3. package/esm/__version.js +1 -1
  4. package/esm/_staging/sharedHooks/useFiltersNamings.d.ts.map +1 -1
  5. package/esm/_staging/sharedHooks/useFiltersNamings.js +5 -3
  6. package/esm/index.d.ts +5 -5
  7. package/esm/index.d.ts.map +1 -1
  8. package/esm/index.js +3 -3
  9. package/esm/model/commandHandlers/dashboard/common/parameterHydration.d.ts +2 -2
  10. package/esm/model/commandHandlers/dashboard/common/parameterHydration.d.ts.map +1 -1
  11. package/esm/model/commandHandlers/dashboard/common/parameterHydration.js +2 -5
  12. package/esm/model/commandHandlers/filterContext/attributeFilter/addAttributeFilterHandler.d.ts.map +1 -1
  13. package/esm/model/commandHandlers/filterContext/attributeFilter/addAttributeFilterHandler.js +5 -0
  14. package/esm/model/commandHandlers/filterContext/attributeFilter/addTextAttributeFilterHandler.d.ts.map +1 -1
  15. package/esm/model/commandHandlers/filterContext/attributeFilter/addTextAttributeFilterHandler.js +5 -0
  16. package/esm/model/commandHandlers/filterContext/attributeFilter/changeAttributeDisplayFormHandler.d.ts.map +1 -1
  17. package/esm/model/commandHandlers/filterContext/attributeFilter/changeAttributeDisplayFormHandler.js +5 -0
  18. package/esm/model/commandHandlers/filterContext/attributeFilter/validation/computedAttributesEnabledValidation.d.ts +16 -0
  19. package/esm/model/commandHandlers/filterContext/attributeFilter/validation/computedAttributesEnabledValidation.d.ts.map +1 -0
  20. package/esm/model/commandHandlers/filterContext/attributeFilter/validation/computedAttributesEnabledValidation.js +27 -0
  21. package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.d.ts.map +1 -1
  22. package/esm/model/commandHandlers/filterContext/changeFilterContextSelectionHandler.js +11 -0
  23. package/esm/model/commandHandlers/filterContext/common.d.ts +1 -1
  24. package/esm/model/commandHandlers/filterContext/common.d.ts.map +1 -1
  25. package/esm/model/commandHandlers/filterContext/common.js +5 -0
  26. package/esm/model/commandHandlers/filterContext/filterViewHandler.d.ts.map +1 -1
  27. package/esm/model/commandHandlers/filterContext/filterViewHandler.js +5 -2
  28. package/esm/model/commandHandlers/parameters/changeParameterValuesHandler.d.ts +12 -2
  29. package/esm/model/commandHandlers/parameters/changeParameterValuesHandler.d.ts.map +1 -1
  30. package/esm/model/commandHandlers/parameters/changeParameterValuesHandler.js +31 -3
  31. package/esm/model/commands/parameters.d.ts +12 -3
  32. package/esm/model/commands/parameters.d.ts.map +1 -1
  33. package/esm/model/events/base.d.ts +1 -1
  34. package/esm/model/events/base.d.ts.map +1 -1
  35. package/esm/model/events/index.d.ts +2 -2
  36. package/esm/model/events/index.d.ts.map +1 -1
  37. package/esm/model/events/parameters.d.ts +38 -0
  38. package/esm/model/events/parameters.d.ts.map +1 -1
  39. package/esm/model/events/parameters.js +22 -0
  40. package/esm/model/react/useIsWidgetRestricted.d.ts.map +1 -1
  41. package/esm/model/react/useIsWidgetRestricted.js +14 -7
  42. package/esm/model/store/tabs/index.d.ts +0 -4
  43. package/esm/model/store/tabs/index.d.ts.map +1 -1
  44. package/esm/model/store/tabs/layout/layoutSelectors.d.ts +10 -0
  45. package/esm/model/store/tabs/layout/layoutSelectors.d.ts.map +1 -1
  46. package/esm/model/store/tabs/layout/layoutSelectors.js +55 -26
  47. package/esm/model/store/tabs/parameters/parametersHelpers.d.ts +15 -4
  48. package/esm/model/store/tabs/parameters/parametersHelpers.d.ts.map +1 -1
  49. package/esm/model/store/tabs/parameters/parametersHelpers.js +28 -0
  50. package/esm/model/store/tabs/parameters/parametersReducers.d.ts +2 -12
  51. package/esm/model/store/tabs/parameters/parametersReducers.d.ts.map +1 -1
  52. package/esm/model/store/tabs/parameters/parametersReducers.js +0 -4
  53. package/esm/model/store/tabs/parameters/parametersSelectors.d.ts +22 -4
  54. package/esm/model/store/tabs/parameters/parametersSelectors.d.ts.map +1 -1
  55. package/esm/model/store/tabs/parameters/parametersSelectors.js +46 -12
  56. package/esm/presentation/automations/alerting/types.d.ts +7 -83
  57. package/esm/presentation/automations/alerting/types.d.ts.map +1 -1
  58. package/esm/presentation/automations/scheduledEmail/types.d.ts +6 -112
  59. package/esm/presentation/automations/scheduledEmail/types.d.ts.map +1 -1
  60. package/esm/presentation/automations/shared/hooks/useFiltersNamings.d.ts.map +1 -1
  61. package/esm/presentation/automations/shared/hooks/useFiltersNamings.js +5 -3
  62. package/esm/presentation/filterBar/filterBar/hooks/useResetFiltersButton.js +2 -2
  63. package/esm/presentation/filterBar/parameterFilter/DashboardParameterFilter.d.ts.map +1 -1
  64. package/esm/presentation/filterBar/parameterFilter/DashboardParameterFilter.js +2 -1
  65. package/esm/presentation/flexibleLayout/DefaultDashboardLayoutRenderer/EditableHeader/SectionHeaderEditable.d.ts.map +1 -1
  66. package/esm/presentation/flexibleLayout/DefaultDashboardLayoutRenderer/EditableHeader/SectionHeaderEditable.js +35 -13
  67. package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts +12 -0
  68. package/esm/presentation/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
  69. package/esm/presentation/localization/bundles/en-US.localization-bundle.js +12 -0
  70. package/esm/presentation/widget/insight/configuration/InsightDescriptionConfig/InsightDescription.d.ts.map +1 -1
  71. package/esm/presentation/widget/insight/configuration/InsightDescriptionConfig/InsightDescription.js +30 -12
  72. package/esm/presentation/widget/richText/EditModeDashboardRichText.d.ts.map +1 -1
  73. package/esm/presentation/widget/richText/EditModeDashboardRichText.js +18 -6
  74. package/esm/presentation/widget/richText/RestrictedReferencesDialog.d.ts +22 -0
  75. package/esm/presentation/widget/richText/RestrictedReferencesDialog.d.ts.map +1 -0
  76. package/esm/presentation/widget/richText/RestrictedReferencesDialog.js +42 -0
  77. package/esm/presentation/widget/richText/useEditableRichTextMenu.d.ts.map +1 -1
  78. package/esm/presentation/widget/richText/useEditableRichTextMenu.js +6 -2
  79. package/esm/sdk-ui-dashboard.d.ts +121 -208
  80. package/package.json +23 -23
  81. package/styles/css/main.css +20 -9
  82. package/styles/css/main.css.map +1 -1
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2022-2026 GoodData Corporation
3
3
  import { useCallback, useEffect, useState } from "react";
4
4
  import cx from "classnames";
@@ -7,6 +7,7 @@ import { RichTextWithTooltip } from "@gooddata/sdk-ui-kit";
7
7
  import { useDashboardSelector } from "../../../../../model/react/DashboardStoreProvider.js";
8
8
  import { useDashboardExecConfig } from "../../../../../model/react/useWidgetExecConfig.js";
9
9
  import { selectRestrictedRichTextReferences } from "../../../../../model/store/unavailableObjects/unavailableObjectsSelectors.js";
10
+ import { RestrictedReferencesDialog, useHasRestrictedReferences, } from "../../../richText/RestrictedReferencesDialog.js";
10
11
  const richTextTooltipAlignPoints = [
11
12
  { align: "bl tl", offset: { x: 4, y: 5 } },
12
13
  { align: "tl bl", offset: { x: 4, y: -5 } },
@@ -16,7 +17,8 @@ export function InsightDescription({ description, setDescription, readOnly = fal
16
17
  const placeholder = intl.formatMessage({
17
18
  id: "configurationPanel.visualprops.descriptionPlaceholder",
18
19
  });
19
- const [isRichTextEditing, setIsRichTextEditing] = useState(false);
20
+ // what the editor asked for; whether it is the question or the editor follows from the text
21
+ const [isEditingRequested, setIsEditingRequested] = useState(false);
20
22
  const [richTextValue, setRichTextValue] = useState(description);
21
23
  const execConfig = useDashboardExecConfig();
22
24
  const restrictedReferences = useDashboardSelector(selectRestrictedRichTextReferences);
@@ -26,17 +28,33 @@ export function InsightDescription({ description, setDescription, readOnly = fal
26
28
  const onChange = useCallback((value) => {
27
29
  setDescription(value.trim());
28
30
  }, [setDescription]);
29
- const onDescriptionClick = useCallback(() => {
30
- if (!isRichTextEditing && !readOnly) {
31
- setIsRichTextEditing(true);
32
- }
33
- }, [isRichTextEditing, readOnly]);
34
- const onDescriptionBlur = useCallback(() => {
35
- setIsRichTextEditing(false);
36
- onChange(richTextValue);
37
- }, [onChange, richTextValue]);
31
+ const startEditing = useCallback(() => setIsEditingRequested(true), []);
38
32
  const onRichTextChange = useCallback((value) => {
39
33
  setRichTextValue(value);
40
34
  }, []);
41
- return (_jsx("label", { className: "gd-input", children: _jsx("div", { className: cx("gd-input-field gd-rich-text-insight-description", { disabled: readOnly }), onClick: onDescriptionClick, onBlur: onDescriptionBlur, children: _jsx(RichTextWithTooltip, { value: richTextValue, renderMode: isRichTextEditing ? "edit" : "view", onChange: onRichTextChange, editRows: 4, editPlaceholder: placeholder, emptyElement: readOnly ? undefined : (_jsx("div", { className: "gd-editable-label-richtext-empty", children: placeholder })), showTooltip: isRichTextEditing, tooltipAlignPoints: richTextTooltipAlignPoints, referencesEnabled: true, LoadingComponent: LoadingComponent, filters: insightFilters, separators: separators, restrictedReferences: restrictedReferences, execConfig: execConfig }) }) }));
35
+ const hasRestrictedReferences = useHasRestrictedReferences(richTextValue);
36
+ const isRichTextEditing = isEditingRequested && !hasRestrictedReferences;
37
+ const isAskingToSanitize = isEditingRequested && hasRestrictedReferences;
38
+ // the rewrite is committed at once: it was confirmed, and it is not a keystroke. The editor was
39
+ // already asked for, so the description opens as soon as the text no longer holds a reference
40
+ const onSanitized = useCallback((sanitized) => {
41
+ setRichTextValue(sanitized);
42
+ onChange(sanitized);
43
+ }, [onChange]);
44
+ const stopEditing = useCallback(() => setIsEditingRequested(false), []);
45
+ const onDescriptionBlur = useCallback(() => {
46
+ // the confirmation takes the focus out of the description, and that is not the editor
47
+ // leaving it: nothing is decided yet
48
+ if (isAskingToSanitize) {
49
+ return;
50
+ }
51
+ setIsEditingRequested(false);
52
+ onChange(richTextValue);
53
+ }, [onChange, richTextValue, isAskingToSanitize]);
54
+ const onDescriptionClick = useCallback(() => {
55
+ if (!isEditingRequested && !readOnly) {
56
+ startEditing();
57
+ }
58
+ }, [isEditingRequested, readOnly, startEditing]);
59
+ return (_jsxs("label", { className: "gd-input", children: [_jsx("div", { className: cx("gd-input-field gd-rich-text-insight-description", { disabled: readOnly }), onClick: onDescriptionClick, onBlur: onDescriptionBlur, children: _jsx(RichTextWithTooltip, { value: richTextValue, renderMode: isRichTextEditing ? "edit" : "view", onChange: onRichTextChange, editRows: 4, editPlaceholder: placeholder, emptyElement: readOnly ? undefined : (_jsx("div", { className: "gd-editable-label-richtext-empty", children: placeholder })), showTooltip: isRichTextEditing, tooltipAlignPoints: richTextTooltipAlignPoints, referencesEnabled: true, LoadingComponent: LoadingComponent, filters: insightFilters, separators: separators, restrictedReferences: restrictedReferences, execConfig: execConfig }) }), isAskingToSanitize ? (_jsx(RestrictedReferencesDialog, { value: richTextValue, onSanitized: onSanitized, onCancel: stopEditing })) : null] }));
42
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EditModeDashboardRichText.d.ts","sourceRoot":"","sources":["../../../../src/presentation/widget/richText/EditModeDashboardRichText.tsx"],"names":[],"mappings":"AA6BA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAK1D;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CAgHvG"}
1
+ {"version":3,"file":"EditModeDashboardRichText.d.ts","sourceRoot":"","sources":["../../../../src/presentation/widget/richText/EditModeDashboardRichText.tsx"],"names":[],"mappings":"AA+BA,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,YAAY,CAAC;AAK1D;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CAqIvG"}
@@ -1,6 +1,6 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2020-2026 GoodData Corporation
3
- import { useEffect, useMemo, useState } from "react";
3
+ import { useCallback, useEffect, useMemo, useState } from "react";
4
4
  import { FormattedMessage, useIntl } from "react-intl";
5
5
  import { widgetRef } from "@gooddata/sdk-model";
6
6
  import { usePrevious } from "@gooddata/sdk-ui";
@@ -13,9 +13,11 @@ import { useDashboardDispatch, useDashboardSelector } from "../../../model/react
13
13
  import { useDashboardExecConfig } from "../../../model/react/useWidgetExecConfig.js";
14
14
  import { useWidgetSelection } from "../../../model/react/useWidgetSelection.js";
15
15
  import { selectIsWhiteLabeled, selectSeparators } from "../../../model/store/config/configSelectors.js";
16
+ import { uiActions } from "../../../model/store/ui/index.js";
16
17
  import { selectRestrictedRichTextReferences } from "../../../model/store/unavailableObjects/unavailableObjectsSelectors.js";
17
18
  import { DASHBOARD_OVERLAYS_FILTER_Z_INDEX } from "../../../presentation/constants/zIndex.js";
18
19
  import { useDashboardComponentsContext } from "../../dashboardContexts/DashboardComponentsContext.js";
20
+ import { RestrictedReferencesDialog, useHasRestrictedReferences } from "./RestrictedReferencesDialog.js";
19
21
  import { useEditableRichTextMenu } from "./useEditableRichTextMenu.js";
20
22
  const overlayController = OverlayController.getInstance(DASHBOARD_OVERLAYS_FILTER_Z_INDEX);
21
23
  /**
@@ -32,8 +34,21 @@ export function EditModeDashboardRichText({ widget, clientWidth, clientHeight })
32
34
  const { filters } = useRichTextWidgetFilters(widget);
33
35
  const separators = useDashboardSelector(selectSeparators);
34
36
  const dispatch = useDashboardDispatch();
37
+ const releaseWidget = useCallback(() => dispatch(uiActions.clearWidgetSelection()), [dispatch]);
35
38
  const [richText, setRichText] = useState(widget?.content);
36
- const [isRichTextEditing, setIsRichTextEditing] = useState(false);
39
+ // the rewrite is committed at once: it was confirmed, and it is not a keystroke
40
+ const onSanitized = useCallback((sanitized) => {
41
+ setRichText(sanitized);
42
+ dispatch(changeRichTextWidgetContent(widget.ref, sanitized));
43
+ }, [dispatch, widget.ref]);
44
+ // Selecting the widget is what opens its editor, and a text holding a reference the editor may
45
+ // not read is asked about first. Both states are that selection and that text, so neither is
46
+ // kept as a flag: confirming rewrites the text, which is what turns the question into the
47
+ // editor; cancelling lets the widget go - deliberately, rather than through deselectWidgets,
48
+ // which holds on to a widget whose text the pointer happens to have selected.
49
+ const hasRestrictedReferences = useHasRestrictedReferences(richText);
50
+ const isRichTextEditing = isSelected && !hasRestrictedReferences;
51
+ const isAskingToSanitize = isSelected && hasRestrictedReferences;
37
52
  const [isConfirmDeleteDialogVisible, setIsConfirmDeleteDialogVisible] = useState(false);
38
53
  const theme = useTheme();
39
54
  const emptyContentIconColor = theme?.palette?.complementary?.c7 ?? "#6D7680";
@@ -42,9 +57,6 @@ export function EditModeDashboardRichText({ widget, clientWidth, clientHeight })
42
57
  }, [emptyContentIconColor, intl]);
43
58
  const { RichTextMenuComponentProvider, LoadingComponent } = useDashboardComponentsContext();
44
59
  const RichTextMenuComponent = useMemo(() => RichTextMenuComponentProvider(widget), [RichTextMenuComponentProvider, widget]);
45
- useEffect(() => {
46
- setIsRichTextEditing(isSelected);
47
- }, [isSelected]);
48
60
  useEffect(() => {
49
61
  // Deselect widget and commit updated markdown text "on blur"
50
62
  if (previousIsSelected && !isSelected && richText !== widget?.content) {
@@ -56,5 +68,5 @@ export function EditModeDashboardRichText({ widget, clientWidth, clientHeight })
56
68
  clientWidth > 250 &&
57
69
  typeof clientHeight !== "undefined" &&
58
70
  clientHeight > 150;
59
- return (_jsxs(_Fragment, { children: [hasConfigPanelOpen ? (_jsx(RichTextMenuComponent, { widget: widget, isOpen: hasConfigPanelOpen, onClose: closeConfigPanel, items: menuItems })) : null, _jsx(RichText, { referencesEnabled: true, filters: filters, separators: separators, restrictedReferences: restrictedReferences, className: "gd-rich-text-widget", value: richText, onChange: setRichText, renderMode: isRichTextEditing ? "edit" : "view", emptyElement: EmptyElement, LoadingComponent: LoadingComponent, execConfig: execConfig }), isRichTextEditing && showLink ? (_jsx("div", { className: "gd-rich-text-widget-footer", children: _jsx("div", { className: "gd-rich-text-footer-options", children: showLink ? (_jsx("a", { className: "gd-button-link-dimmed gd-icon-circle-question", href: "https://www.gooddata.com/docs/cloud/create-dashboards/rich-text/", rel: "noopener noreferrer", target: "_blank", children: _jsx(FormattedMessage, { id: "richText.formattingOptions" }) })) : null }) })) : null, isConfirmDeleteDialogVisible ? (_jsx(OverlayControllerProvider, { overlayController: overlayController, children: _jsx(ConfirmDialog, { className: "s-rich-text-remove-confirm-dialog", onSubmit: () => dispatch(eagerRemoveSectionItemByWidgetRef(widget.ref)), onCancel: () => setIsConfirmDeleteDialogVisible(false), headline: intl.formatMessage({ id: "richText.deleteDialog.header" }), submitButtonText: intl.formatMessage({ id: "delete" }), cancelButtonText: intl.formatMessage({ id: "cancel" }), children: _jsx(FormattedMessage, { id: "richText.deleteDialog.message" }) }) })) : null] }));
71
+ return (_jsxs(_Fragment, { children: [hasConfigPanelOpen ? (_jsx(RichTextMenuComponent, { widget: widget, isOpen: hasConfigPanelOpen, onClose: closeConfigPanel, items: menuItems })) : null, _jsx(RichText, { referencesEnabled: true, filters: filters, separators: separators, restrictedReferences: restrictedReferences, className: "gd-rich-text-widget", value: richText, onChange: setRichText, renderMode: isRichTextEditing ? "edit" : "view", emptyElement: EmptyElement, LoadingComponent: LoadingComponent, execConfig: execConfig }), isRichTextEditing && showLink ? (_jsx("div", { className: "gd-rich-text-widget-footer", children: _jsx("div", { className: "gd-rich-text-footer-options", children: showLink ? (_jsx("a", { className: "gd-button-link-dimmed gd-icon-circle-question", href: "https://www.gooddata.com/docs/cloud/create-dashboards/rich-text/", rel: "noopener noreferrer", target: "_blank", children: _jsx(FormattedMessage, { id: "richText.formattingOptions" }) })) : null }) })) : null, isAskingToSanitize ? (_jsx(RestrictedReferencesDialog, { value: richText, onSanitized: onSanitized, onCancel: releaseWidget })) : null, isConfirmDeleteDialogVisible ? (_jsx(OverlayControllerProvider, { overlayController: overlayController, children: _jsx(ConfirmDialog, { className: "s-rich-text-remove-confirm-dialog", onSubmit: () => dispatch(eagerRemoveSectionItemByWidgetRef(widget.ref)), onCancel: () => setIsConfirmDeleteDialogVisible(false), headline: intl.formatMessage({ id: "richText.deleteDialog.header" }), submitButtonText: intl.formatMessage({ id: "delete" }), cancelButtonText: intl.formatMessage({ id: "cancel" }), children: _jsx(FormattedMessage, { id: "richText.deleteDialog.message" }) }) })) : null] }));
60
72
  }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Whether the text references an object the current user is not allowed to read. A surface that
3
+ * edits text asks this to know which of its two states it is in, rather than keeping a flag that
4
+ * says the same thing a moment later.
5
+ */
6
+ export declare function useHasRestrictedReferences(value: string): boolean;
7
+ interface IRestrictedReferencesDialogProps {
8
+ /** The text as it stands. */
9
+ value: string;
10
+ /** Stores the sanitized text. The caller edits it once it no longer holds such a reference. */
11
+ onSanitized: (sanitized: string) => void;
12
+ /** The editor kept the references, and is not editing after all. */
13
+ onCancel: () => void;
14
+ }
15
+ /**
16
+ * Asks before a text that references objects the user cannot read is edited: those references have
17
+ * to go first, and that is destructive. The caller mounts it while it is the answer it is waiting
18
+ * for - confirming rewrites the text, which is what ends the question.
19
+ */
20
+ export declare function RestrictedReferencesDialog({ value, onSanitized, onCancel, }: IRestrictedReferencesDialogProps): import("react/jsx-runtime").JSX.Element;
21
+ export {};
22
+ //# sourceMappingURL=RestrictedReferencesDialog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RestrictedReferencesDialog.d.ts","sourceRoot":"","sources":["../../../../src/presentation/widget/richText/RestrictedReferencesDialog.tsx"],"names":[],"mappings":"AAqBA;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAWjE;AAED,UAAU,gCAAgC;IACtC,6BAA6B;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,+FAA+F;IAC/F,WAAW,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,oEAAoE;IACpE,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,EACvC,KAAK,EACL,WAAW,EACX,QAAQ,GACX,EAAE,gCAAgC,2CAyBlC"}
@@ -0,0 +1,42 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ // (C) 2026 GoodData Corporation
3
+ import { useCallback, useMemo } from "react";
4
+ import { useIntl } from "react-intl";
5
+ import { areObjRefsEqual } from "@gooddata/sdk-model";
6
+ import { UiConfirmDialog, collectReferences, replaceReferences } from "@gooddata/sdk-ui-kit";
7
+ import { useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
8
+ import { selectRestrictedRichTextReferences } from "../../../model/store/unavailableObjects/unavailableObjectsSelectors.js";
9
+ /**
10
+ * Put in the text in place of a reference the editor may not read, as the design has it. It is
11
+ * stored as the text itself, and thus is the same for every reader and not localised.
12
+ */
13
+ const RESTRICTED_REFERENCE_REPLACEMENT = "???";
14
+ /** The wrapper is there to catch events, and must not take part in the layout it is dropped into. */
15
+ const noBoxOfItsOwn = { display: "contents" };
16
+ /**
17
+ * Whether the text references an object the current user is not allowed to read. A surface that
18
+ * edits text asks this to know which of its two states it is in, rather than keeping a flag that
19
+ * says the same thing a moment later.
20
+ */
21
+ export function useHasRestrictedReferences(value) {
22
+ const restrictedReferences = useDashboardSelector(selectRestrictedRichTextReferences);
23
+ return useMemo(() => {
24
+ if (restrictedReferences.length === 0) {
25
+ return false;
26
+ }
27
+ return Object.values(collectReferences(value)).some((reference) => restrictedReferences.some((restricted) => areObjRefsEqual(restricted, reference.ref)));
28
+ }, [value, restrictedReferences]);
29
+ }
30
+ /**
31
+ * Asks before a text that references objects the user cannot read is edited: those references have
32
+ * to go first, and that is destructive. The caller mounts it while it is the answer it is waiting
33
+ * for - confirming rewrites the text, which is what ends the question.
34
+ */
35
+ export function RestrictedReferencesDialog({ value, onSanitized, onCancel, }) {
36
+ const intl = useIntl();
37
+ const restrictedReferences = useDashboardSelector(selectRestrictedRichTextReferences);
38
+ const onConfirm = useCallback(() => {
39
+ onSanitized(replaceReferences(value, restrictedReferences, RESTRICTED_REFERENCE_REPLACEMENT));
40
+ }, [value, restrictedReferences, onSanitized]);
41
+ return (_jsx("span", { style: noBoxOfItsOwn, onClick: (event) => event.stopPropagation(), children: _jsx(UiConfirmDialog, { isOpen: true, dataTestId: "rich-text-sanitize-references-dialog", title: intl.formatMessage({ id: "richText.restrictedReferences.dialog.header" }), description: intl.formatMessage({ id: "richText.restrictedReferences.dialog.message" }), confirmLabel: intl.formatMessage({ id: "richText.restrictedReferences.dialog.submit" }), confirmVariant: "danger", onConfirm: onConfirm, onCancel: onCancel, onClose: onCancel }) }));
42
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"useEditableRichTextMenu.d.ts","sourceRoot":"","sources":["../../../../src/presentation/widget/richText/useEditableRichTextMenu.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAO3D,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,KAAK,6BAA6B,GAAG;IACjC,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,uBAAuB,WACxB,6BAA6B,KACtC;IAAE,SAAS,EAAE,iBAAiB,EAAE,CAAA;CA2BlC,CAAC"}
1
+ {"version":3,"file":"useEditableRichTextMenu.d.ts","sourceRoot":"","sources":["../../../../src/presentation/widget/richText/useEditableRichTextMenu.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAQ3D,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAElE,KAAK,6BAA6B,GAAG;IACjC,MAAM,EAAE,eAAe,CAAC;IACxB,SAAS,EAAE,MAAM,IAAI,CAAC;CACzB,CAAC;AAEF,eAAO,MAAM,uBAAuB,WACxB,6BAA6B,KACtC;IAAE,SAAS,EAAE,iBAAiB,EAAE,CAAA;CA8BlC,CAAC"}
@@ -3,6 +3,7 @@ import { useMemo } from "react";
3
3
  import { useIntl } from "react-intl";
4
4
  import { useDashboardDispatch, useDashboardSelector } from "../../../model/react/DashboardStoreProvider.js";
5
5
  import { useDashboardEventDispatch } from "../../../model/react/useDashboardEventDispatch.js";
6
+ import { useIsWidgetRestricted } from "../../../model/react/useIsWidgetRestricted.js";
6
7
  import { selectEnableRichTextWidgetFilterConfiguration } from "../../../model/store/config/configSelectors.js";
7
8
  import { useDashboardCustomizationsContext } from "../../dashboardContexts/DashboardCustomizationsContext.js";
8
9
  import { getDefaultRichTextEditMode } from "../richTextMenu/DefaultDashboardRichTextMenu/getDefaultRichTextEditMenuItems.js";
@@ -12,15 +13,18 @@ export const useEditableRichTextMenu = (config) => {
12
13
  const dispatch = useDashboardDispatch();
13
14
  const eventDispatch = useDashboardEventDispatch();
14
15
  const enableRichTextWidgetFilterConfiguration = useDashboardSelector(selectEnableRichTextWidgetFilterConfiguration);
16
+ // there is nothing to configure about a reference the editor is not allowed to read, so the
17
+ // menu of such a widget holds removal alone
18
+ const isRestricted = useIsWidgetRestricted(widget);
15
19
  const { richTextMenuItemsProvider } = useDashboardCustomizationsContext();
16
20
  const defaultMenuItems = useMemo(() => {
17
21
  return getDefaultRichTextEditMode(widget, {
18
22
  intl,
19
23
  dispatch,
20
24
  eventDispatch,
21
- enableRichTextWidgetFilterConfiguration,
25
+ enableRichTextWidgetFilterConfiguration: enableRichTextWidgetFilterConfiguration && !isRestricted,
22
26
  });
23
- }, [dispatch, eventDispatch, intl, widget, enableRichTextWidgetFilterConfiguration]);
27
+ }, [dispatch, eventDispatch, intl, widget, enableRichTextWidgetFilterConfiguration, isRestricted]);
24
28
  const menuItems = useMemo(() => {
25
29
  return richTextMenuItemsProvider
26
30
  ? richTextMenuItemsProvider(widget, defaultMenuItems, closeMenu, "edit")