@gooddata/sdk-ui-kit 11.36.0-alpha.3 → 11.36.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/@ui/UiControlButton/UiControlButton.d.ts +5 -1
- package/esm/@ui/UiControlButton/UiControlButton.js +2 -2
- package/esm/@ui/UiFocusManager/UiAutofocus.js +74 -18
- package/esm/@ui/UiMenu/hooks.js +14 -4
- package/esm/@ui/UiMenu/types.d.ts +4 -0
- package/esm/@ui/UiPagedVirtualList/UiPagedVirtualList.d.ts +1 -1
- package/esm/@ui/UiPagedVirtualList/UiPagedVirtualList.js +9 -3
- package/esm/Dialog/ShareDialog/ShareDialog.d.ts +1 -1
- package/esm/Dialog/ShareDialog/ShareDialog.js +3 -3
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareDialogBase.js +2 -2
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareGranteeBase.d.ts +1 -1
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareGranteeBase.js +2 -2
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareLink.d.ts +1 -1
- package/esm/Dialog/ShareDialog/ShareDialogBase/ShareLink.js +9 -4
- package/esm/Dialog/ShareDialog/ShareDialogBase/types.d.ts +4 -1
- package/esm/Dialog/ShareDialog/ShareDialogBase/types.js +1 -1
- package/esm/Dialog/ShareDialog/types.d.ts +2 -1
- package/esm/Dialog/ShareDialog/types.js +1 -0
- package/esm/Dropdown/DropdownList.js +12 -4
- package/esm/FilterGroupItem/FilterGroupItem.js +12 -5
- package/esm/Header/generateHeaderMenuItemsGroups.js +10 -2
- package/esm/Icon/Icon.js +3 -1
- package/esm/Icon/InsightIcon.js +2 -1
- package/esm/Icon/icons/InsightIcons/Radar.d.ts +5 -0
- package/esm/Icon/icons/InsightIcons/Radar.js +10 -0
- package/esm/index.d.ts +1 -0
- package/esm/index.js +1 -0
- package/esm/sdk-ui-kit.d.ts +21 -4
- package/package.json +11 -11
- package/styles/css/insightList.css +6 -2
- package/styles/css/insightList.css.map +1 -1
- package/styles/css/main.css +6 -2
- package/styles/css/main.css.map +1 -1
- package/styles/images/visualization-types/radar-active.svg +7 -0
- package/styles/images/visualization-types/radar.svg +7 -0
- package/styles/scss/insightList.scss +2 -2
|
@@ -25,6 +25,10 @@ export interface IUiControlButtonProps {
|
|
|
25
25
|
buttonRef?: Ref<HTMLDivElement>;
|
|
26
26
|
buttonId?: string;
|
|
27
27
|
dropdownId?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Overrides the accessible name. When omitted, the name is derived from the rendered title.
|
|
30
|
+
*/
|
|
31
|
+
ariaLabel?: string;
|
|
28
32
|
}
|
|
29
33
|
/**
|
|
30
34
|
* Generic chip-shaped dropdown trigger primitive. One source of truth for filter-bar chip
|
|
@@ -36,4 +40,4 @@ export interface IUiControlButtonProps {
|
|
|
36
40
|
*
|
|
37
41
|
* @internal
|
|
38
42
|
*/
|
|
39
|
-
export declare function UiControlButton({ title, titleClassName, subtitle, icon, titleExtension, subtitleExtension, isOpen, isDraggable, isDragging, isError, disabled, disabledTooltip, onClick, className, "data-testid": dataTestId, buttonRef, buttonId, dropdownId }: IUiControlButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
43
|
+
export declare function UiControlButton({ title, titleClassName, subtitle, icon, titleExtension, subtitleExtension, isOpen, isDraggable, isDragging, isError, disabled, disabledTooltip, onClick, className, "data-testid": dataTestId, buttonRef, buttonId, dropdownId, ariaLabel }: IUiControlButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -21,7 +21,7 @@ const TITLE_TOOLTIP_ALIGN_POINTS = [
|
|
|
21
21
|
*
|
|
22
22
|
* @internal
|
|
23
23
|
*/
|
|
24
|
-
export function UiControlButton({ title, titleClassName, subtitle, icon, titleExtension, subtitleExtension, isOpen, isDraggable, isDragging, isError, disabled, disabledTooltip, onClick, className, "data-testid": dataTestId, buttonRef, buttonId, dropdownId, }) {
|
|
24
|
+
export function UiControlButton({ title, titleClassName, subtitle, icon, titleExtension, subtitleExtension, isOpen, isDraggable, isDragging, isError, disabled, disabledTooltip, onClick, className, "data-testid": dataTestId, buttonRef, buttonId, dropdownId, ariaLabel, }) {
|
|
25
25
|
const tooltipId = useIdPrefixed("gd-ui-kit-control-button-tooltip");
|
|
26
26
|
const showDisabledTooltip = !!disabled && !!disabledTooltip;
|
|
27
27
|
const onKeyDown = (event) => {
|
|
@@ -41,7 +41,7 @@ export function UiControlButton({ title, titleClassName, subtitle, icon, titleEx
|
|
|
41
41
|
isDragging: !!isDragging,
|
|
42
42
|
isError: !!isError,
|
|
43
43
|
disabled: !!disabled,
|
|
44
|
-
}), className), role: "button", tabIndex: 0, "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-disabled": disabled, "aria-controls": isOpen ? dropdownId : undefined, "aria-describedby": showDisabledTooltip ? tooltipId : undefined, "data-testid": dataTestId, onClick: disabled ? undefined : onClick, onKeyDown: onKeyDown, children: [icon ? _jsx("div", { className: e("icon"), children: icon }) : null, _jsxs("div", { className: e("content"), children: [
|
|
44
|
+
}), className), role: "button", tabIndex: 0, "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-disabled": disabled, "aria-controls": isOpen ? dropdownId : undefined, "aria-describedby": showDisabledTooltip ? tooltipId : undefined, "aria-label": ariaLabel, "data-testid": dataTestId, onClick: disabled ? undefined : onClick, onKeyDown: onKeyDown, children: [icon ? _jsx("div", { className: e("icon"), children: icon }) : null, _jsxs("div", { className: e("content"), children: [
|
|
45
45
|
_jsxs("div", { className: e("title-row"), children: [
|
|
46
46
|
_jsx("div", { className: e("title"), children: _jsx(ShortenedText, { tooltipAlignPoints: TITLE_TOOLTIP_ALIGN_POINTS, className: titleClassName, children: title }) }), titleExtension] }), subtitle === undefined && subtitleExtension === undefined ? null : (_jsxs("div", { className: e("subtitle-row"), children: [typeof subtitle === "string" ? (_jsx("span", { className: e("subtitle"), children: subtitle })) : (subtitle), subtitleExtension] }))] })
|
|
47
47
|
] }));
|
|
@@ -18,30 +18,86 @@ export const useUiAutofocusConnectors = ({ active = true, refocusKey, initialFoc
|
|
|
18
18
|
setElement(el);
|
|
19
19
|
}
|
|
20
20
|
}, []);
|
|
21
|
-
//
|
|
22
|
-
//
|
|
21
|
+
// Focus the first focusable inside the wrapper. Robust against slow renders, virtualized lists
|
|
22
|
+
// that recycle DOM nodes, and floating overlays that finish positioning after mount.
|
|
23
|
+
//
|
|
24
|
+
// `.focus()` is a no-op on elements that are not currently focusable (e.g. inside an ancestor
|
|
25
|
+
// with `visibility: hidden`, which Overlay applies until alignment completes). The browser
|
|
26
|
+
// does not throw or fire `focusin` in that case. To handle this we watch two signals:
|
|
27
|
+
//
|
|
28
|
+
// - IntersectionObserver observes the resolved TARGET — fires when the target moves into the
|
|
29
|
+
// viewport (e.g. an Overlay completing alignment from off-screen to its real position).
|
|
30
|
+
// This is the moment `.focus()` will start taking.
|
|
31
|
+
// - MutationObserver observes the wrapper — fires on descendant additions/removals
|
|
32
|
+
// (lazy mount, virtualization) and on attribute changes (style/class/inert/hidden/...)
|
|
33
|
+
// that may affect focusability without a position change.
|
|
34
|
+
//
|
|
35
|
+
// Each signal re-runs `attemptFocus`, which re-resolves the target and re-attaches the
|
|
36
|
+
// IntersectionObserver to it. A single rAF coalesces bursts into one attempt per frame.
|
|
23
37
|
useEffect(() => {
|
|
24
|
-
|
|
25
|
-
if (!elementToFocus || !active) {
|
|
38
|
+
if (!element || !active) {
|
|
26
39
|
return undefined;
|
|
27
40
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
let rafId = 0;
|
|
42
|
+
let stopped = false;
|
|
43
|
+
let observedTarget = null;
|
|
44
|
+
const intersectionObserver = new IntersectionObserver(() => {
|
|
45
|
+
scheduleAttempt();
|
|
46
|
+
});
|
|
47
|
+
const observeTarget = (newTarget) => {
|
|
48
|
+
if (newTarget === observedTarget) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (observedTarget) {
|
|
52
|
+
intersectionObserver.unobserve(observedTarget);
|
|
53
|
+
}
|
|
54
|
+
observedTarget = newTarget ?? null;
|
|
55
|
+
if (observedTarget) {
|
|
56
|
+
intersectionObserver.observe(observedTarget);
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const isFocusSettled = () => element.contains(document.activeElement) || isElementTextInput(document.activeElement);
|
|
60
|
+
const attemptFocus = () => {
|
|
61
|
+
if (isFocusSettled()) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
const target = getElementToFocus(element, initialFocus, true);
|
|
65
|
+
// Always (re-)observe the resolved target; the IntersectionObserver wakes us up when
|
|
66
|
+
// it moves into the viewport — the moment `.focus()` will take after Overlay alignment.
|
|
67
|
+
observeTarget(target);
|
|
68
|
+
if (!target?.isConnected) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
target.focus();
|
|
72
|
+
return document.activeElement === target;
|
|
73
|
+
};
|
|
74
|
+
const scheduleAttempt = () => {
|
|
75
|
+
if (stopped) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
cancelAnimationFrame(rafId);
|
|
79
|
+
rafId = requestAnimationFrame(() => {
|
|
80
|
+
if (attemptFocus()) {
|
|
81
|
+
stop();
|
|
40
82
|
}
|
|
41
83
|
});
|
|
84
|
+
};
|
|
85
|
+
const stop = () => {
|
|
86
|
+
stopped = true;
|
|
87
|
+
cancelAnimationFrame(rafId);
|
|
88
|
+
mutationObserver.disconnect();
|
|
89
|
+
intersectionObserver.disconnect();
|
|
90
|
+
};
|
|
91
|
+
const mutationObserver = new MutationObserver(scheduleAttempt);
|
|
92
|
+
mutationObserver.observe(element, {
|
|
93
|
+
childList: true,
|
|
94
|
+
subtree: true,
|
|
95
|
+
attributes: true,
|
|
96
|
+
attributeFilter: ["style", "class", "hidden", "inert", "disabled", "tabindex", "aria-hidden"],
|
|
42
97
|
});
|
|
43
|
-
|
|
44
|
-
|
|
98
|
+
// Initial attempt — fast path when the first focusable is already present and visible.
|
|
99
|
+
scheduleAttempt();
|
|
100
|
+
return stop;
|
|
45
101
|
}, [refocusKey, element, initialFocus, active]);
|
|
46
102
|
return useMemo(() => ({ ref }), [ref]);
|
|
47
103
|
};
|
package/esm/@ui/UiMenu/hooks.js
CHANGED
|
@@ -16,7 +16,7 @@ import { getClosestFocusableSibling, getFocusableItem, getItemInteractiveParent,
|
|
|
16
16
|
* @internal
|
|
17
17
|
*/
|
|
18
18
|
export function useUiMenuContextValue(props, menuComponentRef, itemsContainerRef) {
|
|
19
|
-
const { items, size = "medium", itemDataTestId, onSelect, onLevelChange, onClose, InteractiveItem: InteractiveItemComponent = DefaultUiMenuInteractiveItem, InteractiveItemWrapper: InteractiveItemWrapperComponent = DefaultUiMenuInteractiveItemWrapper, StaticItem: StaticItemComponent = DefaultUiMenuStaticItem, GroupItem: GroupItemComponent = DefaultUiMenuGroupItem, MenuHeader: MenuHeaderComponent = DefaultUiMenuHeader, ContentItem: ContentItemComponent = DefaultUiMenuContentItem, ContentItemWrapper: ContentItemWrapperComponent = DefaultUiMenuContentItemWrapper, Content: ContentComponent = DefaultUiMenuContent, shouldCloseOnSelect = true, isDisabledFocusable = true, ariaAttributes, menuCtxData, } = props;
|
|
19
|
+
const { items, size = "medium", itemDataTestId, onSelect, onLeaveLevel, onEnterLevel, onLevelChange, onClose, InteractiveItem: InteractiveItemComponent = DefaultUiMenuInteractiveItem, InteractiveItemWrapper: InteractiveItemWrapperComponent = DefaultUiMenuInteractiveItemWrapper, StaticItem: StaticItemComponent = DefaultUiMenuStaticItem, GroupItem: GroupItemComponent = DefaultUiMenuGroupItem, MenuHeader: MenuHeaderComponent = DefaultUiMenuHeader, ContentItem: ContentItemComponent = DefaultUiMenuContentItem, ContentItemWrapper: ContentItemWrapperComponent = DefaultUiMenuContentItemWrapper, Content: ContentComponent = DefaultUiMenuContent, shouldCloseOnSelect = true, isDisabledFocusable = true, ariaAttributes, menuCtxData, } = props;
|
|
20
20
|
const [controlType, setControlType] = useState("unknown");
|
|
21
21
|
const isItemFocusable = useCallback((item) => {
|
|
22
22
|
if (!item || (item.type !== "interactive" && item.type !== "content")) {
|
|
@@ -128,6 +128,8 @@ export function useUiMenuContextValue(props, menuComponentRef, itemsContainerRef
|
|
|
128
128
|
items,
|
|
129
129
|
size,
|
|
130
130
|
onSelect: handleSelectItem,
|
|
131
|
+
onLeaveLevel,
|
|
132
|
+
onEnterLevel,
|
|
131
133
|
itemDataTestId,
|
|
132
134
|
isItemFocusable,
|
|
133
135
|
makeItemId,
|
|
@@ -171,6 +173,8 @@ export function useUiMenuContextValue(props, menuComponentRef, itemsContainerRef
|
|
|
171
173
|
shownCustomContentItemId,
|
|
172
174
|
shownSubview,
|
|
173
175
|
size,
|
|
176
|
+
onLeaveLevel,
|
|
177
|
+
onEnterLevel,
|
|
174
178
|
]);
|
|
175
179
|
}
|
|
176
180
|
/**
|
|
@@ -222,7 +226,10 @@ export function useKeyNavigation({ menuContextValue, shouldKeyboardActionPrevent
|
|
|
222
226
|
onSelect(focusedItem, e);
|
|
223
227
|
},
|
|
224
228
|
onEnterLevel: (e) => {
|
|
225
|
-
const { onSelect, focusedItem } = menuContextRef.current;
|
|
229
|
+
const { onSelect, onEnterLevel, focusedItem } = menuContextRef.current;
|
|
230
|
+
if (onEnterLevel?.(focusedItem, e)) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
226
233
|
if ((focusedItem?.type !== "interactive" && focusedItem?.type !== "content") ||
|
|
227
234
|
(focusedItem?.type === "interactive" && !focusedItem.subItems) ||
|
|
228
235
|
(focusedItem?.type === "content" && !focusedItem.Component)) {
|
|
@@ -230,8 +237,11 @@ export function useKeyNavigation({ menuContextValue, shouldKeyboardActionPrevent
|
|
|
230
237
|
}
|
|
231
238
|
onSelect(focusedItem, e);
|
|
232
239
|
},
|
|
233
|
-
onLeaveLevel: () => {
|
|
234
|
-
const { setFocusedId, items } = menuContextRef.current;
|
|
240
|
+
onLeaveLevel: (e) => {
|
|
241
|
+
const { setFocusedId, onLeaveLevel, focusedItem, items } = menuContextRef.current;
|
|
242
|
+
if (onLeaveLevel?.(focusedItem, e)) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
235
245
|
setFocusedId((prevId) => {
|
|
236
246
|
if (prevId === undefined) {
|
|
237
247
|
return prevId;
|
|
@@ -156,6 +156,8 @@ export interface IUiMenuContext<T extends IUiMenuItemData = object, M = object>
|
|
|
156
156
|
pushShownSubview: (subview: IUiMenuSubview) => void;
|
|
157
157
|
popShownSubview: () => void;
|
|
158
158
|
onSelect: (item: IUiMenuFocusableItem<T> | undefined, event: MouseEvent | KeyboardEvent) => void;
|
|
159
|
+
onEnterLevel?: (item: IUiMenuFocusableItem<T> | undefined, event: MouseEvent | KeyboardEvent) => boolean;
|
|
160
|
+
onLeaveLevel?: (item: IUiMenuFocusableItem<T> | undefined, event: MouseEvent | KeyboardEvent) => boolean;
|
|
159
161
|
onClose?: () => void;
|
|
160
162
|
setFocusedId: Dispatch<SetStateAction<string | undefined>>;
|
|
161
163
|
isItemFocusable: (item: IUiMenuItem<T>) => boolean;
|
|
@@ -187,6 +189,8 @@ export interface IUiMenuProps<T extends IUiMenuItemData = object, M = object> ex
|
|
|
187
189
|
containerBottomPadding?: "none" | "small" | "medium";
|
|
188
190
|
containerTopPadding?: "none" | "small" | "medium";
|
|
189
191
|
onSelect?: (item: IUiMenuInteractiveItem<T>, event: MouseEvent | KeyboardEvent) => void;
|
|
192
|
+
onEnterLevel?: (item: IUiMenuFocusableItem<T> | undefined, event: MouseEvent | KeyboardEvent) => boolean;
|
|
193
|
+
onLeaveLevel?: (item: IUiMenuFocusableItem<T> | undefined, event: MouseEvent | KeyboardEvent) => boolean;
|
|
190
194
|
onLevelChange?: (level: number, item?: IUiMenuContentItem<T> | IUiMenuInteractiveItem<T>) => void;
|
|
191
195
|
onClose?: () => void;
|
|
192
196
|
onUnhandledKeyDown?: (event: KeyboardEvent, context: IUiMenuContext<T>) => void;
|
|
@@ -40,7 +40,7 @@ export interface IUiPagedVirtualListProps<T> {
|
|
|
40
40
|
children: (item: T, focusedIndex?: number) => ReactNode;
|
|
41
41
|
scrollbarHoverEffect?: boolean;
|
|
42
42
|
SkeletonItem?: ComponentType<IUiPagedVirtualListSkeletonItemProps>;
|
|
43
|
-
representAs?: "grid" | "listbox";
|
|
43
|
+
representAs?: "grid" | "listbox" | "list";
|
|
44
44
|
listboxProps?: Record<string, any>;
|
|
45
45
|
tabIndex?: number;
|
|
46
46
|
focusedItem?: T;
|
|
@@ -67,11 +67,15 @@ function UiPagedVirtualListNotWrapped(props, ref) {
|
|
|
67
67
|
height: `${rowVirtualizer.getTotalSize()}px`,
|
|
68
68
|
width: "100%",
|
|
69
69
|
position: "relative",
|
|
70
|
-
}, tabIndex:
|
|
70
|
+
}, tabIndex: representAs === "list" ? undefined : tabIndex, onFocus: representAs === "list" ? undefined : onFocus, onKeyDown: representAs === "list" || tabIndex < 0
|
|
71
|
+
? undefined
|
|
72
|
+
: (customKeyboardNavigationHandler ?? onKeyboardNavigation), role: representAs === "grid"
|
|
71
73
|
? "rowgroup"
|
|
72
74
|
: representAs === "listbox"
|
|
73
75
|
? "listbox"
|
|
74
|
-
:
|
|
76
|
+
: representAs === "list"
|
|
77
|
+
? "list"
|
|
78
|
+
: undefined, ...listboxProps, children: virtualItems.map((virtualRow) => {
|
|
75
79
|
const item = items?.[virtualRow.index];
|
|
76
80
|
const isSkeletonItem = virtualRow.index > itemsCount - 1;
|
|
77
81
|
const baseItemHeight = virtualRow.index >= itemsCount
|
|
@@ -97,7 +101,9 @@ function UiPagedVirtualListNotWrapped(props, ref) {
|
|
|
97
101
|
? makeId?.({ item, specifier: SELECT_ITEM_ACTION })
|
|
98
102
|
: undefined,
|
|
99
103
|
}
|
|
100
|
-
:
|
|
104
|
+
: representAs === "list"
|
|
105
|
+
? { role: "listitem" }
|
|
106
|
+
: {};
|
|
101
107
|
return (_jsxs(ItemElement, { className: e("item", {
|
|
102
108
|
isFocused: !customKeyboardNavigationHandler &&
|
|
103
109
|
finalFocusedIndex === virtualRow.index,
|
|
@@ -2,4 +2,4 @@ import { type IShareDialogProps } from "./types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* @internal
|
|
4
4
|
*/
|
|
5
|
-
export declare function ShareDialog({ backend, workspace, locale, sharedObject, currentUser, onApply, onCancel, onError, onInteraction, isLockingSupported, isCurrentUserWorkspaceManager, isGranteeShareLoading, labels, currentUserPermissions, dashboardFilters, isShareGrantHidden, applyShareGrantOnSelect, showDashboardShareLink, onShareLinkCopy }: IShareDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function ShareDialog({ backend, workspace, locale, sharedObject, currentUser, onApply, onCancel, onError, onInteraction, isLockingSupported, isCurrentUserWorkspaceManager, isGranteeShareLoading, labels, currentUserPermissions, dashboardFilters, dashboardParameters, isShareGrantHidden, applyShareGrantOnSelect, showDashboardShareLink, onShareLinkCopy }: IShareDialogProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
// (C) 2021-
|
|
2
|
+
// (C) 2021-2026 GoodData Corporation
|
|
3
3
|
import { useCallback, useMemo } from "react";
|
|
4
4
|
import { BackendProvider, IntlWrapper, UnexpectedSdkError, WorkspaceProvider, useBackendStrict, useWorkspaceStrict, } from "@gooddata/sdk-ui";
|
|
5
5
|
import { ComponentInteractionProvider } from "./ShareDialogBase/ComponentInteractionContext.js";
|
|
@@ -9,7 +9,7 @@ import { mapGranteesToGranularAccessGrantees, mapGranteesToShareStatus, mapOwner
|
|
|
9
9
|
/**
|
|
10
10
|
* @internal
|
|
11
11
|
*/
|
|
12
|
-
export function ShareDialog({ backend, workspace, locale, sharedObject, currentUser, onApply, onCancel, onError, onInteraction = () => { }, isLockingSupported, isCurrentUserWorkspaceManager, isGranteeShareLoading, labels, currentUserPermissions, dashboardFilters, isShareGrantHidden, applyShareGrantOnSelect, showDashboardShareLink, onShareLinkCopy, }) {
|
|
12
|
+
export function ShareDialog({ backend, workspace, locale, sharedObject, currentUser, onApply, onCancel, onError, onInteraction = () => { }, isLockingSupported, isCurrentUserWorkspaceManager, isGranteeShareLoading, labels, currentUserPermissions, dashboardFilters, dashboardParameters, isShareGrantHidden, applyShareGrantOnSelect, showDashboardShareLink, onShareLinkCopy, }) {
|
|
13
13
|
const effectiveBackend = useBackendStrict(backend);
|
|
14
14
|
const effectiveWorkspace = useWorkspaceStrict(workspace);
|
|
15
15
|
const areGranularPermissionsSupported = effectiveBackend.capabilities.supportsGranularAccessControl;
|
|
@@ -54,5 +54,5 @@ export function ShareDialog({ backend, workspace, locale, sharedObject, currentU
|
|
|
54
54
|
isMetadataObjectLockingSupported,
|
|
55
55
|
canWorkspaceManagerSeeEverySharedObject,
|
|
56
56
|
]);
|
|
57
|
-
return (_jsx(IntlWrapper, { locale: locale, children: _jsx(BackendProvider, { backend: effectiveBackend, children: _jsx(WorkspaceProvider, { workspace: effectiveWorkspace, children: _jsx(ComponentLabelsProvider, { labels: labels, children: _jsx(ComponentInteractionProvider, { onInteraction: onInteraction, currentUser: currentUser, currentUserPermissions: currentUserPermissions, isCurrentUserWorkspaceManager: isCurrentUserWorkspaceManager, sharedObjectStatus: affectedSharedObject.shareStatus, isSharedObjectLocked: affectedSharedObject.isLocked, children: _jsx(ShareDialogBase, { currentUser: currentUser, sharedObject: affectedSharedObject, isCurrentUserWorkspaceManager: isCurrentUserWorkspaceManager, currentUserPermissions: currentUserPermissions, dashboardFilters: dashboardFilters, onCancel: onCancel, onSubmit: onSubmit, onError: onShareDialogBaseError, isShareGrantHidden: isShareGrantHidden, applyShareGrantOnSelect: applyShareGrantOnSelect, showDashboardShareLink: showDashboardShareLink, onShareLinkCopy: onShareLinkCopy, isGranteeShareLoading: isGranteeShareLoading }) }) }) }) }) }));
|
|
57
|
+
return (_jsx(IntlWrapper, { locale: locale, children: _jsx(BackendProvider, { backend: effectiveBackend, children: _jsx(WorkspaceProvider, { workspace: effectiveWorkspace, children: _jsx(ComponentLabelsProvider, { labels: labels, children: _jsx(ComponentInteractionProvider, { onInteraction: onInteraction, currentUser: currentUser, currentUserPermissions: currentUserPermissions, isCurrentUserWorkspaceManager: isCurrentUserWorkspaceManager, sharedObjectStatus: affectedSharedObject.shareStatus, isSharedObjectLocked: affectedSharedObject.isLocked, children: _jsx(ShareDialogBase, { currentUser: currentUser, sharedObject: affectedSharedObject, isCurrentUserWorkspaceManager: isCurrentUserWorkspaceManager, currentUserPermissions: currentUserPermissions, dashboardFilters: dashboardFilters, dashboardParameters: dashboardParameters, onCancel: onCancel, onSubmit: onSubmit, onError: onShareDialogBaseError, isShareGrantHidden: isShareGrantHidden, applyShareGrantOnSelect: applyShareGrantOnSelect, showDashboardShareLink: showDashboardShareLink, onShareLinkCopy: onShareLinkCopy, isGranteeShareLoading: isGranteeShareLoading }) }) }) }) }) }));
|
|
58
58
|
}
|
|
@@ -11,7 +11,7 @@ const alignPoints = [{ align: "cc cc" }];
|
|
|
11
11
|
* @internal
|
|
12
12
|
*/
|
|
13
13
|
export function ShareDialogBase(props) {
|
|
14
|
-
const { onCancel, sharedObject, currentUser, currentUserPermissions, dashboardFilters, isCurrentUserWorkspaceManager, isShareGrantHidden, applyShareGrantOnSelect, showDashboardShareLink, isGranteeShareLoading, onShareLinkCopy, } = props;
|
|
14
|
+
const { onCancel, sharedObject, currentUser, currentUserPermissions, dashboardFilters, dashboardParameters, isCurrentUserWorkspaceManager, isShareGrantHidden, applyShareGrantOnSelect, showDashboardShareLink, isGranteeShareLoading, onShareLinkCopy, } = props;
|
|
15
15
|
const { openInteraction, closeInteraction } = useShareDialogInteraction();
|
|
16
16
|
useEffect(() => {
|
|
17
17
|
openInteraction();
|
|
@@ -22,5 +22,5 @@ export function ShareDialogBase(props) {
|
|
|
22
22
|
}, [onCancel, closeInteraction]);
|
|
23
23
|
const { onAddedGranteeDelete, onSharedGranteeDelete, onAddGranteeBackClick, onAddGranteeButtonClick, onGranteeAdd, onSubmitShareGrantee, onSubmitAddGrantee, granteesToAdd, dialogMode, isShareDialogDirty, isAddDialogDirty, sharedGrantees, appliedGranteesWithOwner, isGranteesLoading, isLockedNow, isUnderLenientControlNow, onLockChange, onUnderLenientControlChange, onGranularGranteeAddChange, onGranularGranteeShareChange, } = useShareDialogBase(props);
|
|
24
24
|
const previouslyFocusedRef = useRef(document.activeElement);
|
|
25
|
-
return (_jsx(Overlay, { alignPoints: alignPoints, isModal: true, positionType: "fixed", className: "gd-share-dialog-overlay", children: _jsx("div", { className: "s-gd-share-dialog", children: dialogMode === "ShareGrantee" ? (_jsx(ShareGranteeBase, { currentUserPermissions: currentUserPermissions, dashboardFilters: dashboardFilters, isShareGrantHidden: isShareGrantHidden, applyShareGrantOnSelect: applyShareGrantOnSelect, showDashboardShareLink: showDashboardShareLink, onShareLinkCopy: onShareLinkCopy, isGranteeShareLoading: isGranteeShareLoading, isLoading: isGranteesLoading, isDirty: isShareDialogDirty, isLockedNow: isLockedNow, isUnderLenientControlNow: isUnderLenientControlNow, sharedObject: sharedObject, grantees: sharedGrantees, onCancel: handleCancel, onSubmit: onSubmitShareGrantee, onAddGranteeButtonClick: onAddGranteeButtonClick, onGranteeDelete: onSharedGranteeDelete, onLockChange: onLockChange, onUnderLenientControlChange: onUnderLenientControlChange, onGranularGranteeChange: onGranularGranteeShareChange, isCurrentUserWorkspaceManager: isCurrentUserWorkspaceManager })) : (_jsx(AddGranteeBase, { currentUserPermissions: currentUserPermissions, isDirty: isAddDialogDirty, currentUser: currentUser, appliedGrantees: appliedGranteesWithOwner, addedGrantees: granteesToAdd, sharedObject: sharedObject, previouslyFocusedRef: previouslyFocusedRef, onAddUserOrGroups: onGranteeAdd, onDelete: onAddedGranteeDelete, onCancel: handleCancel, onSubmit: onSubmitAddGrantee, onBackClick: onAddGranteeBackClick, onGranularGranteeChange: onGranularGranteeAddChange, isGranteeShareLoading: isGranteeShareLoading })) }) }));
|
|
25
|
+
return (_jsx(Overlay, { alignPoints: alignPoints, isModal: true, positionType: "fixed", className: "gd-share-dialog-overlay", children: _jsx("div", { className: "s-gd-share-dialog", children: dialogMode === "ShareGrantee" ? (_jsx(ShareGranteeBase, { currentUserPermissions: currentUserPermissions, dashboardFilters: dashboardFilters, dashboardParameters: dashboardParameters, isShareGrantHidden: isShareGrantHidden, applyShareGrantOnSelect: applyShareGrantOnSelect, showDashboardShareLink: showDashboardShareLink, onShareLinkCopy: onShareLinkCopy, isGranteeShareLoading: isGranteeShareLoading, isLoading: isGranteesLoading, isDirty: isShareDialogDirty, isLockedNow: isLockedNow, isUnderLenientControlNow: isUnderLenientControlNow, sharedObject: sharedObject, grantees: sharedGrantees, onCancel: handleCancel, onSubmit: onSubmitShareGrantee, onAddGranteeButtonClick: onAddGranteeButtonClick, onGranteeDelete: onSharedGranteeDelete, onLockChange: onLockChange, onUnderLenientControlChange: onUnderLenientControlChange, onGranularGranteeChange: onGranularGranteeShareChange, isCurrentUserWorkspaceManager: isCurrentUserWorkspaceManager })) : (_jsx(AddGranteeBase, { currentUserPermissions: currentUserPermissions, isDirty: isAddDialogDirty, currentUser: currentUser, appliedGrantees: appliedGranteesWithOwner, addedGrantees: granteesToAdd, sharedObject: sharedObject, previouslyFocusedRef: previouslyFocusedRef, onAddUserOrGroups: onGranteeAdd, onDelete: onAddedGranteeDelete, onCancel: handleCancel, onSubmit: onSubmitAddGrantee, onBackClick: onAddGranteeBackClick, onGranularGranteeChange: onGranularGranteeAddChange, isGranteeShareLoading: isGranteeShareLoading })) }) }));
|
|
26
26
|
}
|
|
@@ -2,4 +2,4 @@ import { type IShareGranteeBaseProps } from "./types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* @internal
|
|
4
4
|
*/
|
|
5
|
-
export declare function ShareGranteeBase({ isLoading, isLockedNow, isUnderLenientControlNow, grantees, sharedObject, isDirty, currentUserPermissions, dashboardFilters, isShareGrantHidden, applyShareGrantOnSelect, showDashboardShareLink, isGranteeShareLoading, onCancel, onSubmit, onGranteeDelete, onGranularGranteeChange, onAddGranteeButtonClick, onLockChange, onUnderLenientControlChange, isCurrentUserWorkspaceManager, onShareLinkCopy }: IShareGranteeBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function ShareGranteeBase({ isLoading, isLockedNow, isUnderLenientControlNow, grantees, sharedObject, isDirty, currentUserPermissions, dashboardFilters, dashboardParameters, isShareGrantHidden, applyShareGrantOnSelect, showDashboardShareLink, isGranteeShareLoading, onCancel, onSubmit, onGranteeDelete, onGranularGranteeChange, onAddGranteeButtonClick, onLockChange, onUnderLenientControlChange, isCurrentUserWorkspaceManager, onShareLinkCopy }: IShareGranteeBaseProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -14,7 +14,7 @@ import { ADD_GRANTEE_ID } from "./utils.js";
|
|
|
14
14
|
/**
|
|
15
15
|
* @internal
|
|
16
16
|
*/
|
|
17
|
-
export function ShareGranteeBase({ isLoading, isLockedNow, isUnderLenientControlNow, grantees, sharedObject, isDirty, currentUserPermissions, dashboardFilters, isShareGrantHidden, applyShareGrantOnSelect, showDashboardShareLink, isGranteeShareLoading, onCancel, onSubmit, onGranteeDelete, onGranularGranteeChange, onAddGranteeButtonClick, onLockChange, onUnderLenientControlChange, isCurrentUserWorkspaceManager, onShareLinkCopy, }) {
|
|
17
|
+
export function ShareGranteeBase({ isLoading, isLockedNow, isUnderLenientControlNow, grantees, sharedObject, isDirty, currentUserPermissions, dashboardFilters, dashboardParameters, isShareGrantHidden, applyShareGrantOnSelect, showDashboardShareLink, isGranteeShareLoading, onCancel, onSubmit, onGranteeDelete, onGranularGranteeChange, onAddGranteeButtonClick, onLockChange, onUnderLenientControlChange, isCurrentUserWorkspaceManager, onShareLinkCopy, }) {
|
|
18
18
|
const { owner, isLeniencyControlSupported, isLockingSupported, areGranularPermissionsSupported, isMetadataObjectLockingSupported, isLocked, canWorkspaceManagerSeeEverySharedObject, } = sharedObject;
|
|
19
19
|
const intl = useIntl();
|
|
20
20
|
const granteeList = useMemo(() => {
|
|
@@ -42,5 +42,5 @@ export function ShareGranteeBase({ isLoading, isLockedNow, isUnderLenientControl
|
|
|
42
42
|
}, [intl, showDashboardShareLink, applyShareGrantOnSelect, isUsingTabs]);
|
|
43
43
|
const shouldDisplayAdminMessage = useMemo(() => canWorkspaceManagerSeeEverySharedObject && isCurrentUserWorkspaceManager && !isLoading, [canWorkspaceManagerSeeEverySharedObject, isCurrentUserWorkspaceManager, isLoading]);
|
|
44
44
|
return (_jsxs(ConfirmDialogBase, { className: "gd-share-dialog s-gd-share-grantees", displayCloseButton: true, isPositive: true, isSubmitDisabled: !isDirty, headline: dialogLabels.headline, cancelButtonText: dialogLabels.cancelButtonText, submitButtonText: dialogLabels.submitButtonText, onCancel: onCancel, onSubmit: onSubmit, hideSubmitButton: applyShareGrantOnSelect, initialFocus: ADD_GRANTEE_ID, children: [
|
|
45
|
-
_jsx(AdminInformationMessage, { isVisible: shouldDisplayAdminMessage ?? false }), isShareGrantHidden ? null : (_jsx(ShareGranteeContent, { currentUserPermissions: currentUserPermissions, isSharedObjectLocked: isLocked, isLoading: isLoading, grantees: granteeList, areGranularPermissionsSupported: areGranularPermissionsSupported, onAddGrantee: onAddGranteeButtonClick, onDelete: onGranteeDelete, onChange: onGranularGranteeChange, isGranteeShareLoading: isGranteeShareLoading, applyShareGrantOnSelect: !!applyShareGrantOnSelect, headline: dialogLabels.shareGrantHeadline })), showDashboardShareLink ? (_jsx(ShareLink, { dashboardFilters: dashboardFilters, onShareLinkCopy: onShareLinkCopy, headline: dialogLabels.linkHeadline, helperText: dialogLabels.linkHelperText, buttonLabel: dialogLabels.linkButtonLabel })) : null, _jsx(ContentDivider, { className: "gd-share-dialog-content-divider" }), _jsx(SharedObjectUnderLenientControl, { isUnderLenientControl: isUnderLenientControlNow, isLeniencyControlSupported: isLeniencyControlSupported, onUnderLenientControlChange: onUnderLenientControlChange }), isMetadataObjectLockingSupported ? (_jsx(SharedObjectLockControl, { isLocked: isLockedNow, isLockingSupported: isLockingSupported, onLockChange: onLockChange })) : null] }));
|
|
45
|
+
_jsx(AdminInformationMessage, { isVisible: shouldDisplayAdminMessage ?? false }), isShareGrantHidden ? null : (_jsx(ShareGranteeContent, { currentUserPermissions: currentUserPermissions, isSharedObjectLocked: isLocked, isLoading: isLoading, grantees: granteeList, areGranularPermissionsSupported: areGranularPermissionsSupported, onAddGrantee: onAddGranteeButtonClick, onDelete: onGranteeDelete, onChange: onGranularGranteeChange, isGranteeShareLoading: isGranteeShareLoading, applyShareGrantOnSelect: !!applyShareGrantOnSelect, headline: dialogLabels.shareGrantHeadline })), showDashboardShareLink ? (_jsx(ShareLink, { dashboardFilters: dashboardFilters, dashboardParameters: dashboardParameters, onShareLinkCopy: onShareLinkCopy, headline: dialogLabels.linkHeadline, helperText: dialogLabels.linkHelperText, buttonLabel: dialogLabels.linkButtonLabel })) : null, _jsx(ContentDivider, { className: "gd-share-dialog-content-divider" }), _jsx(SharedObjectUnderLenientControl, { isUnderLenientControl: isUnderLenientControlNow, isLeniencyControlSupported: isLeniencyControlSupported, onUnderLenientControlChange: onUnderLenientControlChange }), isMetadataObjectLockingSupported ? (_jsx(SharedObjectLockControl, { isLocked: isLockedNow, isLockingSupported: isLockingSupported, onLockChange: onLockChange })) : null] }));
|
|
46
46
|
}
|
|
@@ -2,4 +2,4 @@ import { type IShareLinkProps } from "./types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* @internal
|
|
4
4
|
*/
|
|
5
|
-
export declare function ShareLink({ dashboardFilters, headline, helperText, buttonLabel, onShareLinkCopy }: IShareLinkProps): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
export declare function ShareLink({ dashboardFilters, dashboardParameters, headline, helperText, buttonLabel, onShareLinkCopy }: IShareLinkProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -9,16 +9,21 @@ import { SHARE_LINK_HEADLINE_ID, SHARE_LINK_HELPER_TEXT_ID } from "./utils.js";
|
|
|
9
9
|
/**
|
|
10
10
|
* @internal
|
|
11
11
|
*/
|
|
12
|
-
export function ShareLink({ dashboardFilters, headline, helperText, buttonLabel, onShareLinkCopy, }) {
|
|
12
|
+
export function ShareLink({ dashboardFilters, dashboardParameters, headline, helperText, buttonLabel, onShareLinkCopy, }) {
|
|
13
13
|
const shareLink = useMemo(() => {
|
|
14
|
-
const
|
|
14
|
+
const queryParams = {
|
|
15
|
+
filters: compressForUrl(dashboardFilters ?? []),
|
|
16
|
+
};
|
|
17
|
+
if (dashboardParameters?.length) {
|
|
18
|
+
queryParams["parameters"] = compressForUrl(dashboardParameters);
|
|
19
|
+
}
|
|
15
20
|
const url = window.location.origin;
|
|
16
21
|
const hashLocation = window.location.hash.split("?")[0];
|
|
17
22
|
return url
|
|
18
23
|
.concat("/dashboards/")
|
|
19
24
|
.concat(hashLocation)
|
|
20
|
-
.concat(`?${new URLSearchParams(
|
|
21
|
-
}, [dashboardFilters]);
|
|
25
|
+
.concat(`?${new URLSearchParams(queryParams).toString()}`);
|
|
26
|
+
}, [dashboardFilters, dashboardParameters]);
|
|
22
27
|
const onIconButtonClick = useCallback(() => {
|
|
23
28
|
onShareLinkCopy?.(shareLink);
|
|
24
29
|
}, [shareLink, onShareLinkCopy]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type MutableRefObject, type ReactNode } from "react";
|
|
2
|
-
import { type AccessGranularPermission, type FilterContextItem, type IUser, type ObjRef, type ShareStatus } from "@gooddata/sdk-model";
|
|
2
|
+
import { type AccessGranularPermission, type FilterContextItem, type IDashboardParameter, type IUser, type ObjRef, type ShareStatus } from "@gooddata/sdk-model";
|
|
3
3
|
import { type CurrentUserPermissions, type IShareDialogLabels } from "../types.js";
|
|
4
4
|
/**
|
|
5
5
|
* @internal
|
|
@@ -159,6 +159,7 @@ export interface IShareDialogBaseProps {
|
|
|
159
159
|
currentUser: IUser;
|
|
160
160
|
currentUserPermissions: CurrentUserPermissions;
|
|
161
161
|
dashboardFilters?: FilterContextItem[];
|
|
162
|
+
dashboardParameters?: IDashboardParameter[];
|
|
162
163
|
isShareGrantHidden?: boolean;
|
|
163
164
|
applyShareGrantOnSelect?: boolean;
|
|
164
165
|
showDashboardShareLink?: boolean;
|
|
@@ -195,6 +196,7 @@ export interface IShareGranteeBaseProps {
|
|
|
195
196
|
isCurrentUserWorkspaceManager: boolean;
|
|
196
197
|
currentUserPermissions: CurrentUserPermissions;
|
|
197
198
|
dashboardFilters?: FilterContextItem[];
|
|
199
|
+
dashboardParameters?: IDashboardParameter[];
|
|
198
200
|
isShareGrantHidden?: boolean;
|
|
199
201
|
applyShareGrantOnSelect?: boolean;
|
|
200
202
|
showDashboardShareLink?: boolean;
|
|
@@ -277,6 +279,7 @@ export interface IGranteesListProps {
|
|
|
277
279
|
*/
|
|
278
280
|
export interface IShareLinkProps {
|
|
279
281
|
dashboardFilters?: FilterContextItem[];
|
|
282
|
+
dashboardParameters?: IDashboardParameter[];
|
|
280
283
|
headline: string;
|
|
281
284
|
helperText: string;
|
|
282
285
|
buttonLabel: string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type IAnalyticalBackend } from "@gooddata/sdk-backend-spi";
|
|
2
|
-
import { type AccessGranularPermission, type FilterContextItem, type IAccessControlAware, type IAccessGrantee, type IAuditableUsers, type IUser, type ObjRef, type ShareStatus } from "@gooddata/sdk-model";
|
|
2
|
+
import { type AccessGranularPermission, type FilterContextItem, type IAccessControlAware, type IAccessGrantee, type IAuditableUsers, type IDashboardParameter, type IUser, type ObjRef, type ShareStatus } from "@gooddata/sdk-model";
|
|
3
3
|
import { type GoodDataSdkError } from "@gooddata/sdk-ui";
|
|
4
4
|
/**
|
|
5
5
|
* @internal
|
|
@@ -50,6 +50,7 @@ export interface IShareDialogProps {
|
|
|
50
50
|
labels: IShareDialogLabels;
|
|
51
51
|
currentUserPermissions: CurrentUserPermissions;
|
|
52
52
|
dashboardFilters?: FilterContextItem[];
|
|
53
|
+
dashboardParameters?: IDashboardParameter[];
|
|
53
54
|
isGranteeShareLoading?: boolean;
|
|
54
55
|
isShareGrantHidden?: boolean;
|
|
55
56
|
applyShareGrantOnSelect?: boolean;
|
|
@@ -82,13 +82,21 @@ export function DropdownList({ id, title, className = "", tabsClassName = "", wi
|
|
|
82
82
|
? Math.max(mobileItemHeight, itemHeight)
|
|
83
83
|
: itemHeight;
|
|
84
84
|
const effectiveMaxHeight = maxHeight || listHeight || 300;
|
|
85
|
-
return (_jsx("div", { "data-testid": "gd-dropdown-list", id: id, style: { width: listWidth }, className: listClassNames, role: accessibilityConfig?.role === "listbox"
|
|
85
|
+
return (_jsx("div", { "data-testid": "gd-dropdown-list", id: id, style: { width: listWidth }, className: listClassNames, role: accessibilityConfig?.role === "listbox" ||
|
|
86
|
+
accessibilityConfig?.role === "list"
|
|
86
87
|
? undefined
|
|
87
|
-
: accessibilityConfig?.role, "aria-label": accessibilityConfig?.role === "listbox"
|
|
88
|
+
: accessibilityConfig?.role, "aria-label": accessibilityConfig?.role === "listbox" ||
|
|
89
|
+
accessibilityConfig?.role === "list"
|
|
88
90
|
? undefined
|
|
89
|
-
: accessibilityConfig?.ariaLabel, "aria-labelledby": accessibilityConfig?.role === "listbox"
|
|
91
|
+
: accessibilityConfig?.ariaLabel, "aria-labelledby": accessibilityConfig?.role === "listbox" ||
|
|
92
|
+
accessibilityConfig?.role === "list"
|
|
90
93
|
? undefined
|
|
91
|
-
: accessibilityConfig?.ariaLabelledBy, children: _jsx(UiPagedVirtualList, { maxHeight: effectiveMaxHeight, items: items, itemHeight: effectiveItemHeight, itemsGap: 0, itemPadding: 0, containerPadding: containerPadding, onKeyDownSelect: onKeyDownSelect, onKeyDownConfirm: onKeyDownConfirm, closeDropdown: closeDropdown, itemHeightGetter: itemHeightGetter, hasNextPage: hasNextPage, loadNextPage: loadNextPage, skeletonItemsCount: skeletonItemsCount, SkeletonItem: SkeletonItem, shouldLoadNextPage: shouldLoadNextPage, isLoading: isNextPageLoading, onScroll: onScroll, scrollToItem: scrollToItem, scrollToItemKeyExtractor: scrollToItemKeyExtractor, representAs: accessibilityConfig?.role === "listbox"
|
|
94
|
+
: accessibilityConfig?.ariaLabelledBy, children: _jsx(UiPagedVirtualList, { maxHeight: effectiveMaxHeight, items: items, itemHeight: effectiveItemHeight, itemsGap: 0, itemPadding: 0, containerPadding: containerPadding, onKeyDownSelect: onKeyDownSelect, onKeyDownConfirm: onKeyDownConfirm, closeDropdown: closeDropdown, itemHeightGetter: itemHeightGetter, hasNextPage: hasNextPage, loadNextPage: loadNextPage, skeletonItemsCount: skeletonItemsCount, SkeletonItem: SkeletonItem, shouldLoadNextPage: shouldLoadNextPage, isLoading: isNextPageLoading, onScroll: onScroll, scrollToItem: scrollToItem, scrollToItemKeyExtractor: scrollToItemKeyExtractor, representAs: accessibilityConfig?.role === "listbox"
|
|
95
|
+
? "listbox"
|
|
96
|
+
: accessibilityConfig?.role === "list"
|
|
97
|
+
? "list"
|
|
98
|
+
: undefined, listboxProps: accessibilityConfig?.role === "listbox" ||
|
|
99
|
+
accessibilityConfig?.role === "list"
|
|
92
100
|
? {
|
|
93
101
|
"aria-label": accessibilityConfig?.ariaLabel,
|
|
94
102
|
"aria-labelledby": accessibilityConfig?.ariaLabelledBy,
|
|
@@ -27,11 +27,18 @@ export function FilterGroupItem({ title, subtitle, selectedItemsCount, totalItem
|
|
|
27
27
|
}
|
|
28
28
|
const tooltipId = useIdPrefixed("filter-group-item-locked-tooltip");
|
|
29
29
|
const onKeyDown = useCallback((event) => {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
// <div role="button"> doesn't reliably fire click on Enter/Space across browsers and
|
|
31
|
+
// AT modes (ARIA APG requires manual handling). Dispatch onClick ourselves.
|
|
32
|
+
if (!isActionKey(event)) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
event.preventDefault();
|
|
36
|
+
event.stopPropagation();
|
|
37
|
+
if (disabled) {
|
|
38
|
+
return;
|
|
33
39
|
}
|
|
34
|
-
|
|
40
|
+
onClick?.();
|
|
41
|
+
}, [disabled, onClick]);
|
|
35
42
|
const handleButtonRef = useCallback((element) => {
|
|
36
43
|
if (!buttonRef) {
|
|
37
44
|
return;
|
|
@@ -57,7 +64,7 @@ export function FilterGroupItem({ title, subtitle, selectedItemsCount, totalItem
|
|
|
57
64
|
"gd-is-active": isOpen,
|
|
58
65
|
"gd-is-loaded": isLoaded,
|
|
59
66
|
"gd-is-disabled": disabled,
|
|
60
|
-
}), "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-describedby": disabled ? tooltipId : undefined, "aria-disabled": disabled, onClick: disabled ? undefined : onClick, onKeyDown: onKeyDown, "aria-controls": isOpen ? dropdownId : undefined, role: "button", tabIndex:
|
|
67
|
+
}), "aria-haspopup": "dialog", "aria-expanded": isOpen, "aria-describedby": disabled ? tooltipId : undefined, "aria-disabled": disabled, onClick: disabled ? undefined : onClick, onKeyDown: onKeyDown, "aria-controls": isOpen ? dropdownId : undefined, role: "button", tabIndex: 0, ref: handleButtonRef, "data-testid": `s-filter-group-item-${simplifyText(title ?? null)}`, children: [isError || icon ? (_jsx("div", { className: "gd-filter-group-item-icon", children: isError ? _jsx(UiIcon, { type: "crossCircle", size: 12, color: "currentColor" }) : icon })) : null, _jsxs("div", { className: "gd-filter-group-item-body", children: [
|
|
61
68
|
_jsxs("div", { className: "gd-filter-group-item-content", children: [
|
|
62
69
|
_jsxs("div", { className: "gd-filter-group-item-title-content", children: [
|
|
63
70
|
_jsx("div", { className: "gd-filter-group-item-title", children: _jsx(ShortenedText, { tooltipAlignPoints: ALIGN_POINT, "data-testid": "s-filter-group-item-title", ellipsisPosition: "end", children: `${buttonTitle}` }) }), _jsx("div", { className: "gd-filter-group-item-title-extension", children: titleExtension })
|
|
@@ -71,7 +71,7 @@ function createInsightsItemsGroup(featureFlags, workspaceId, workspacePermission
|
|
|
71
71
|
pushConditionally(insightItemsGroup, createIHeaderMenuItem(HEADER_ITEM_ID_METRICS, "s-menu-metrics", measuresUrl), canShowMetricsItem(hasMeasures, workspacePermissions));
|
|
72
72
|
const dataUrl = dataItemUrl(workspaceId, workspacePermissions, backendSupportsDataItem, hasNoDataSet, baseUrl);
|
|
73
73
|
pushConditionally(insightItemsGroup, createIHeaderMenuItem(HEADER_ITEM_ID_DATA, "s-menu-data", dataUrl), canShowDataItem(featureFlags, workspacePermissions));
|
|
74
|
-
pushConditionally(insightItemsGroup, createIHeaderMenuItem(HEADER_ITEM_ID_CATALOG, "s-menu-workspace-catalog", catalogItemUrl(workspaceId), true), canShowCatalogItem(featureFlags, workspacePermissions));
|
|
74
|
+
pushConditionally(insightItemsGroup, createIHeaderMenuItem(HEADER_ITEM_ID_CATALOG, "s-menu-workspace-catalog", catalogItemUrl(workspaceId, featureFlags), true), canShowCatalogItem(featureFlags, workspacePermissions));
|
|
75
75
|
const loadUrl = loadItemUrl(baseUrl, workspaceId);
|
|
76
76
|
pushConditionally(insightItemsGroup, createIHeaderMenuItem(HEADER_ITEM_ID_LOAD, "s-menu-load", loadUrl), canShowLoadItem(featureFlags, workspacePermissions, isFreemiumCustomer, backendSupportsCsvUploader));
|
|
77
77
|
return insightItemsGroup;
|
|
@@ -90,7 +90,15 @@ function pushConditionally(items, item, cond) {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
const withBaseUrl = (baseUrl, uri) => `${baseUrl.endsWith("/") ? baseUrl.substring(0, baseUrl.length - 2) : baseUrl}${uri}`;
|
|
93
|
-
function catalogItemUrl(workspaceId) {
|
|
93
|
+
function catalogItemUrl(workspaceId, featureFlags) {
|
|
94
|
+
// When the host app and the catalog pluggable-app migration are both on,
|
|
95
|
+
// link directly to the singular host route. Otherwise fall back to the
|
|
96
|
+
// legacy plural URL owned by gdc-home-ui, which re-redirects to the host
|
|
97
|
+
// route on arrival. Skipping the indirection avoids a double redirect when
|
|
98
|
+
// switching from Dashboards/Analyze/Metrics/Data to Catalog. See LX-2426.
|
|
99
|
+
if (featureFlags.enableShellApplication && featureFlags.enableShellApplication_catalog) {
|
|
100
|
+
return `/workspace/${workspaceId}/catalog`;
|
|
101
|
+
}
|
|
94
102
|
return `/workspaces/${workspaceId}/catalog`;
|
|
95
103
|
}
|
|
96
104
|
function canShowCatalogItem(featureFlags, workspacePermissions) {
|
package/esm/Icon/Icon.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// (C) 2021-
|
|
1
|
+
// (C) 2021-2026 GoodData Corporation
|
|
2
2
|
import { Aborted } from "./icons/Aborted.js";
|
|
3
3
|
import { Alert } from "./icons/Alert.js";
|
|
4
4
|
import { AlertPaused } from "./icons/AlertPaused.js";
|
|
@@ -59,6 +59,7 @@ import { HeatMap } from "./icons/InsightIcons/HeatMap.js";
|
|
|
59
59
|
import { Line } from "./icons/InsightIcons/Line.js";
|
|
60
60
|
import { Pie } from "./icons/InsightIcons/Pie.js";
|
|
61
61
|
import { Pyramid } from "./icons/InsightIcons/Pyramid.js";
|
|
62
|
+
import { Radar } from "./icons/InsightIcons/Radar.js";
|
|
62
63
|
import { Repeater } from "./icons/InsightIcons/Repeater.js";
|
|
63
64
|
import { Sankey } from "./icons/InsightIcons/Sankey.js";
|
|
64
65
|
import { ScatterPlot } from "./icons/InsightIcons/ScatterPlot.js";
|
|
@@ -185,6 +186,7 @@ export const Icon = {
|
|
|
185
186
|
Run,
|
|
186
187
|
Invite,
|
|
187
188
|
Pyramid,
|
|
189
|
+
Radar,
|
|
188
190
|
Funnel,
|
|
189
191
|
RichText,
|
|
190
192
|
VisualizationSwitcher,
|
package/esm/Icon/InsightIcon.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// (C) 2022-
|
|
1
|
+
// (C) 2022-2026 GoodData Corporation
|
|
2
2
|
import { Icon } from "./Icon.js";
|
|
3
3
|
const INSIGHT_ICON_MAP = {
|
|
4
4
|
"local:scatter": Icon["ScatterPlot"],
|
|
@@ -20,6 +20,7 @@ const INSIGHT_ICON_MAP = {
|
|
|
20
20
|
"local:dependencywheel": Icon["DependencyWheel"],
|
|
21
21
|
"local:funnel": Icon["Funnel"],
|
|
22
22
|
"local:pyramid": Icon["Pyramid"],
|
|
23
|
+
"local:radar": Icon["Radar"],
|
|
23
24
|
"local:waterfall": Icon["Waterfall"],
|
|
24
25
|
"local:repeater": Icon["Repeater"],
|
|
25
26
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { combineIconClasses } from "../../utils.js";
|
|
3
|
+
/**
|
|
4
|
+
* @internal
|
|
5
|
+
*/
|
|
6
|
+
export function Radar({ className, width, height, color, ariaHidden }) {
|
|
7
|
+
return (_jsxs("svg", { width: width ?? 32, height: height ?? 30, className: combineIconClasses(className), viewBox: "0 0 32 30", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": ariaHidden, children: [
|
|
8
|
+
_jsx("path", { d: "M14.4122 15.4619L9.40442 22.4717C7.31888 20.639 6.0011 17.9536 6.0011 14.959C6.0011 14.1517 6.0988 13.3672 6.27942 12.6152L14.4122 15.4619Z", fill: color ?? "#B0BECA", fillOpacity: "0.6" }), _jsx("path", { d: "M17.0011 4.00488C21.0165 4.36689 24.4069 6.887 26.0089 10.3965L17.0011 13.5488V4.00488Z", fill: color ?? "#B0BECA", fillOpacity: "0.6" }), _jsx("path", { d: "M15.0011 13.5488L5.04504 10.0645C6.78918 6.16628 10.5491 3.36728 15.0011 3V13.5488Z", fill: color ?? "#B0BECA" }), _jsx("path", { d: "M24.7734 12.9201C24.9196 13.5616 25 14.2285 25 14.9142C25 17.5737 23.8441 19.9605 22.0098 21.6076L17.5889 15.4191L24.7734 12.9201Z", fill: color ?? "#B0BECA" }), _jsx("path", { d: "M22.1359 25.2676C20.3405 26.3395 18.2441 26.959 16.0011 26.959C13.7577 26.959 11.66 26.3406 9.86438 25.2686L16.0011 16.6787L22.1359 25.2676Z", fill: color ?? "#B0BECA", fillOpacity: "0.4" })
|
|
9
|
+
] }));
|
|
10
|
+
}
|
package/esm/index.d.ts
CHANGED
|
@@ -233,6 +233,7 @@ export { HeatMap as IconHeatMap } from "./Icon/icons/InsightIcons/HeatMap.js";
|
|
|
233
233
|
export { Line as IconLine } from "./Icon/icons/InsightIcons/Line.js";
|
|
234
234
|
export { Pie as IconPie } from "./Icon/icons/InsightIcons/Pie.js";
|
|
235
235
|
export { Pyramid as IconPyramid } from "./Icon/icons/InsightIcons/Pyramid.js";
|
|
236
|
+
export { Radar as IconRadar } from "./Icon/icons/InsightIcons/Radar.js";
|
|
236
237
|
export { Repeater as IconRepeater } from "./Icon/icons/InsightIcons/Repeater.js";
|
|
237
238
|
export { Sankey as IconSankey } from "./Icon/icons/InsightIcons/Sankey.js";
|
|
238
239
|
export { ScatterPlot as IconScatterPlot } from "./Icon/icons/InsightIcons/ScatterPlot.js";
|
package/esm/index.js
CHANGED
|
@@ -220,6 +220,7 @@ export { HeatMap as IconHeatMap } from "./Icon/icons/InsightIcons/HeatMap.js";
|
|
|
220
220
|
export { Line as IconLine } from "./Icon/icons/InsightIcons/Line.js";
|
|
221
221
|
export { Pie as IconPie } from "./Icon/icons/InsightIcons/Pie.js";
|
|
222
222
|
export { Pyramid as IconPyramid } from "./Icon/icons/InsightIcons/Pyramid.js";
|
|
223
|
+
export { Radar as IconRadar } from "./Icon/icons/InsightIcons/Radar.js";
|
|
223
224
|
export { Repeater as IconRepeater } from "./Icon/icons/InsightIcons/Repeater.js";
|
|
224
225
|
export { Sankey as IconSankey } from "./Icon/icons/InsightIcons/Sankey.js";
|
|
225
226
|
export { ScatterPlot as IconScatterPlot } from "./Icon/icons/InsightIcons/ScatterPlot.js";
|