@gooddata/sdk-ui-kit 11.53.0-alpha.5 → 11.53.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.
@@ -23,6 +23,8 @@ export interface IUiGranteeRowControlsProps {
23
23
  disabledLevels?: ReadonlyArray<PermissionMenuLevel>;
24
24
  /** Tooltip shown on disabled level rows in place of the level's info text. */
25
25
  disabledTooltip?: string;
26
+ /** Per-level override of `disabledTooltip` — see {@link UiPermissionMenu}. */
27
+ disabledLevelTooltips?: Partial<Record<PermissionMenuLevel, string>>;
26
28
  onLabelsChange: (selectedIds: string[]) => void;
27
29
  onPermissionChange: (level: PermissionMenuLevel) => void;
28
30
  onRemoveAccess?: () => void;
@@ -44,5 +46,5 @@ export interface IUiGranteeRowControlsProps {
44
46
  *
45
47
  * @internal
46
48
  */
47
- export declare function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel, effectivePermission, disabledLevels, disabledTooltip, onLabelsChange, onPermissionChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, isDisabled, dataTestId }: IUiGranteeRowControlsProps): import("react/jsx-runtime").JSX.Element;
49
+ export declare function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel, effectivePermission, disabledLevels, disabledTooltip, disabledLevelTooltips, onLabelsChange, onPermissionChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, isDisabled, dataTestId }: IUiGranteeRowControlsProps): import("react/jsx-runtime").JSX.Element;
48
50
  //# sourceMappingURL=UiGranteeRowControls.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UiGranteeRowControls.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiGranteeRowControls/UiGranteeRowControls.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAMpE,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACxF,OAAO,EACH,KAAK,mBAAmB,EAG3B,MAAM,yCAAyC,CAAC;AAcjD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,mDAAmD;IACnD,MAAM,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC9C,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,8EAA4E;IAC5E,eAAe,EAAE,wBAAwB,CAAC;IAC1C;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;IAC/C,wFAAsF;IACtF,cAAc,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACpD,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,2DAA2D;IAC3D,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,MAAM,EACN,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,UAAU,EACV,UAAU,EACb,EAAE,0BAA0B,2CAwD5B"}
1
+ {"version":3,"file":"UiGranteeRowControls.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiGranteeRowControls/UiGranteeRowControls.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,wBAAwB,EAAE,MAAM,qBAAqB,CAAC;AAMpE,OAAO,EAAE,KAAK,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AACxF,OAAO,EACH,KAAK,mBAAmB,EAG3B,MAAM,yCAAyC,CAAC;AAcjD;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACvC,mDAAmD;IACnD,MAAM,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC9C,gBAAgB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACxC,8EAA4E;IAC5E,eAAe,EAAE,wBAAwB,CAAC;IAC1C;;;;;;;OAOG;IACH,mBAAmB,CAAC,EAAE,wBAAwB,CAAC;IAC/C,wFAAsF;IACtF,cAAc,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACpD,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gFAA8E;IAC9E,qBAAqB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC,CAAC;IACrE,cAAc,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAChD,kBAAkB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,2DAA2D;IAC3D,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,MAAM,EACN,gBAAgB,EAChB,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,UAAU,EACV,UAAU,EACb,EAAE,0BAA0B,2CAyD5B"}
@@ -23,7 +23,7 @@ const EFFECTIVE_PERMISSION_TOOLTIP = {
23
23
  *
24
24
  * @internal
25
25
  */
26
- export function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel, effectivePermission, disabledLevels, disabledTooltip, onLabelsChange, onPermissionChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, isDisabled, dataTestId, }) {
26
+ export function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel, effectivePermission, disabledLevels, disabledTooltip, disabledLevelTooltips, onLabelsChange, onPermissionChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, isDisabled, dataTestId, }) {
27
27
  const intl = useIntl();
28
28
  const hasLabels = labels.length > 0;
29
29
  // The caller decides when inheritance drives the row (see the prop's contract) —
@@ -32,6 +32,6 @@ export function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel
32
32
  const effectiveTooltip = inheritedTooltipMessage
33
33
  ? intl.formatMessage(inheritedTooltipMessage)
34
34
  : undefined;
35
- return (_jsxs("div", { className: b(), "data-testid": dataTestId, children: [effectiveTooltip ? (_jsx(UiTooltip, { triggerBy: ["hover", "focus"], content: effectiveTooltip, anchor: _jsx("span", { className: e("effective-warning"), role: "img", "aria-label": intl.formatMessage(olpPermissionMessages.effectivePermissionAriaLabel), tabIndex: 0, children: _jsx(UiIcon, { type: "warning", size: 16, color: "warning" }) }) })) : null, _jsx(UiPermissionMenu, { anchor: _jsx(UiButton, { label: intl.formatMessage(permissionLevelMessage(permissionLevel)), size: "small", variant: "dropdownInline", iconAfter: "navigateDown", isDisabled: isDisabled }), selectedLevel: permissionLevel, onPermissionChange: onPermissionChange, disabledLevels: disabledLevels, disabledTooltip: disabledTooltip, labels: hasLabels ? labels : undefined, selectedLabelIds: selectedLabelIds, onLabelsChange: onLabelsChange, onRemoveAccess: onRemoveAccess, isRemoveDisabled: isRemoveDisabled, removeDisabledTooltip: removeDisabledTooltip })
35
+ return (_jsxs("div", { className: b(), "data-testid": dataTestId, children: [effectiveTooltip ? (_jsx(UiTooltip, { triggerBy: ["hover", "focus"], content: effectiveTooltip, anchor: _jsx("span", { className: e("effective-warning"), role: "img", "aria-label": intl.formatMessage(olpPermissionMessages.effectivePermissionAriaLabel), tabIndex: 0, children: _jsx(UiIcon, { type: "warning", size: 16, color: "warning" }) }) })) : null, _jsx(UiPermissionMenu, { anchor: _jsx(UiButton, { label: intl.formatMessage(permissionLevelMessage(permissionLevel)), size: "small", variant: "dropdownInline", iconAfter: "navigateDown", isDisabled: isDisabled }), selectedLevel: permissionLevel, onPermissionChange: onPermissionChange, disabledLevels: disabledLevels, disabledTooltip: disabledTooltip, disabledLevelTooltips: disabledLevelTooltips, labels: hasLabels ? labels : undefined, selectedLabelIds: selectedLabelIds, onLabelsChange: onLabelsChange, onRemoveAccess: onRemoveAccess, isRemoveDisabled: isRemoveDisabled, removeDisabledTooltip: removeDisabledTooltip })
36
36
  ] }));
37
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"DefaultUiListboxInteractiveItemComponent.d.ts","sourceRoot":"","sources":["../../../../src/@ui/UiListbox/defaults/DefaultUiListboxInteractiveItemComponent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,OAAO,EAAE,KAAK,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAElE;;GAEG;AACH,wBAAgB,wCAAwC,CAAC,CAAC,EAAE,EACxD,IAAI,EACJ,SAAS,EACT,UAAU,EACV,SAAS,EACT,QAAQ,EACX,EAAE,8BAA8B,CAAC,CAAC,CAAC,GAAG,SAAS,CAgC/C"}
1
+ {"version":3,"file":"DefaultUiListboxInteractiveItemComponent.d.ts","sourceRoot":"","sources":["../../../../src/@ui/UiListbox/defaults/DefaultUiListboxInteractiveItemComponent.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAMvC,OAAO,EAAE,KAAK,8BAA8B,EAAE,MAAM,aAAa,CAAC;AAElE;;GAEG;AACH,wBAAgB,wCAAwC,CAAC,CAAC,EAAE,EACxD,IAAI,EACJ,SAAS,EACT,UAAU,EACV,SAAS,EACT,QAAQ,EACX,EAAE,8BAA8B,CAAC,CAAC,CAAC,GAAG,SAAS,CAuC/C"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { ShortenedText } from "../../../ShortenedText/ShortenedText.js";
3
3
  import { UiIcon } from "../../UiIcon/UiIcon.js";
4
4
  import { UiTooltip } from "../../UiTooltip/UiTooltip.js";
@@ -12,5 +12,7 @@ export function DefaultUiListboxInteractiveItemComponent({ item, isFocused, isSe
12
12
  isSelected,
13
13
  isCompact,
14
14
  isDisabled: !!item.isDisabled,
15
- }), onClick: item.isDisabled ? undefined : onSelect, children: [item.icon ? _jsx(UiIcon, { type: item.icon, size: 14, color: "complementary-7" }) : null, _jsx(ShortenedText, { className: e("item-title"), ellipsisPosition: "end", children: item.stringTitle }), item.tooltip ? (_jsx(UiTooltip, { anchor: _jsx("div", { className: e("item-explanation"), children: _jsx(UiIcon, { type: "question", size: 14, color: "complementary-7" }) }), content: item.tooltip, triggerBy: ["hover", "focus"], arrowPlacement: "left", optimalPlacement: true, width: 200, offset: 10 })) : null] }));
15
+ }), onClick: item.isDisabled ? undefined : onSelect, children: [item.icon ? _jsx(UiIcon, { type: item.icon, size: 14, color: "complementary-7" }) : null, _jsx(ShortenedText, { className: e("item-title"), ellipsisPosition: "end", children: item.stringTitle }), item.tooltip ? (_jsxs(_Fragment, { children: [
16
+ _jsx(UiTooltip, { anchor: _jsx("div", { className: e("item-explanation"), children: _jsx(UiIcon, { type: "question", size: 14, color: "complementary-7" }) }), content: item.tooltip, triggerBy: ["hover"], accessibilityHidden: true, arrowPlacement: "left", optimalPlacement: true, width: 200, offset: 10 }), _jsx("span", { className: "sr-only", children: item.tooltip })
17
+ ] })) : null] }));
16
18
  }
@@ -33,6 +33,11 @@ export interface IUiPermissionMenuProps {
33
33
  disabledLevels?: ReadonlyArray<PermissionMenuLevel>;
34
34
  /** Tooltip shown on disabled level rows in place of the level's info text. */
35
35
  disabledTooltip?: string;
36
+ /**
37
+ * Per-level override of `disabledTooltip`, for menus whose disabled levels have
38
+ * different reasons (capped by the caller's own level vs. already inherited).
39
+ */
40
+ disabledLevelTooltips?: Partial<Record<PermissionMenuLevel, string>>;
36
41
  /**
37
42
  * Non-empty enables a labels row that drills into {@link UiLabelsChecklist}
38
43
  * within the menu — for rows whose menu hosts every action (no "⋯" menu).
@@ -64,5 +69,5 @@ export interface IUiPermissionMenuProps {
64
69
  *
65
70
  * @internal
66
71
  */
67
- export declare function UiPermissionMenu({ anchor, selectedLevel, onPermissionChange, disabledLevels, disabledTooltip, labels, selectedLabelIds, onLabelsChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, dataTestId }: IUiPermissionMenuProps): import("react/jsx-runtime").JSX.Element;
72
+ export declare function UiPermissionMenu({ anchor, selectedLevel, onPermissionChange, disabledLevels, disabledTooltip, disabledLevelTooltips, labels, selectedLabelIds, onLabelsChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, dataTestId }: IUiPermissionMenuProps): import("react/jsx-runtime").JSX.Element;
68
73
  //# sourceMappingURL=UiPermissionMenu.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"UiPermissionMenu.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiPermissionMenu/UiPermissionMenu.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,YAAY,EAAiC,MAAM,OAAO,CAAC;AAE7F,OAAO,EAAE,KAAK,iBAAiB,EAAW,MAAM,YAAY,CAAC;AAO7D,OAAO,EAAE,KAAK,sBAAsB,EAAqB,MAAM,2CAA2C,CAAC;AAM3G;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAQ5D;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,mBAAmB,GAAG,iBAAiB,CAEpF;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,4CAA4C;IAC5C,MAAM,EAAE,YAAY,CAAC;IACrB,qEAAmE;IACnE,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,oDAAoD;IACpD,kBAAkB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD;;;OAGG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACpD,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC/C,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,2DAA2D;IAC3D,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAsBD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,EAC7B,MAAM,EACN,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,UAAU,EACb,EAAE,sBAAsB,2CAyBxB"}
1
+ {"version":3,"file":"UiPermissionMenu.d.ts","sourceRoot":"","sources":["../../../src/@ui/UiPermissionMenu/UiPermissionMenu.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAsB,KAAK,YAAY,EAAiC,MAAM,OAAO,CAAC;AAE7F,OAAO,EAAE,KAAK,iBAAiB,EAAW,MAAM,YAAY,CAAC;AAO7D,OAAO,EAAE,KAAK,sBAAsB,EAAqB,MAAM,2CAA2C,CAAC;AAM3G;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAC;AAQ5D;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,mBAAmB,GAAG,iBAAiB,CAEpF;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,4CAA4C;IAC5C,MAAM,EAAE,YAAY,CAAC;IACrB,qEAAmE;IACnE,aAAa,CAAC,EAAE,mBAAmB,CAAC;IACpC,oDAAoD;IACpD,kBAAkB,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACzD;;;OAGG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IACpD,8EAA8E;IAC9E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC,CAAC;IACrE;;;OAGG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAC;IAC/C,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACzC,uEAAuE;IACvE,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,2DAA2D;IAC3D,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,0CAA0C;IAC1C,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAsBD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,EAC7B,MAAM,EACN,aAAa,EACb,kBAAkB,EAClB,cAAc,EACd,eAAe,EACf,qBAAqB,EACrB,MAAM,EACN,gBAAgB,EAChB,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,UAAU,EACb,EAAE,sBAAsB,2CA0BxB"}
@@ -33,11 +33,11 @@ export function permissionLevelMessage(level) {
33
33
  *
34
34
  * @internal
35
35
  */
36
- export function UiPermissionMenu({ anchor, selectedLevel, onPermissionChange, disabledLevels, disabledTooltip, labels, selectedLabelIds, onLabelsChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, dataTestId, }) {
36
+ export function UiPermissionMenu({ anchor, selectedLevel, onPermissionChange, disabledLevels, disabledTooltip, disabledLevelTooltips, labels, selectedLabelIds, onLabelsChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, dataTestId, }) {
37
37
  const hasLabels = (labels?.length ?? 0) > 0;
38
- return (_jsx(UiPopover, { anchor: anchor, anchorAccessibilityConfig: { ariaHaspopup: "menu" }, width: hasLabels ? 200 : 180, content: ({ onClose }) => (_jsx(MenuBody, { selectedLevel: selectedLevel, onPermissionChange: onPermissionChange, disabledLevels: disabledLevels, disabledTooltip: disabledTooltip, labels: labels, selectedLabelIds: selectedLabelIds, onLabelsChange: onLabelsChange, onRemoveAccess: onRemoveAccess, isRemoveDisabled: isRemoveDisabled, removeDisabledTooltip: removeDisabledTooltip, onClose: onClose, dataTestId: dataTestId })) }));
38
+ return (_jsx(UiPopover, { anchor: anchor, anchorAccessibilityConfig: { ariaHaspopup: "menu" }, width: hasLabels ? 200 : 180, content: ({ onClose }) => (_jsx(MenuBody, { selectedLevel: selectedLevel, onPermissionChange: onPermissionChange, disabledLevels: disabledLevels, disabledTooltip: disabledTooltip, disabledLevelTooltips: disabledLevelTooltips, labels: labels, selectedLabelIds: selectedLabelIds, onLabelsChange: onLabelsChange, onRemoveAccess: onRemoveAccess, isRemoveDisabled: isRemoveDisabled, removeDisabledTooltip: removeDisabledTooltip, onClose: onClose, dataTestId: dataTestId })) }));
39
39
  }
40
- function MenuBody({ selectedLevel, onPermissionChange, disabledLevels, disabledTooltip, labels, selectedLabelIds, onLabelsChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, onClose, dataTestId, }) {
40
+ function MenuBody({ selectedLevel, onPermissionChange, disabledLevels, disabledTooltip, disabledLevelTooltips, labels, selectedLabelIds, onLabelsChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, onClose, dataTestId, }) {
41
41
  const intl = useIntl();
42
42
  // Drill-in state — swaps the row list for the labels checklist. Local to the
43
43
  // popover content, so it resets every time the menu opens. `origin` is what
@@ -60,7 +60,8 @@ function MenuBody({ selectedLevel, onPermissionChange, disabledLevels, disabledT
60
60
  key: level,
61
61
  label,
62
62
  // A disabled level explains why it can't be picked instead of what it does.
63
- tooltip: disabled && disabledTooltip ? disabledTooltip : tooltip,
63
+ // `||`, not `??`: an empty explanation must not suppress the info button.
64
+ tooltip: disabled ? (disabledLevelTooltips?.[level] ?? disabledTooltip) || tooltip : tooltip,
64
65
  radioValue: level,
65
66
  disabled,
66
67
  onClick: disabled ? () => { } : choose(() => onPermissionChange(level)),
@@ -3,7 +3,7 @@ import { type IUiListboxItem } from "../@ui/UiListbox/types.js";
3
3
  import { type IDropdownButtonRenderProps } from "../Dropdown/Dropdown.js";
4
4
  /**
5
5
  * Special item rendered above the divider in {@link TimezoneSelect}, ahead of the curated
6
- * timezone list. Callers use these for entries like "Default (workspace)" or "From browser (...)".
6
+ * timezone list. Callers use these for entries like "Default" or "Device time zone".
7
7
  *
8
8
  * @internal
9
9
  */
@@ -34,7 +34,7 @@ export interface ITimezoneSelectSpecialItem {
34
34
  export interface ITimezoneSelectButtonRenderProps extends IDropdownButtonRenderProps {
35
35
  /**
36
36
  * Human-readable label of the current selection: the matching special item label,
37
- * the selected timezone as "name (offset)" (e.g. "Prague (GMT+01:00)"),
37
+ * the friendly name of the selected timezone (e.g. "Prague"),
38
38
  * or the placeholder when nothing is selected.
39
39
  */
40
40
  buttonLabel: string;
@@ -78,6 +78,16 @@ export interface ITimezoneSelectProps {
78
78
  * Accessibility label of the search input and the listbox.
79
79
  */
80
80
  ariaLabel: string;
81
+ /**
82
+ * Id of the default dropdown trigger, so a visible `<label htmlFor>` can be associated
83
+ * with it. Ignored when a custom trigger is rendered via `renderButton`.
84
+ */
85
+ id?: string;
86
+ /**
87
+ * Ids of elements describing the default dropdown trigger (`aria-describedby`), e.g. an
88
+ * adjacent hint text. Ignored when a custom trigger is rendered via `renderButton`.
89
+ */
90
+ ariaDescribedBy?: string;
81
91
  /**
82
92
  * Label shown when the search yields no results.
83
93
  */
@@ -107,10 +117,10 @@ export declare function buildListboxItems(specialItems: ITimezoneSelectSpecialIt
107
117
  export declare function getSelectedItemId(value: string | undefined, specialItems: ITimezoneSelectSpecialItem[]): string | undefined;
108
118
  /**
109
119
  * Searchable dropdown for picking a timezone from the curated list, with optional special
110
- * items (e.g. "Default (workspace)", "From browser (...)") rendered above a divider.
120
+ * items (e.g. "Default", "Device time zone") rendered above a divider.
111
121
  *
112
122
  * @internal
113
123
  */
114
- export declare function TimezoneSelect({ value, onChange, specialItems, placeholder, searchPlaceholder, ariaLabel, noMatchLabel, isDisabled, header, showTooltip, renderButton }: ITimezoneSelectProps): ReactElement;
124
+ export declare function TimezoneSelect({ value, onChange, specialItems, placeholder, searchPlaceholder, ariaLabel, id, ariaDescribedBy, noMatchLabel, isDisabled, header, showTooltip, renderButton }: ITimezoneSelectProps): ReactElement;
115
125
  export {};
116
126
  //# sourceMappingURL=TimezoneSelect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TimezoneSelect.d.ts","sourceRoot":"","sources":["../../src/Timezone/TimezoneSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;AAE7E,OAAO,EAAkC,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhG,OAAO,EAAY,KAAK,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAapF;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;OAGG;IACH,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IAEvB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gCAAiC,SAAQ,0BAA0B;IAChF;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACjC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAE3C;;OAEG;IACH,YAAY,CAAC,EAAE,0BAA0B,EAAE,CAAC;IAE5C;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,gCAAgC,KAAK,SAAS,CAAC;CACzE;AAED,KAAK,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAAC;AAM/C,wBAAgB,iBAAiB,CAC7B,YAAY,EAAE,0BAA0B,EAAE,EAC1C,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,OAAO,GACrB,cAAc,CAAC,oBAAoB,CAAC,EAAE,CAqCxC;AAGD,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,YAAY,EAAE,0BAA0B,EAAE,GAC3C,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,YAAiB,EACjB,WAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,UAAU,EACV,MAAM,EACN,WAAmB,EACnB,YAAY,EACf,EAAE,oBAAoB,GAAG,YAAY,CAiGrC"}
1
+ {"version":3,"file":"TimezoneSelect.d.ts","sourceRoot":"","sources":["../../src/Timezone/TimezoneSelect.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,SAAS,EAAqB,MAAM,OAAO,CAAC;AAE7E,OAAO,EAAkC,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAMhG,OAAO,EAAY,KAAK,0BAA0B,EAAE,MAAM,yBAAyB,CAAC;AAapF;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;OAGG;IACH,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IAEvB;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gCAAiC,SAAQ,0BAA0B;IAChF;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAE1B;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACjC;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAE3C;;OAEG;IACH,YAAY,CAAC,EAAE,0BAA0B,EAAE,CAAC;IAE5C;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,iBAAiB,EAAE,MAAM,CAAC;IAE1B;;OAEG;IACH,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,EAAE,CAAC,EAAE,MAAM,CAAC;IAEZ;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,MAAM,CAAC,EAAE,SAAS,CAAC;IAEnB;;OAEG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,gCAAgC,KAAK,SAAS,CAAC;CACzE;AAED,KAAK,oBAAoB,GAAG,MAAM,GAAG,SAAS,CAAC;AAM/C,wBAAgB,iBAAiB,CAC7B,YAAY,EAAE,0BAA0B,EAAE,EAC1C,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,OAAO,GACrB,cAAc,CAAC,oBAAoB,CAAC,EAAE,CAqCxC;AAGD,wBAAgB,iBAAiB,CAC7B,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,YAAY,EAAE,0BAA0B,EAAE,GAC3C,MAAM,GAAG,SAAS,CAMpB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,EAC3B,KAAK,EACL,QAAQ,EACR,YAAiB,EACjB,WAAgB,EAChB,iBAAiB,EACjB,SAAS,EACT,EAAE,EACF,eAAe,EACf,YAAY,EACZ,UAAU,EACV,MAAM,EACN,WAAmB,EACnB,YAAY,EACf,EAAE,oBAAoB,GAAG,YAAY,CAsHrC"}
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  // (C) 2026 GoodData Corporation
3
3
  import { useMemo, useState } from "react";
4
4
  import { UiListbox } from "../@ui/UiListbox/UiListbox.js";
5
+ import { DETAILED_ANNOUNCEMENT_THRESHOLD, UiSearchResultsAnnouncement, } from "../@ui/UiSearchResultsAnnouncement/UiSearchResultsAnnouncement.js";
5
6
  import { Dropdown } from "../Dropdown/Dropdown.js";
6
7
  import { DropdownButton } from "../Dropdown/DropdownButton.js";
7
8
  import { Input } from "../Form/Input.js";
@@ -59,11 +60,11 @@ export function getSelectedItemId(value, specialItems) {
59
60
  }
60
61
  /**
61
62
  * Searchable dropdown for picking a timezone from the curated list, with optional special
62
- * items (e.g. "Default (workspace)", "From browser (...)") rendered above a divider.
63
+ * items (e.g. "Default", "Device time zone") rendered above a divider.
63
64
  *
64
65
  * @internal
65
66
  */
66
- export function TimezoneSelect({ value, onChange, specialItems = [], placeholder = "", searchPlaceholder, ariaLabel, noMatchLabel, isDisabled, header, showTooltip = false, renderButton, }) {
67
+ export function TimezoneSelect({ value, onChange, specialItems = [], placeholder = "", searchPlaceholder, ariaLabel, id, ariaDescribedBy, noMatchLabel, isDisabled, header, showTooltip = false, renderButton, }) {
67
68
  const [searchString, setSearchString] = useState("");
68
69
  const selectedSpecialItem = specialItems.find((item) => item.id === value);
69
70
  const buttonLabel = selectedSpecialItem
@@ -73,12 +74,16 @@ export function TimezoneSelect({ value, onChange, specialItems = [], placeholder
73
74
  : getTimezoneDisplayLabel(value);
74
75
  const items = useMemo(() => buildListboxItems(specialItems, searchString, showTooltip), [specialItems, searchString, showTooltip]);
75
76
  const hasNoMatchingData = items.length === 0;
77
+ // items may contain a separator between special items and the timezone list; only the
78
+ // interactive entries are search results worth announcing
79
+ const interactiveItems = useMemo(() => items.filter((item) => item.type === "interactive"), [items]);
76
80
  return (_jsx(Dropdown, { closeOnParentScroll: true, closeOnOutsideClick: true, alignPoints: DROPDOWN_ALIGN_POINTS, className: "gd-timezone-select s-timezone-select", onOpenStateChanged: (isOpen) => {
77
81
  if (!isOpen) {
78
82
  setSearchString("");
79
83
  }
80
- }, renderButton: (renderProps) => renderButton ? (renderButton({ ...renderProps, buttonLabel, value, isDisabled })) : (_jsx(DropdownButton, { value: buttonLabel, isOpen: renderProps.isOpen, onClick: renderProps.toggleDropdown, disabled: isDisabled, dropdownId: renderProps.dropdownId, buttonRef: renderProps.buttonRef, accessibilityConfig: {
84
+ }, renderButton: (renderProps) => renderButton ? (renderButton({ ...renderProps, buttonLabel, value, isDisabled })) : (_jsx(DropdownButton, { value: buttonLabel, isOpen: renderProps.isOpen, onClick: renderProps.toggleDropdown, disabled: isDisabled, id: id, dropdownId: renderProps.dropdownId, buttonRef: renderProps.buttonRef, accessibilityConfig: {
81
85
  ariaLabel,
86
+ ariaDescribedBy,
82
87
  ariaExpanded: renderProps.isOpen,
83
88
  popupType: "listbox",
84
89
  }, className: "gd-timezone-select__button s-timezone-select-button customizable" })), renderBody: ({ closeDropdown, ariaAttributes }) => (_jsxs("div", { className: "gd-timezone-select__body s-timezone-select-body", children: [header, _jsx("div", { className: "gd-timezone-select__search s-timezone-select-search", children: _jsx(Input, { value: searchString, onChange: (newValue) => setSearchString(newValue.toString()), placeholder: searchPlaceholder, autofocus: true, clearOnEsc: true, isSearch: true, isSmall: true, onEscKeyPress: (event) => {
@@ -90,7 +95,9 @@ export function TimezoneSelect({ value, onChange, specialItems = [], placeholder
90
95
  }
91
96
  }, accessibilityConfig: {
92
97
  ariaLabel,
93
- } }) }), hasNoMatchingData ? (_jsx(NoData, { hasNoMatchingData: true, notFoundLabel: noMatchLabel, noDataLabel: noMatchLabel })) : (_jsx(UiListbox
98
+ } }) }), _jsx(UiSearchResultsAnnouncement, { totalResults: searchString ? interactiveItems.length : undefined, resultValues: interactiveItems.length <= DETAILED_ANNOUNCEMENT_THRESHOLD
99
+ ? interactiveItems.map((item) => item.stringTitle)
100
+ : undefined }), hasNoMatchingData ? (_jsx(NoData, { hasNoMatchingData: true, notFoundLabel: noMatchLabel, noDataLabel: noMatchLabel })) : (_jsx(UiListbox
94
101
  // remount when the filter changes so the focused index cannot point
95
102
  // past the end of a shortened result list, which would break keyboard selection
96
103
  , { width: DROPDOWN_BODY_WIDTH, maxHeight: LIST_MAX_HEIGHT, items: items, selectedItemId: getSelectedItemId(value, specialItems), onSelect: (item) => {
@@ -54,9 +54,8 @@ export declare function getTimezoneById(id: string | undefined): ITimezoneItem |
54
54
  */
55
55
  export declare function getUserTimezone(): ITimezoneItem;
56
56
  /**
57
- * Returns the display label used by the timezone picker: the friendly name with the GMT offset
58
- * as a suffix in brackets, e.g. "Prague (GMT+01:00)". The name falls back to the raw IANA ID
59
- * for zones outside the curated list, and the offset suffix is dropped when not known.
57
+ * Returns the display label used by the timezone picker: the friendly name, e.g. "Prague".
58
+ * The name falls back to the raw IANA ID for zones outside the curated list.
60
59
  *
61
60
  * The friendly name (not the IANA ID) is shown so the picker reads the same as the Home UI
62
61
  * timezone settings — the id-to-name mapping is not visible to users anywhere.
@@ -66,7 +65,7 @@ export declare function getUserTimezone(): ITimezoneItem;
66
65
  export declare function getTimezoneDisplayLabel(id: string): string;
67
66
  /**
68
67
  * Tests whether the timezone matches the search string. Matches on the picker display label
69
- * ("name (offset)"), the friendly title (offset + name) and the IANA ID, with underscores
68
+ * (the friendly name), the friendly title (offset + name) and the IANA ID, with underscores
70
69
  * treated as spaces so that e.g. "Los Angeles" finds "America/Los_Angeles".
71
70
  *
72
71
  * @internal
@@ -1 +1 @@
1
- {"version":3,"file":"timezones.d.ts","sourceRoot":"","sources":["../../src/Timezone/timezones.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;CACtB;AAkJD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,MAAM,CAE1F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAE9C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAEjF;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,aAAa,CAkB/C;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAWtF;AAmBD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,aAAa,CAAC,CAUzF;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,MAAM,UAQpD"}
1
+ {"version":3,"file":"timezones.d.ts","sourceRoot":"","sources":["../../src/Timezone/timezones.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC1B;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,WAAW,EAAE,MAAM,CAAC;IAEpB;;OAEG;IACH,aAAa,EAAE,MAAM,CAAC;IAEtB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;CACtB;AAkJD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,aAAa,CAAC,GAAG,MAAM,CAE1F;AAED;;;;GAIG;AACH,wBAAgB,YAAY,IAAI,aAAa,EAAE,CAE9C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,aAAa,GAAG,SAAS,CAEjF;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,IAAI,aAAa,CAkB/C;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAG1D;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAWtF;AAmBD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,aAAa,CAAC,CAUzF;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,EAAE,MAAM,UAWpD"}
@@ -183,9 +183,8 @@ export function getUserTimezone() {
183
183
  TIMEZONE_DEFAULT);
184
184
  }
185
185
  /**
186
- * Returns the display label used by the timezone picker: the friendly name with the GMT offset
187
- * as a suffix in brackets, e.g. "Prague (GMT+01:00)". The name falls back to the raw IANA ID
188
- * for zones outside the curated list, and the offset suffix is dropped when not known.
186
+ * Returns the display label used by the timezone picker: the friendly name, e.g. "Prague".
187
+ * The name falls back to the raw IANA ID for zones outside the curated list.
189
188
  *
190
189
  * The friendly name (not the IANA ID) is shown so the picker reads the same as the Home UI
191
190
  * timezone settings — the id-to-name mapping is not visible to users anywhere.
@@ -198,7 +197,7 @@ export function getTimezoneDisplayLabel(id) {
198
197
  }
199
198
  /**
200
199
  * Tests whether the timezone matches the search string. Matches on the picker display label
201
- * ("name (offset)"), the friendly title (offset + name) and the IANA ID, with underscores
200
+ * (the friendly name), the friendly title (offset + name) and the IANA ID, with underscores
202
201
  * treated as spaces so that e.g. "Los Angeles" finds "America/Los_Angeles".
203
202
  *
204
203
  * @internal
@@ -260,5 +259,8 @@ export function getCurrentTimeByTimezoneId(id) {
260
259
  const date = new Date(dateTime);
261
260
  const hours = date.getHours();
262
261
  const minutes = date.getMinutes();
263
- return hours && minutes ? `${("0" + hours).slice(-2)}:${("0" + minutes).slice(-2)}` : "";
262
+ // guard against an unparsable date (NaN); zero is a valid hour/minute value
263
+ return Number.isNaN(hours) || Number.isNaN(minutes)
264
+ ? ""
265
+ : `${("0" + hours).slice(-2)}:${("0" + minutes).slice(-2)}`;
264
266
  }
@@ -1348,9 +1348,8 @@ export declare const getSiblingItems: <T extends IUiMenuItemData = object>(items
1348
1348
  export declare function getTimezoneById(id: string | undefined): ITimezoneItem | undefined;
1349
1349
 
1350
1350
  /**
1351
- * Returns the display label used by the timezone picker: the friendly name with the GMT offset
1352
- * as a suffix in brackets, e.g. "Prague (GMT+01:00)". The name falls back to the raw IANA ID
1353
- * for zones outside the curated list, and the offset suffix is dropped when not known.
1351
+ * Returns the display label used by the timezone picker: the friendly name, e.g. "Prague".
1352
+ * The name falls back to the raw IANA ID for zones outside the curated list.
1354
1353
  *
1355
1354
  * The friendly name (not the IANA ID) is shown so the picker reads the same as the Home UI
1356
1355
  * timezone settings — the id-to-name mapping is not visible to users anywhere.
@@ -6351,7 +6350,7 @@ export declare interface ITimezoneItem {
6351
6350
  export declare interface ITimezoneSelectButtonRenderProps extends IDropdownButtonRenderProps {
6352
6351
  /**
6353
6352
  * Human-readable label of the current selection: the matching special item label,
6354
- * the selected timezone as "name (offset)" (e.g. "Prague (GMT+01:00)"),
6353
+ * the friendly name of the selected timezone (e.g. "Prague"),
6355
6354
  * or the placeholder when nothing is selected.
6356
6355
  */
6357
6356
  buttonLabel: string;
@@ -6396,6 +6395,16 @@ export declare interface ITimezoneSelectProps {
6396
6395
  * Accessibility label of the search input and the listbox.
6397
6396
  */
6398
6397
  ariaLabel: string;
6398
+ /**
6399
+ * Id of the default dropdown trigger, so a visible `<label htmlFor>` can be associated
6400
+ * with it. Ignored when a custom trigger is rendered via `renderButton`.
6401
+ */
6402
+ id?: string;
6403
+ /**
6404
+ * Ids of elements describing the default dropdown trigger (`aria-describedby`), e.g. an
6405
+ * adjacent hint text. Ignored when a custom trigger is rendered via `renderButton`.
6406
+ */
6407
+ ariaDescribedBy?: string;
6399
6408
  /**
6400
6409
  * Label shown when the search yields no results.
6401
6410
  */
@@ -6423,7 +6432,7 @@ export declare interface ITimezoneSelectProps {
6423
6432
 
6424
6433
  /**
6425
6434
  * Special item rendered above the divider in {@link TimezoneSelect}, ahead of the curated
6426
- * timezone list. Callers use these for entries like "Default (workspace)" or "From browser (...)".
6435
+ * timezone list. Callers use these for entries like "Default" or "Device time zone".
6427
6436
  *
6428
6437
  * @internal
6429
6438
  */
@@ -7783,6 +7792,8 @@ export declare interface IUiGranteeRowControlsProps {
7783
7792
  disabledLevels?: ReadonlyArray<PermissionMenuLevel>;
7784
7793
  /** Tooltip shown on disabled level rows in place of the level's info text. */
7785
7794
  disabledTooltip?: string;
7795
+ /** Per-level override of `disabledTooltip` — see {@link UiPermissionMenu}. */
7796
+ disabledLevelTooltips?: Partial<Record<PermissionMenuLevel, string>>;
7786
7797
  onLabelsChange: (selectedIds: string[]) => void;
7787
7798
  onPermissionChange: (level: PermissionMenuLevel) => void;
7788
7799
  onRemoveAccess?: () => void;
@@ -8643,6 +8654,11 @@ export declare interface IUiPermissionMenuProps {
8643
8654
  disabledLevels?: ReadonlyArray<PermissionMenuLevel>;
8644
8655
  /** Tooltip shown on disabled level rows in place of the level's info text. */
8645
8656
  disabledTooltip?: string;
8657
+ /**
8658
+ * Per-level override of `disabledTooltip`, for menus whose disabled levels have
8659
+ * different reasons (capped by the caller's own level vs. already inherited).
8660
+ */
8661
+ disabledLevelTooltips?: Partial<Record<PermissionMenuLevel, string>>;
8646
8662
  /**
8647
8663
  * Non-empty enables a labels row that drills into {@link UiLabelsChecklist}
8648
8664
  * within the menu — for rows whose menu hosts every action (no "⋯" menu).
@@ -10615,11 +10631,11 @@ export declare const Timepicker: NamedExoticComponent<ITimepickerOwnProps>;
10615
10631
 
10616
10632
  /**
10617
10633
  * Searchable dropdown for picking a timezone from the curated list, with optional special
10618
- * items (e.g. "Default (workspace)", "From browser (...)") rendered above a divider.
10634
+ * items (e.g. "Default", "Device time zone") rendered above a divider.
10619
10635
  *
10620
10636
  * @internal
10621
10637
  */
10622
- export declare function TimezoneSelect({ value, onChange, specialItems, placeholder, searchPlaceholder, ariaLabel, noMatchLabel, isDisabled, header, showTooltip, renderButton }: ITimezoneSelectProps): ReactElement;
10638
+ export declare function TimezoneSelect({ value, onChange, specialItems, placeholder, searchPlaceholder, ariaLabel, id, ariaDescribedBy, noMatchLabel, isDisabled, header, showTooltip, renderButton }: ITimezoneSelectProps): ReactElement;
10623
10639
 
10624
10640
  /**
10625
10641
  * @internal
@@ -11191,7 +11207,7 @@ export declare function UiGranteeRow({ kind, name, email, isPending, controls, d
11191
11207
  *
11192
11208
  * @internal
11193
11209
  */
11194
- export declare function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel, effectivePermission, disabledLevels, disabledTooltip, onLabelsChange, onPermissionChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, isDisabled, dataTestId }: IUiGranteeRowControlsProps): JSX.Element;
11210
+ export declare function UiGranteeRowControls({ labels, selectedLabelIds, permissionLevel, effectivePermission, disabledLevels, disabledTooltip, disabledLevelTooltips, onLabelsChange, onPermissionChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, isDisabled, dataTestId }: IUiGranteeRowControlsProps): JSX.Element;
11195
11211
 
11196
11212
  /**
11197
11213
  * @internal
@@ -11368,7 +11384,7 @@ export declare type UiPaginationButtonSize = "small" | "large";
11368
11384
  *
11369
11385
  * @internal
11370
11386
  */
11371
- export declare function UiPermissionMenu({ anchor, selectedLevel, onPermissionChange, disabledLevels, disabledTooltip, labels, selectedLabelIds, onLabelsChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, dataTestId }: IUiPermissionMenuProps): JSX.Element;
11387
+ export declare function UiPermissionMenu({ anchor, selectedLevel, onPermissionChange, disabledLevels, disabledTooltip, disabledLevelTooltips, labels, selectedLabelIds, onLabelsChange, onRemoveAccess, isRemoveDisabled, removeDisabledTooltip, dataTestId }: IUiPermissionMenuProps): JSX.Element;
11372
11388
 
11373
11389
  /**
11374
11390
  * @internal
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gooddata/sdk-ui-kit",
3
- "version": "11.53.0-alpha.5",
3
+ "version": "11.53.0-alpha.7",
4
4
  "description": "GoodData SDK - UI Building Components",
5
5
  "license": "MIT",
6
6
  "author": "GoodData Corporation",
@@ -78,11 +78,11 @@
78
78
  "unified": "^11.0.5",
79
79
  "uuid": "11.1.1",
80
80
  "yaml": "2.8.3",
81
- "@gooddata/sdk-backend-spi": "11.53.0-alpha.5",
82
- "@gooddata/sdk-model": "11.53.0-alpha.5",
83
- "@gooddata/sdk-ui": "11.53.0-alpha.5",
84
- "@gooddata/util": "11.53.0-alpha.5",
85
- "@gooddata/sdk-ui-theme-provider": "11.53.0-alpha.5"
81
+ "@gooddata/sdk-model": "11.53.0-alpha.7",
82
+ "@gooddata/sdk-ui": "11.53.0-alpha.7",
83
+ "@gooddata/sdk-backend-spi": "11.53.0-alpha.7",
84
+ "@gooddata/sdk-ui-theme-provider": "11.53.0-alpha.7",
85
+ "@gooddata/util": "11.53.0-alpha.7"
86
86
  },
87
87
  "devDependencies": {
88
88
  "@microsoft/api-documenter": "^7.17.0",
@@ -131,11 +131,11 @@
131
131
  "typescript": "5.9.3",
132
132
  "vitest": "4.1.8",
133
133
  "vitest-dom": "0.1.1",
134
- "@gooddata/eslint-config": "11.53.0-alpha.5",
135
- "@gooddata/oxlint-config": "11.53.0-alpha.5",
136
- "@gooddata/reference-workspace": "11.53.0-alpha.5",
137
- "@gooddata/sdk-backend-mockingbird": "11.53.0-alpha.5",
138
- "@gooddata/stylelint-config": "11.53.0-alpha.5"
134
+ "@gooddata/eslint-config": "11.53.0-alpha.7",
135
+ "@gooddata/oxlint-config": "11.53.0-alpha.7",
136
+ "@gooddata/reference-workspace": "11.53.0-alpha.7",
137
+ "@gooddata/sdk-backend-mockingbird": "11.53.0-alpha.7",
138
+ "@gooddata/stylelint-config": "11.53.0-alpha.7"
139
139
  },
140
140
  "peerDependencies": {
141
141
  "react": "^18.0.0 || ^19.0.0",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=simpleRecurrenceTypeMappingFn.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"simpleRecurrenceTypeMappingFn.test.d.ts","sourceRoot":"","sources":["../../../src/RecurrenceForm/utils/simpleRecurrenceTypeMappingFn.test.ts"],"names":[],"mappings":""}
@@ -1,79 +0,0 @@
1
- // (C) 2025-2026 GoodData Corporation
2
- import { describe, expect, it } from "vitest";
3
- import { RECURRENCE_TYPES } from "../constants.js";
4
- import { simpleRecurrenceTypeMappingFn } from "./simpleRecurrenceTypeMappingFn.js";
5
- describe("simpleRecurrenceTypeMappingFn", () => {
6
- it.each([
7
- // Basic hourly patterns
8
- ["0 0 * ? * *", true, "Monday", RECURRENCE_TYPES.HOURLY, "hourly pattern when allowed"],
9
- ["0 0 * ? * *", false, "Monday", RECURRENCE_TYPES.CRON, "hourly pattern when not allowed"],
10
- [undefined, true, "Monday", RECURRENCE_TYPES.HOURLY, "default hourly when allowed and no cron"],
11
- // Basic daily patterns
12
- ["0 0 0 ? * *", false, "Monday", RECURRENCE_TYPES.DAILY, "daily pattern"],
13
- ["0 0 0 ? * *", true, "Monday", RECURRENCE_TYPES.DAILY, "daily pattern with hourly allowed"],
14
- [
15
- undefined,
16
- false,
17
- "Monday",
18
- RECURRENCE_TYPES.DAILY,
19
- "default daily when hourly not allowed and no cron",
20
- ],
21
- // Weekly patterns - Monday week start
22
- ["0 0 0 ? * 1", false, "Monday", RECURRENCE_TYPES.WEEKLY, "Monday numeric weekly"],
23
- ["0 0 0 ? * MON", false, "Monday", RECURRENCE_TYPES.WEEKLY, "Monday string weekly"],
24
- ["0 0 0 ? * 0", false, "Monday", RECURRENCE_TYPES.CRON, "Sunday with Monday week start"],
25
- ["0 0 0 ? * SUN", false, "Monday", RECURRENCE_TYPES.CRON, "Sunday string with Monday week start"],
26
- ["0 0 0 ? * 2", false, "Monday", RECURRENCE_TYPES.CRON, "Tuesday with Monday week start"],
27
- // Weekly patterns - Sunday week start
28
- ["0 0 0 ? * 0", false, "Sunday", RECURRENCE_TYPES.WEEKLY, "Sunday numeric weekly"],
29
- ["0 0 0 ? * SUN", false, "Sunday", RECURRENCE_TYPES.WEEKLY, "Sunday string weekly"],
30
- ["0 0 0 ? * 1", false, "Sunday", RECURRENCE_TYPES.CRON, "Monday with Sunday week start"],
31
- ["0 0 0 ? * MON", false, "Sunday", RECURRENCE_TYPES.CRON, "Monday string with Sunday week start"],
32
- // Weekly patterns - undefined week start (defaults to Monday)
33
- [
34
- "0 0 0 ? * 1",
35
- false,
36
- undefined,
37
- RECURRENCE_TYPES.WEEKLY,
38
- "Monday numeric with undefined week start",
39
- ],
40
- [
41
- "0 0 0 ? * MON",
42
- false,
43
- undefined,
44
- RECURRENCE_TYPES.WEEKLY,
45
- "Monday string with undefined week start",
46
- ],
47
- // Monthly patterns
48
- ["0 0 0 1 * *", false, "Monday", RECURRENCE_TYPES.MONTHLY, "monthly pattern"],
49
- ["0 0 0 1 * *", true, "Monday", RECURRENCE_TYPES.MONTHLY, "monthly pattern with hourly allowed"],
50
- // Custom/complex cron patterns
51
- ["0 30 10 ? * MON-FRI", false, "Monday", RECURRENCE_TYPES.CRON, "complex business days pattern"],
52
- ["0 15 8 ? * TUE", false, "Monday", RECURRENCE_TYPES.CRON, "Tuesday at specific time"],
53
- ["0 0 8 ? * MON#1", false, "Monday", RECURRENCE_TYPES.CRON, "first Monday of month pattern"],
54
- ["0 30 14 ? * MON-FRI", false, "Monday", RECURRENCE_TYPES.CRON, "complex pattern"],
55
- // Invalid/edge cases
56
- ["invalid cron", false, "Monday", RECURRENCE_TYPES.CRON, "invalid cron expression"],
57
- ["", false, "Monday", RECURRENCE_TYPES.CRON, "empty string"],
58
- [" ", false, "Monday", RECURRENCE_TYPES.CRON, "whitespace-only string"],
59
- [null, false, "Monday", RECURRENCE_TYPES.DAILY, "null cron expression"],
60
- ])("should return %s for cron '%s' with allowHourly=%s, weekStart=%s (%s)", (cronExpression, allowHourly, weekStart, expectedType, _description) => {
61
- const result = simpleRecurrenceTypeMappingFn(undefined, // Date parameter is not used, so we can pass undefined
62
- cronExpression, allowHourly, false, weekStart);
63
- expect(result).toBe(expectedType);
64
- });
65
- // Test demonstrating that the date parameter is indeed optional and not used
66
- it("should work the same regardless of date parameter", () => {
67
- const cronExpression = "0 0 0 ? * *";
68
- const allowHourly = false;
69
- const weekStart = "Monday";
70
- const resultWithDate = simpleRecurrenceTypeMappingFn(new Date("2024-01-15T10:30:00"), cronExpression, allowHourly, false, weekStart);
71
- const resultWithoutDate = simpleRecurrenceTypeMappingFn(undefined, cronExpression, allowHourly, false, weekStart);
72
- const resultWithNull = simpleRecurrenceTypeMappingFn(null, cronExpression, allowHourly, false, weekStart);
73
- expect(resultWithDate).toBe(RECURRENCE_TYPES.DAILY);
74
- expect(resultWithoutDate).toBe(RECURRENCE_TYPES.DAILY);
75
- expect(resultWithNull).toBe(RECURRENCE_TYPES.DAILY);
76
- expect(resultWithDate).toBe(resultWithoutDate);
77
- expect(resultWithoutDate).toBe(resultWithNull);
78
- });
79
- });
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=utils.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../../src/RecurrenceForm/utils/utils.test.ts"],"names":[],"mappings":""}
@@ -1,224 +0,0 @@
1
- // (C) 2024-2026 GoodData Corporation
2
- import { describe, expect, it } from "vitest";
3
- import { createIntlMock } from "@gooddata/sdk-ui";
4
- import { RECURRENCE_TYPES } from "../constants.js";
5
- import { constructCronExpression, isLastOccurrenceOfWeekdayInMonth, transformCronExpressionToRecurrenceType, transformRecurrenceTypeToDescription, } from "./utils.js";
6
- const sampleCronExp = "0 0 1 ? * 2";
7
- const sampleDate = new Date("2023-04-05T14:34:21");
8
- const sampleDate2 = new Date("2023-04-13T15:34:21");
9
- const sampleDate3 = new Date("2023-04-18T16:34:21");
10
- const sampleDate4 = new Date("2023-03-24T12:34:21");
11
- const sampleDate5 = new Date("2023-04-24T17:34:21");
12
- const sampleDate6 = new Date("2023-04-30T18:34:21");
13
- describe("isLastOccurrenceOfWeekdayInMonth", () => {
14
- it.each([
15
- [true, new Date("2023-04-30"), "5th Sunday of April 2023, last because April 2023 has 5 Sundays"],
16
- [
17
- false,
18
- new Date("2023-04-02"),
19
- "1st Sunday of April 2023, not last because April 2023 has 5 Sundays",
20
- ],
21
- [true, new Date("2023-07-28"), "4th Friday of July 2023, last because July 2023 has 4 Fridays"],
22
- [
23
- true,
24
- new Date("2024-02-25"),
25
- "4th Sunday of February 2024, last because February 2024 has 4 Sundays (leap year)",
26
- ],
27
- [true, new Date("2023-05-25"), "4th Thursday of May 2023, last because May 2023 has 4 Thursdays"],
28
- [true, new Date("2023-05-31"), "5th Wednesday of May 2023, last because May 2023 has 5 Wednesdays"],
29
- [
30
- true,
31
- new Date("2023-12-28"),
32
- "4th Thursday of December 2023, last because December 2023 has 4 Thursdays",
33
- ],
34
- [
35
- true,
36
- new Date("2023-12-31"),
37
- "5th Sunday of December 2023, last because December 2023 has 5 Sundays",
38
- ],
39
- [
40
- true,
41
- new Date("2023-09-28"),
42
- "4th Thursday of September 2023, last because September 2023 has 4 Thursdays",
43
- ],
44
- [
45
- false,
46
- new Date("2023-09-21"),
47
- "3rd Thursday of September 2023, not last because September 2023 has 4 Thursdays",
48
- ],
49
- [
50
- true,
51
- new Date("2023-02-22"),
52
- "4th Wednesday of February 2023, last because February 2023 has 4 Wednesdays",
53
- ],
54
- [
55
- false,
56
- new Date("2023-02-15"),
57
- "3rd Wednesday of February 2023, not last because February 2023 has 4 Wednesdays",
58
- ],
59
- ])("should return %s for %s", (expectedResult, date) => {
60
- expect(isLastOccurrenceOfWeekdayInMonth(date)).toBe(expectedResult);
61
- });
62
- });
63
- describe("constructCronExpression with date", () => {
64
- it.each([
65
- ["hourly", sampleDate, sampleCronExp, "0 0 * ? * *", "every hour"],
66
- ["daily", sampleDate, sampleCronExp, "0 0 14 ? * *", "every day at the same time"],
67
- ["weekly", sampleDate, sampleCronExp, "0 0 14 ? * WED", "every week at the same day and time"],
68
- ["monthly", sampleDate, sampleCronExp, "0 0 14 ? * WED#1", "every month on the first wednesday"],
69
- ["monthly", sampleDate2, sampleCronExp, "0 0 15 ? * THU#2", "every month on the second thursday"],
70
- ["monthly", sampleDate3, sampleCronExp, "0 0 16 ? * TUE#3", "every month on the third tuesday"],
71
- ["monthly", sampleDate4, sampleCronExp, "0 0 12 ? * FRI#4", "every month on the fourth friday"],
72
- ["monthly", sampleDate5, sampleCronExp, "0 0 17 ? * MONL", "every month on the last (fourth) monday"],
73
- ["monthly", sampleDate6, sampleCronExp, "0 0 18 ? * SUNL", "every month on the last (fifth) sunday"],
74
- ["cron", sampleDate, sampleCronExp, sampleCronExp, "provided cron expression"],
75
- ])("should transform date and recurrence type to %s expression", (recurrenceType, date, defaultCronExpression, expectedCronExpression, _description) => {
76
- expect(constructCronExpression(date, recurrenceType, defaultCronExpression, "Monday")).toEqual(expectedCronExpression);
77
- });
78
- });
79
- describe("constructCronExpression without date, default Monday", () => {
80
- it.each([
81
- ["hourly", sampleCronExp, "0 0 * ? * *", "every hour"],
82
- ["daily", sampleCronExp, "0 0 0 ? * *", "every day at the same time"],
83
- ["weekly", sampleCronExp, "0 0 0 ? * MON", "every week at the same day and time"],
84
- ["monthly", sampleCronExp, "0 0 0 1 * *", "every month at first day"],
85
- ["cron", sampleCronExp, sampleCronExp, "provided cron expression"],
86
- ])("should transform date and recurrence type to %s expression", (recurrenceType, defaultCronExpression, expectedCronExpression, _description) => {
87
- expect(constructCronExpression(null, recurrenceType, defaultCronExpression, "Monday")).toEqual(expectedCronExpression);
88
- });
89
- });
90
- describe("constructCronExpression without date, default Sunday", () => {
91
- it.each([
92
- ["hourly", sampleCronExp, "0 0 * ? * *", "every hour"],
93
- ["daily", sampleCronExp, "0 0 0 ? * *", "every day at the same time"],
94
- ["weekly", sampleCronExp, "0 0 0 ? * SUN", "every week at the same day and time"],
95
- ["monthly", sampleCronExp, "0 0 0 1 * *", "every month at first day"],
96
- ["cron", sampleCronExp, sampleCronExp, "provided cron expression"],
97
- ])("should transform date and recurrence type to %s expression", (recurrenceType, defaultCronExpression, expectedCronExpression, _description) => {
98
- expect(constructCronExpression(null, recurrenceType, defaultCronExpression, "Sunday")).toEqual(expectedCronExpression);
99
- });
100
- });
101
- describe("transformCronExpressionToRecurrenceType with date", () => {
102
- const universal = new Date();
103
- const D2024_01_01_01 = new Date(2024, 0, 1, 1, 0, 0);
104
- const D2024_01_01_09 = new Date(2024, 0, 1, 9, 0, 0);
105
- const D2024_01_01_18 = new Date(2024, 0, 1, 18, 0, 0);
106
- const D2024_01_07_01 = new Date(2024, 0, 7, 1, 0, 0);
107
- const D2024_01_08_09 = new Date(2024, 0, 8, 9, 0, 0);
108
- const D2024_01_09_12 = new Date(2024, 0, 9, 12, 0, 0);
109
- const D2024_01_12_18 = new Date(2024, 0, 12, 18, 0, 0);
110
- const D2024_01_13_23 = new Date(2024, 0, 13, 23, 0, 0);
111
- const D2024_01_01_15 = new Date(2024, 0, 1, 15, 0, 0);
112
- const D2024_01_05_15 = new Date(2024, 0, 5, 15, 0, 0);
113
- const D2024_01_09_15 = new Date(2024, 0, 9, 15, 0, 0);
114
- const D2024_01_17_15 = new Date(2024, 0, 17, 15, 0, 0);
115
- const D2024_01_25_15 = new Date(2024, 0, 25, 15, 0, 0);
116
- it.each([
117
- ["0 0 * ? * *", true, false, universal, "hourly"],
118
- ["0 0 * ? * *", false, false, universal, "cron"],
119
- ["0 0 1 ? * *", true, false, D2024_01_01_01, "daily"],
120
- ["0 0 9 ? * *", true, false, D2024_01_01_09, "daily"],
121
- ["0 0 18 ? * *", true, false, D2024_01_01_18, "daily"],
122
- ["0 0 10 ? * *", true, false, D2024_01_01_18, "cron"],
123
- ["0 0 1 ? * SUN", true, false, D2024_01_07_01, "weekly"],
124
- ["0 0 9 ? * MON", true, false, D2024_01_08_09, "weekly"],
125
- ["0 0 12 ? * TUE", true, false, D2024_01_09_12, "weekly"],
126
- ["0 0 18 ? * FRI", true, false, D2024_01_12_18, "weekly"],
127
- ["0 0 23 ? * SAT", true, false, D2024_01_13_23, "weekly"],
128
- ["0 0 23 ? * FRI", true, false, D2024_01_13_23, "cron"],
129
- ["0 0 10 ? * SAT", true, false, D2024_01_13_23, "cron"],
130
- ["0 0 15 ? * MON#1", true, false, D2024_01_01_15, "monthly", "every first monday"],
131
- ["0 0 15 ? * FRI#1", true, false, D2024_01_05_15, "monthly", "every first friday"],
132
- ["0 0 15 ? * TUE#2", true, false, D2024_01_09_15, "monthly", "every second tuesday"],
133
- ["0 0 15 ? * WED#3", true, false, D2024_01_17_15, "monthly", "every third wednesday"],
134
- ["0 0 15 ? * THUL", true, false, D2024_01_25_15, "monthly", "every last (fourth) thursday"],
135
- ["0 0 15 ? * THU#5", true, false, D2024_01_25_15, "cron"],
136
- ["0 0 8 ? * TUE#2", true, false, D2024_01_09_15, "cron"],
137
- ["* * * * * *", true, false, universal, "cron"],
138
- ["* * * ? * *", true, false, universal, "cron"],
139
- ["1 1 1 1 1 1", true, false, universal, "cron"],
140
- ["1 1 1 ? 1 1", true, false, universal, "cron"],
141
- ["0 0 1 ? * 5", true, false, universal, "cron"],
142
- ["0 0 1 ? JAN SUN", true, false, universal, "cron"],
143
- ["0 0 1 ? * 1-3", true, false, universal, "cron"],
144
- ["0 0 1 ? * 1,2", true, false, universal, "cron"],
145
- ["0 0 1 ? * 1/2", true, false, universal, "cron"],
146
- ["0 0 0 1 * *", true, false, universal, "cron"],
147
- ["", true, true, universal, "inherit"],
148
- ["", true, true, undefined, "inherit"],
149
- [undefined, true, true, undefined, "inherit"],
150
- [undefined, true, false, undefined, "cron"],
151
- ])("should correctly identify %s with hourly %s and date %s as %s", ((cronExpression, allowHourly, allowInherit, date, expected) => {
152
- expect(transformCronExpressionToRecurrenceType(date ?? null, cronExpression, allowHourly, allowInherit, "Monday")).toEqual(expected);
153
- }));
154
- });
155
- describe("transformCronExpressionToRecurrenceType without date, default Monday", () => {
156
- it.each([
157
- ["0 0 * ? * *", true, false, "hourly"],
158
- ["0 0 * ? * *", false, false, "cron"],
159
- ["0 0 1 ? * *", true, false, "daily"],
160
- ["0 0 9 ? * *", true, false, "daily"],
161
- ["0 0 18 ? * *", true, false, "daily"],
162
- ["0 0 10 ? * *", true, false, "daily"],
163
- ["0 0 1 ? * SUN", true, false, "weekly"],
164
- ["0 0 9 ? * MON", true, false, "weekly"],
165
- ["0 0 12 ? * TUE", true, false, "weekly"],
166
- ["0 0 18 ? * FRI", true, false, "weekly"],
167
- ["0 0 23 ? * SAT", true, false, "weekly"],
168
- ["0 0 23 ? * FRI", true, false, "weekly"],
169
- ["0 0 10 ? * SAT", true, false, "weekly"],
170
- ["0 0 15 ? * MON#1", true, false, "monthly", "every first monday"],
171
- ["0 0 15 ? * FRI#1", true, false, "monthly", "every first friday"],
172
- ["0 0 15 ? * TUE#2", true, false, "monthly", "every second tuesday"],
173
- ["0 0 15 ? * WED#3", true, false, "monthly", "every third wednesday"],
174
- ["0 0 15 ? * THUL", true, false, "monthly", "every last (fourth) thursday"],
175
- ["0 0 15 ? * THU#5", true, false, "monthly"],
176
- ["0 0 8 ? * TUE#2", true, false, "monthly"],
177
- ["0 0 0 1 * *", true, false, "monthly"],
178
- ["* * * * * *", true, false, "cron"],
179
- ["* * * ? * *", true, false, "cron"],
180
- ["1 1 1 1 1 1", true, false, "cron"],
181
- ["1 1 1 ? 1 1", true, false, "cron"],
182
- ["0 0 1 ? * 5", true, false, "cron"],
183
- ["0 0 1 ? JAN SUN", true, false, "cron"],
184
- ["0 0 1 ? * 1-3", true, false, "cron"],
185
- ["0 0 1 ? * 1,2", true, false, "cron"],
186
- ["0 0 1 ? * 1/2", true, false, "cron"],
187
- ["0 0 1 ? * 1/2", true, false, "cron"],
188
- ["", true, true, "inherit"],
189
- ["", true, true, "inherit"],
190
- [undefined, true, true, "inherit"],
191
- [undefined, true, false, "cron"],
192
- ])("should correctly identify %s with hourly %s as %s", ((cronExpression, allowHourly, allowInherit, expected) => {
193
- expect(transformCronExpressionToRecurrenceType(null, cronExpression, allowHourly, allowInherit, "Monday")).toEqual(expected);
194
- }));
195
- });
196
- describe("transformRecurrenceTypeToDescription", () => {
197
- const intl = createIntlMock();
198
- const d1 = new Date(2024, 7, 13, 22, 0, 0);
199
- it.each([
200
- [RECURRENCE_TYPES.HOURLY, null, "Monday", "At start of every hour"],
201
- [RECURRENCE_TYPES.HOURLY, null, "Sunday", "At start of every hour"],
202
- [RECURRENCE_TYPES.DAILY, null, "Monday", "At 12 AM every day"],
203
- [RECURRENCE_TYPES.DAILY, null, "Sunday", "At 12 AM every day"],
204
- [RECURRENCE_TYPES.WEEKLY, null, "Monday", "At 12 AM every week start"],
205
- [RECURRENCE_TYPES.WEEKLY, null, "Sunday", "At 12 AM every week start"],
206
- [RECURRENCE_TYPES.MONTHLY, null, "Monday", "At 12 AM every month start"],
207
- [RECURRENCE_TYPES.MONTHLY, null, "Sunday", "At 12 AM every month start"],
208
- [RECURRENCE_TYPES.CRON, null, "Monday", ""],
209
- [RECURRENCE_TYPES.CRON, null, "Sunday", ""],
210
- [RECURRENCE_TYPES.HOURLY, d1, "Monday", "At start of every hour"],
211
- [RECURRENCE_TYPES.HOURLY, d1, "Sunday", "At start of every hour"],
212
- [RECURRENCE_TYPES.DAILY, d1, "Monday", "At 10 PM every day"],
213
- [RECURRENCE_TYPES.DAILY, d1, "Sunday", "At 10 PM every day"],
214
- [RECURRENCE_TYPES.WEEKLY, d1, "Monday", "At 10 PM on Tuesday every week"],
215
- [RECURRENCE_TYPES.WEEKLY, d1, "Sunday", "At 10 PM on Tuesday every week"],
216
- [RECURRENCE_TYPES.MONTHLY, d1, "Monday", "At 10 PM on Tuesday every 2. week in month"],
217
- [RECURRENCE_TYPES.MONTHLY, d1, "Sunday", "At 10 PM on Tuesday every 2. week in month"],
218
- [RECURRENCE_TYPES.CRON, d1, "Monday", ""],
219
- [RECURRENCE_TYPES.CRON, d1, "Sunday", ""],
220
- [RECURRENCE_TYPES.INHERIT, d1, "Sunday", ""],
221
- ])("should correctly describe %s", ((recurrenceType, date, weekStart, expected) => {
222
- expect(transformRecurrenceTypeToDescription(intl, recurrenceType, date, weekStart)).toEqual(expected);
223
- }));
224
- });