@gooddata/sdk-ui-ext 11.53.0-alpha.6 → 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.
@@ -1 +1 @@
1
- {"version":3,"file":"AddSingleWorkspaceSelect.d.ts","sourceRoot":"","sources":["../../../../../../src/internal/components/dialogs/userManagementDialogs/Workspace/AddSingleWorkspaceSelect.tsx"],"names":[],"mappings":"AAYA,OAAO,EACH,KAAK,8BAA8B,EAKtC,MAAM,aAAa,CAAC;AAgBrB,wBAAgB,wBAAwB,CAAC,EACrC,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,IAAa,EAChB,EAAE,8BAA8B,2CA4GhC"}
1
+ {"version":3,"file":"AddSingleWorkspaceSelect.d.ts","sourceRoot":"","sources":["../../../../../../src/internal/components/dialogs/userManagementDialogs/Workspace/AddSingleWorkspaceSelect.tsx"],"names":[],"mappings":"AAYA,OAAO,EACH,KAAK,8BAA8B,EAKtC,MAAM,aAAa,CAAC;AAgBrB,wBAAgB,wBAAwB,CAAC,EACrC,cAAc,EACd,iBAAiB,EACjB,iBAAiB,EACjB,IAAa,EAChB,EAAE,8BAA8B,2CA0GhC"}
@@ -63,9 +63,7 @@ export function AddSingleWorkspaceSelect({ addedWorkspace, grantedWorkspaces, on
63
63
  }, styles: {
64
64
  dropdownIndicator: (base) => ({
65
65
  ...base,
66
- padding: "0",
67
- marginRight: "-6px",
68
- svg: { height: "14px" },
66
+ svg: { width: "14px", height: "14px" },
69
67
  }),
70
68
  }, loadOptions: loadOptions, defaultOptions: true, placeholder: intl.formatMessage(messages.searchWorkspacePlaceholder), onKeyDown: onKeyDownCallback, noOptionsMessage: noOptionsMessage, onChange: onSelect, filterOption: filterOption, isMulti: false, isDisabled: !isEditMode, value: addedWorkspace
71
69
  ? {
@@ -2519,6 +2519,10 @@ export declare const en_US: {
2519
2519
  text: string;
2520
2520
  crowdinContext: string;
2521
2521
  };
2522
+ "objectShare.granteeLevel.inheritedCovered": {
2523
+ text: string;
2524
+ crowdinContext: string;
2525
+ };
2522
2526
  "objectShare.grantee.you": {
2523
2527
  text: string;
2524
2528
  crowdinContext: string;
@@ -2547,6 +2551,10 @@ export declare const en_US: {
2547
2551
  text: string;
2548
2552
  crowdinContext: string;
2549
2553
  };
2554
+ "objectShare.toast.escalationRefused": {
2555
+ text: string;
2556
+ crowdinContext: string;
2557
+ };
2550
2558
  "objectShare.toast.labelScopePartial": {
2551
2559
  text: string;
2552
2560
  crowdinContext: string;
@@ -1 +1 @@
1
- {"version":3,"file":"en-US.localization-bundle.d.ts","sourceRoot":"","sources":["../../../src/internal/translations/en-US.localization-bundle.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyuFjB,CAAC"}
1
+ {"version":3,"file":"en-US.localization-bundle.d.ts","sourceRoot":"","sources":["../../../src/internal/translations/en-US.localization-bundle.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAivFjB,CAAC"}
@@ -2521,6 +2521,10 @@ export const en_US = {
2521
2521
  "text": "This access is inherited from a group or a parent workspace and cannot be removed here.",
2522
2522
  "crowdinContext": "Tooltip on the disabled Remove access action in a grantee row's permission menu, shown when the grantee has no permission granted in this workspace, so there is nothing here to remove."
2523
2523
  },
2524
+ "objectShare.granteeLevel.inheritedCovered": {
2525
+ "text": "This level is already covered by access inherited from a group or a parent workspace.",
2526
+ "crowdinContext": "Tooltip on a disabled permission level in a grantee row's menu, shown when an inherited grant already covers that level, so picking it could not change what the grantee can do."
2527
+ },
2524
2528
  "objectShare.grantee.you": {
2525
2529
  "text": "{name} (you)",
2526
2530
  "crowdinContext": "Display name of the signed-in user's own row in the share dialog grantee list. {name} is the user's full name."
@@ -2549,6 +2553,10 @@ export const en_US = {
2549
2553
  "text": "Access could not be updated.",
2550
2554
  "crowdinContext": "Toast shown when an access change fails."
2551
2555
  },
2556
+ "objectShare.toast.escalationRefused": {
2557
+ "text": "You can only grant permissions that you have yourself.",
2558
+ "crowdinContext": "Error toast shown when a permission change was refused because the user tried to grant a higher permission level than they hold themselves."
2559
+ },
2552
2560
  "objectShare.toast.labelScopePartial": {
2553
2561
  "text": "Some label access could not be saved.",
2554
2562
  "crowdinContext": "Warning toast when sharing an attribute succeeded but one or more of its per-label permission writes failed."
@@ -40,7 +40,7 @@ export function ObjectShareDialog(props) {
40
40
  /** The dialog session — mounted only while open, so its state cannot outlive a close. */
41
41
  function ObjectShareDialogSession({ target, objectTitle, onClose, onSummaryChange, labels, labelsLoading, labelsError, }) {
42
42
  const intl = useIntl();
43
- const { state, actions, isShareViewOpen, isAddGranteeOpen, isGeneralAccessConfirmOpen, isSelfRestrictConfirmOpen, isMutable, isLoading, workspaceDisabledLevels, rowDisabledLevels, isRowRemoveDisabled, rowRemoveDisabledTooltip, onClose: closeDialog, onRowPermissionChange, onRowRemove, onSelfRestrictCancel, onSelfRestrictConfirm, } = useObjectShareDialog({
43
+ const { state, actions, isShareViewOpen, isAddGranteeOpen, isGeneralAccessConfirmOpen, isSelfRestrictConfirmOpen, isMutable, isLoading, workspaceDisabledLevels, rowDisabledLevels, rowDisabledLevelTooltips, isRowRemoveDisabled, isRowControlsLocked, rowRemoveDisabledTooltip, onClose: closeDialog, onRowPermissionChange, onRowRemove, onSelfRestrictCancel, onSelfRestrictConfirm, } = useObjectShareDialog({
44
44
  target,
45
45
  onClose,
46
46
  onSummaryChange,
@@ -81,13 +81,15 @@ function ObjectShareDialogSession({ target, objectTitle, onClose, onSummaryChang
81
81
  : display.name,
82
82
  email: display.email,
83
83
  isPending: g.pending !== undefined,
84
- controls: (_jsx(UiGranteeRowControls, { labels: rowLabelItems(g.id), selectedLabelIds: state.selectedLabelIdsByGrantee[g.id] ?? state.labels.map((l) => l.id), permissionLevel: g.level, effectivePermission: g.effectivePermission, disabledLevels: disabledLevels, disabledTooltip: disabledLevels
84
+ controls: (_jsx(UiGranteeRowControls, { labels: rowLabelItems(g.id), selectedLabelIds: state.selectedLabelIdsByGrantee[g.id] ?? state.labels.map((l) => l.id), permissionLevel: g.level, effectivePermission: g.effectivePermission, disabledLevels: disabledLevels,
85
+ // Row-wide warning is the self row's; covered picks carry their own.
86
+ disabledTooltip: state.selfManagedGranteeId === g.id
85
87
  ? intl.formatMessage(objectShareMessages.selfRestrictWarning)
86
- : undefined, isRemoveDisabled: isRowRemoveDisabled(g), removeDisabledTooltip: rowRemoveDisabledTooltip,
88
+ : undefined, disabledLevelTooltips: rowDisabledLevelTooltips(g), isRemoveDisabled: isRowRemoveDisabled(g), removeDisabledTooltip: rowRemoveDisabledTooltip,
87
89
  // Disabled while the row's own write is saving, while mutations are
88
90
  // gated (unresolved label scope would orphan real per-label grants),
89
91
  // and while a sole row's self identity is unknown.
90
- isDisabled: g.pending !== undefined || !isMutable || state.granteeControlsLocked, onLabelsChange: (selectedIds) => {
92
+ isDisabled: g.pending !== undefined || !isMutable || isRowControlsLocked(g), onLabelsChange: (selectedIds) => {
91
93
  void actions.changeGranteeLabels(g.id, selectedIds);
92
94
  }, onPermissionChange: (level) => onRowPermissionChange(g, level), onRemoveAccess: () => onRowRemove(g) })),
93
95
  };
@@ -47,6 +47,17 @@ export declare const objectShareMessages: {
47
47
  granteeRemoveInherited: {
48
48
  id: string;
49
49
  };
50
+ /** Disabled-level tooltip for picks an inherited grant already covers. */
51
+ granteeLevelInheritedCovered: {
52
+ id: string;
53
+ };
54
+ /**
55
+ * Error toast for a write the backend refused as an escalation. Distinct from the
56
+ * generic failure: the change was rejected on purpose, retrying will not help.
57
+ */
58
+ toastEscalationRefused: {
59
+ id: string;
60
+ };
50
61
  granteeYou: {
51
62
  id: string;
52
63
  };
@@ -1 +1 @@
1
- {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/share/messages.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;IAO5B;;;;OAIG;;;;IAEH;;;OAGG;;;;IAEH;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWL,CAAC"}
1
+ {"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../src/share/messages.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;IAO5B;;;;OAIG;;;;IAEH;;;OAGG;;;;IAEH;;;OAGG;;;;IAEH,0EAA0E;;;;IAE1E;;;OAGG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWL,CAAC"}
@@ -31,6 +31,13 @@ export const objectShareMessages = defineMessages({
31
31
  * access is inherited only — there is no grant in this workspace to revoke.
32
32
  */
33
33
  granteeRemoveInherited: { id: "objectShare.granteeRemove.inherited" },
34
+ /** Disabled-level tooltip for picks an inherited grant already covers. */
35
+ granteeLevelInheritedCovered: { id: "objectShare.granteeLevel.inheritedCovered" },
36
+ /**
37
+ * Error toast for a write the backend refused as an escalation. Distinct from the
38
+ * generic failure: the change was rejected on purpose, retrying will not help.
39
+ */
40
+ toastEscalationRefused: { id: "objectShare.toast.escalationRefused" },
34
41
  granteeYou: { id: "objectShare.grantee.you" },
35
42
  adminTagLabel: { id: "objectShare.adminTag.label" },
36
43
  adminTagTooltip: { id: "objectShare.adminTag.tooltip" },
@@ -90,10 +90,11 @@ export interface IObjectShareControllerState {
90
90
  summary: IObjectAccessSummary | undefined;
91
91
  grantees: IObjectShareGrantee[];
92
92
  /**
93
- * Id of the grantee row whose permission menu manages the signed-in user's
94
- * OWN access set only when the sole explicit grant is the caller's own
95
- * (the "restrict own access" design). Consumers gate lowering behind a
96
- * confirm and disable the levels above the row's own.
93
+ * Id of the grantee row whose permission menu manages the signed-in user's OWN
94
+ * access (the "restrict own access" design), whatever else is listed. Consumers
95
+ * gate lowering behind a confirm and disable the levels above the row's own.
96
+ * Undefined for a workspace manager (their access is not this grant) and while
97
+ * their identity is unresolved, which `granteeControlsLocked` covers.
97
98
  */
98
99
  selfManagedGranteeId: string | undefined;
99
100
  /**
@@ -110,10 +111,11 @@ export interface IObjectShareControllerState {
110
111
  */
111
112
  workspaceDisabledLevels: ObjectSharePermissionLevel[] | undefined;
112
113
  /**
113
- * Whether grantee-row controls must stay disabled because a sole USER row
114
- * cannot be told apart from the caller's own grant yet (profile pending or
115
- * silently failed) — mutating it then would bypass the self-restriction
116
- * confirm. Group rows and multi-row lists never set this.
114
+ * Whether USER-row controls must stay disabled because no row can be told apart
115
+ * from the caller's own grant yet (profile pending or silently failed) — mutating
116
+ * one then would bypass the self-restriction confirm and can lose access for good.
117
+ * Set however many rows are listed. Group rows are never the caller, and a known
118
+ * workspace manager needs no confirm, so neither sets this.
117
119
  */
118
120
  granteeControlsLocked: boolean;
119
121
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"objectShareController.types.d.ts","sourceRoot":"","sources":["../../src/share/objectShareController.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"objectShareController.types.d.ts","sourceRoot":"","sources":["../../src/share/objectShareController.types.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { IObjectPermissionsObject } from "@gooddata/sdk-backend-spi";
1
+ import { type IObjectPermissionsObject } from "@gooddata/sdk-backend-spi";
2
2
  import { type IGranularAccessGrantee } from "@gooddata/sdk-model";
3
3
  import { type GoodDataSdkError } from "@gooddata/sdk-ui";
4
4
  import { type GeneralAccessValue, type IUiGranteeAsyncOptions } from "@gooddata/sdk-ui-kit";
@@ -23,8 +23,26 @@ export interface IAccessList {
23
23
  * way in must not read as grant-independent after locally removing it.
24
24
  */
25
25
  seededWithoutSelfGrant: boolean;
26
+ /**
27
+ * Whether the SEED's workspace rule was share-capable (SHARE or EDIT, own or
28
+ * inherited). Load-time fact like {@link seededWithoutSelfGrant}: the Admin badge
29
+ * infers how the caller ENTERED, so restricting the rule mid-session must not
30
+ * start reading as admin access.
31
+ */
32
+ seededRuleShareCapable: boolean;
26
33
  /** Signed-in user's identity facts + login id, once the profile resolves. */
27
34
  selfIdentity: ISelfIdentity | undefined;
35
+ /**
36
+ * Whether the caller manages this workspace (org admins arrive through the same
37
+ * MANAGE permission), or **undefined** while the read is pending or after it failed.
38
+ *
39
+ * Read it in the direction the policy needs. A protective policy (the
40
+ * self-restriction confirm, the row lock) may treat undefined as "not a manager",
41
+ * since a needless confirm is harmless. A restrictive one (a limit on what may be
42
+ * granted) must require an explicit `false`, or a failed read would block a caller
43
+ * the backend would allow.
44
+ */
45
+ isWorkspaceManager: boolean | undefined;
28
46
  /**
29
47
  * Whether the profile resolved. Until then a sole grantee row can't be told apart
30
48
  * from the caller's own grant, so its `isSelf` is only an unresolved default.
@@ -1 +1 @@
1
- {"version":3,"file":"useAccessList.d.ts","sourceRoot":"","sources":["../../src/share/useAccessList.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAC1E,OAAO,EACH,KAAK,sBAAsB,EAK9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACH,KAAK,gBAAgB,EAKxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,sBAAsB,EAAmB,MAAM,sBAAsB,CAAC;AAS7G,OAAO,EAEH,KAAK,SAAS,EASjB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EACR,2BAA2B,EAC3B,mBAAmB,EACnB,aAAa,EACb,0BAA0B,EAC7B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IACxB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC;;;;;;OAMG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC,6EAA6E;IAC7E,YAAY,EAAE,aAAa,GAAG,SAAS,CAAC;IACxC;;;OAGG;IACH,oBAAoB,EAAE,OAAO,CAAC;IAC9B,8DAA8D;IAC9D,aAAa,EAAE,kBAAkB,CAAC;IAClC,oFAAkF;IAClF,cAAc,EAAE,0BAA0B,CAAC;IAC3C;;;OAGG;IACH,uBAAuB,EAAE,0BAA0B,GAAG,SAAS,CAAC;IAChE,wFAAwF;IACxF,oBAAoB,EAAE,OAAO,CAAC;IAC9B,iFAAiF;IACjF,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC1C,qDAAqD;IACrD,MAAM,EAAE,2BAA2B,CAAC,QAAQ,CAAC,CAAC;IAC9C,mDAAmD;IACnD,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAExC,mFAAmF;IACnF,MAAM,EAAE,CAAC,MAAM,EAAE,sBAAsB,EAAE,EAAE,cAAc,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/F,+FAA6F;IAC7F,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAEjE;;;;OAIG;IACH,eAAe,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACxD;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAC3E;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gFAAgF;IAChF,kBAAkB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,iEAAiE;IACjE,iBAAiB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAEtC,oFAAoF;IACpF,aAAa,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,IAAI,CAAC;IAC1D,6DAA6D;IAC7D,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,8FAA8F;IAC9F,YAAY,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,GAAG,WAAW,CA8SvF"}
1
+ {"version":3,"file":"useAccessList.d.ts","sourceRoot":"","sources":["../../src/share/useAccessList.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,wBAAwB,EAAiC,MAAM,2BAA2B,CAAC;AACzG,OAAO,EACH,KAAK,sBAAsB,EAM9B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACH,KAAK,gBAAgB,EAKxB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,KAAK,kBAAkB,EAAE,KAAK,sBAAsB,EAAmB,MAAM,sBAAsB,CAAC;AAU7G,OAAO,EAEH,KAAK,SAAS,EASjB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EACR,2BAA2B,EAC3B,mBAAmB,EACnB,aAAa,EACb,0BAA0B,EAC7B,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;GAIG;AACH,MAAM,WAAW,WAAW;IACxB,oDAAoD;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC;;;;;;OAMG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC;;;;;OAKG;IACH,sBAAsB,EAAE,OAAO,CAAC;IAChC,6EAA6E;IAC7E,YAAY,EAAE,aAAa,GAAG,SAAS,CAAC;IACxC;;;;;;;;;OASG;IACH,kBAAkB,EAAE,OAAO,GAAG,SAAS,CAAC;IACxC;;;OAGG;IACH,oBAAoB,EAAE,OAAO,CAAC;IAC9B,8DAA8D;IAC9D,aAAa,EAAE,kBAAkB,CAAC;IAClC,oFAAkF;IAClF,cAAc,EAAE,0BAA0B,CAAC;IAC3C;;;OAGG;IACH,uBAAuB,EAAE,0BAA0B,GAAG,SAAS,CAAC;IAChE,wFAAwF;IACxF,oBAAoB,EAAE,OAAO,CAAC;IAC9B,iFAAiF;IACjF,OAAO,EAAE,oBAAoB,GAAG,SAAS,CAAC;IAC1C,qDAAqD;IACrD,MAAM,EAAE,2BAA2B,CAAC,QAAQ,CAAC,CAAC;IAC9C,mDAAmD;IACnD,SAAS,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAExC,mFAAmF;IACnF,MAAM,EAAE,CAAC,MAAM,EAAE,sBAAsB,EAAE,EAAE,cAAc,EAAE;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/F,+FAA6F;IAC7F,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAEjE;;;;OAIG;IACH,eAAe,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACxD;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;IAC3E;;;;OAIG;IACH,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gFAAgF;IAChF,kBAAkB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,iEAAiE;IACjE,iBAAiB,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAEtC,oFAAoF;IACpF,aAAa,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,SAAS,CAAC,KAAK,IAAI,CAAC;IAC1D,6DAA6D;IAC7D,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,8FAA8F;IAC9F,YAAY,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,GAAG,WAAW,CAsUvF"}
@@ -1,9 +1,10 @@
1
1
  // (C) 2026 GoodData Corporation
2
2
  import { useCallback, useMemo, useState } from "react";
3
+ import { isPermissionEscalationRefused } from "@gooddata/sdk-backend-spi";
3
4
  import { idRef, objRefToString, serializeObjRef, } from "@gooddata/sdk-model";
4
5
  import { convertError, useBackendStrict, useCancelablePromise, useWorkspaceStrict, } from "@gooddata/sdk-ui";
5
6
  import { useToastMessage } from "@gooddata/sdk-ui-kit";
6
- import { composeEffectiveWorkspaceAccess, deriveGeneralAccess, deriveInheritedWorkspaceLevel, deriveWorkspacePermissionLevel, } from "./accessSummary.js";
7
+ import { accessListToSummary, composeEffectiveWorkspaceAccess, deriveGeneralAccess, deriveInheritedWorkspaceLevel, deriveWorkspacePermissionLevel, } from "./accessSummary.js";
7
8
  import { objectShareMessages } from "./messages.js";
8
9
  import { assigneeIdentityFacts, assigneeMatchesQuery, granteeId, granteesFromAccessList, mergeGrantees, userDisplayPair, userIdentityFacts, withDirectLevel, } from "./objectShareController.helpers.js";
9
10
  /**
@@ -51,10 +52,21 @@ export function useAccessList(target) {
51
52
  // Success only: while pending or after a swallowed failure a sole row can't be told
52
53
  // apart from the caller's own grant, so it must not be treated as safe to mutate.
53
54
  const selfIdentityResolved = currentUserStatus === "success";
55
+ // Read straight from the backend, like the profile above, and keyed on it: the shared
56
+ // per-workspace loader caches one answer for the workspace, so after a backend swap it
57
+ // would hand back the PREVIOUS user's permissions and the policies below would trust it.
58
+ const { result: workspacePermissions } = useCancelablePromise({
59
+ promise: async () => backend.workspace(workspace).permissions().getPermissionsForCurrentUser(),
60
+ onError: () => { },
61
+ }, [backend, workspace]);
62
+ const isWorkspaceManager = workspacePermissions?.canManageProject;
54
63
  const selfId = currentUser ? granteeId("user", idRef(currentUser.login)) : undefined;
55
64
  // Derived from the immutable SEED (see the interface doc): a caller whose own
56
65
  // grant was the way in must not read as grant-independent after removing it.
57
66
  const seededWithoutSelfGrant = hasList && selfIdentityResolved && !base.some((g) => g.id === selfId);
67
+ // Seed only, never the rule overlay; `accessListToSummary` so this cannot drift.
68
+ const seededSummary = hasList ? accessListToSummary(fetchedList) : undefined;
69
+ const seededRuleShareCapable = seededSummary?.generalAccess === "WORKSPACE" && seededSummary.workspaceLevel !== "VIEW";
58
70
  // De-collapsed like every listing fact — on tiger the user id is often the email.
59
71
  const selfIdentity = useMemo(() => currentUser
60
72
  ? {
@@ -106,8 +118,11 @@ export function useAccessList(target) {
106
118
  toast.addSuccess(successMessage);
107
119
  return true;
108
120
  }
109
- catch {
110
- toast.addError(objectShareMessages.toastError);
121
+ catch (error) {
122
+ // A refused escalation is a deliberate "no", not a failure to retry.
123
+ toast.addError(isPermissionEscalationRefused(error)
124
+ ? objectShareMessages.toastEscalationRefused
125
+ : objectShareMessages.toastError);
111
126
  return false;
112
127
  }
113
128
  }, [backend, workspace, target, toast]);
@@ -244,7 +259,9 @@ export function useAccessList(target) {
244
259
  hasList,
245
260
  grantees,
246
261
  seededWithoutSelfGrant,
262
+ seededRuleShareCapable,
247
263
  selfIdentity,
264
+ isWorkspaceManager,
248
265
  selfIdentityResolved,
249
266
  generalAccess,
250
267
  workspaceLevel,
@@ -1 +1 @@
1
- {"version":3,"file":"useObjectShareController.d.ts","sourceRoot":"","sources":["../../src/share/useObjectShareController.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAkB1E,OAAO,EACH,KAAK,sBAAsB,EAI3B,KAAK,sBAAsB,EAE9B,MAAM,kCAAkC,CAAC;AAI1C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,wBAAwB,GAAG,SAAS,EAC5C,OAAO,CAAC,EAAE,sBAAsB,GACjC,sBAAsB,CAkxBxB"}
1
+ {"version":3,"file":"useObjectShareController.d.ts","sourceRoot":"","sources":["../../src/share/useObjectShareController.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAkB1E,OAAO,EACH,KAAK,sBAAsB,EAI3B,KAAK,sBAAsB,EAE9B,MAAM,kCAAkC,CAAC;AAI1C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,wBAAwB,CACpC,MAAM,EAAE,wBAAwB,GAAG,SAAS,EAC5C,OAAO,CAAC,EAAE,sBAAsB,GACjC,sBAAsB,CAwxBxB"}
@@ -35,7 +35,7 @@ export function useObjectShareController(target, options) {
35
35
  const [subview, setSubview] = useState("main");
36
36
  const [pendingGrantees, setPendingGrantees] = useState([]);
37
37
  const [pendingGeneralAccess, setPendingGeneralAccess] = useState(undefined);
38
- const { hasList, grantees, seededWithoutSelfGrant, selfIdentity, selfIdentityResolved, generalAccess, workspaceLevel, workspaceInheritedLevel, workspaceLevelSaving, summary, status, loadError, commit, loadOptions, applyGranteeAdd, applyGranteeLevel, applyGranteeLock, applyGranteeRemove, settleGranteeEdit, failGranteeEdit, applyRuleEdit, settleRuleEdit, failRuleEdit, } = useAccessList(target);
38
+ const { hasList, grantees, seededWithoutSelfGrant, seededRuleShareCapable, selfIdentity, isWorkspaceManager, selfIdentityResolved, generalAccess, workspaceLevel, workspaceInheritedLevel, workspaceLevelSaving, summary, status, loadError, commit, loadOptions, applyGranteeAdd, applyGranteeLevel, applyGranteeLock, applyGranteeRemove, settleGranteeEdit, failGranteeEdit, applyRuleEdit, settleRuleEdit, failRuleEdit, } = useAccessList(target);
39
39
  // Grantee ids the label-scope probe resolves against — a removing row is excluded
40
40
  // so its scope is dropped, not re-seeded.
41
41
  const committedGranteeIds = useMemo(() => {
@@ -605,20 +605,23 @@ export function useObjectShareController(target, options) {
605
605
  const state = useMemo(() => {
606
606
  // Row policy is classified here, not in the dialog, so a consumer
607
607
  // injecting this controller into its own UI gets the same classification.
608
- const selfManagedGranteeId = grantees.length === 1 && grantees[0].isSelf ? grantees[0].id : undefined;
609
- const granteeControlsLocked = grantees.length === 1 && grantees[0].kind === "user" && !selfIdentityResolved;
610
- // A workspace-wide share-capable rule (SHARE or EDIT) is the one way other
611
- // than admin/manager rights through the manage gate no Admin badge then.
612
- const workspaceShareCapable = effectiveWorkspace.generalAccess === "WORKSPACE" && effectiveWorkspace.workspaceLevel !== "VIEW";
608
+ // The policy follows the self row however many others are listed: what makes
609
+ // it special is that the access is THEIRS. A manager is exempt, their access
610
+ // comes from the role, so there is no ceiling to cap and no lockout to warn of.
611
+ const selfRow = isWorkspaceManager ? undefined : grantees.find((g) => g.isSelf);
612
+ const selfManagedGranteeId = selfRow?.id;
613
+ const granteeControlsLocked = !selfIdentityResolved && !isWorkspaceManager && grantees.some((g) => g.kind === "user");
613
614
  // The synthesized Admin row shows only while NO other permissions are set:
614
615
  // the caller must have reached the list without a grant of their own
615
616
  // (`seededWithoutSelfGrant` — a non-admin who locally removes their own
616
617
  // grant must not gain the badge) and the list must currently be empty, so
617
618
  // adding a grantee hides it and removing the last one brings it back.
619
+ // A share-capable rule also passes the gate, judged from the SEED. A group
620
+ // grant is another way in this cannot see: the heuristic's accepted blind spot.
618
621
  const adminSelfRow = status === "success" &&
619
622
  seededWithoutSelfGrant &&
620
623
  grantees.length === 0 &&
621
- !workspaceShareCapable &&
624
+ !seededRuleShareCapable &&
622
625
  selfIdentity
623
626
  ? userDisplayPair(selfIdentity, selfIdentity.id)
624
627
  : undefined;
@@ -629,9 +632,9 @@ export function useObjectShareController(target, options) {
629
632
  summary,
630
633
  grantees: sortedGrantees,
631
634
  selfManagedGranteeId,
632
- // Policy, not just classification: the caller's own sole row can't be
633
- // raised above itself, an inherited workspace level can't be undercut.
634
- selfManagedDisabledLevels: selfManagedGranteeId ? levelsAbove(grantees[0].level) : undefined,
635
+ // Policy, not just classification: the caller's own row can't be raised
636
+ // above itself, an inherited workspace level can't be undercut.
637
+ selfManagedDisabledLevels: selfRow ? levelsAbove(selfRow.level) : undefined,
635
638
  workspaceDisabledLevels: workspaceInheritedLevel
636
639
  ? levelsBelow(workspaceInheritedLevel)
637
640
  : undefined,
@@ -656,7 +659,9 @@ export function useObjectShareController(target, options) {
656
659
  summary,
657
660
  selfIdentity,
658
661
  selfIdentityResolved,
662
+ isWorkspaceManager,
659
663
  seededWithoutSelfGrant,
664
+ seededRuleShareCapable,
660
665
  grantees,
661
666
  sortedGrantees,
662
667
  effectiveWorkspace,
@@ -40,10 +40,12 @@ export interface IObjectShareDialogViewModel {
40
40
  /** The controller's workspace-rule menu policy, forwarded (see `IObjectShareControllerState`). */
41
41
  workspaceDisabledLevels: ObjectSharePermissionLevel[] | undefined;
42
42
  /**
43
- * The controller's self-managed-row policy resolved per row: its disabled levels
44
- * for the signed-in user's own sole grant, undefined for every other row.
43
+ * Level picks a row must render disabled: the self-managed-row policy plus every
44
+ * pick an inherited grant already covers.
45
45
  */
46
46
  rowDisabledLevels: (grantee: IObjectShareGrantee) => ObjectSharePermissionLevel[] | undefined;
47
+ /** Per-level tooltips for the disabled picks an inherited grant covers. */
48
+ rowDisabledLevelTooltips: (grantee: IObjectShareGrantee) => Partial<Record<ObjectSharePermissionLevel, string>> | undefined;
47
49
  /**
48
50
  * Whether Remove access must render disabled: the grantee holds no grant in this
49
51
  * workspace, so there is nothing here to revoke (their access is inherited).
@@ -51,6 +53,8 @@ export interface IObjectShareDialogViewModel {
51
53
  isRowRemoveDisabled: (grantee: IObjectShareGrantee) => boolean;
52
54
  /** Tooltip explaining why Remove access is disabled on this row. */
53
55
  rowRemoveDisabledTooltip: string;
56
+ /** Whether this row's controls must stay disabled (see `granteeControlsLocked`). */
57
+ isRowControlsLocked: (grantee: IObjectShareGrantee) => boolean;
54
58
  /** Close the whole dialog, discarding any staged self-restriction. */
55
59
  onClose: () => void;
56
60
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"useObjectShareDialog.d.ts","sourceRoot":"","sources":["../../src/share/useObjectShareDialog.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAI1E,OAAO,EACH,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAClC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAY1E;;;;;;;GAOG;AACH,MAAM,WAAW,2BAA2B;IACxC,yFAAyF;IACzF,KAAK,EAAE,2BAA2B,CAAC;IACnC,yEAAyE;IACzE,OAAO,EAAE,6BAA6B,CAAC;IAEvC,8EAA8E;IAC9E,eAAe,EAAE,OAAO,CAAC;IACzB,qDAAqD;IACrD,gBAAgB,EAAE,OAAO,CAAC;IAC1B,4EAA0E;IAC1E,0BAA0B,EAAE,OAAO,CAAC;IACpC,+EAA+E;IAC/E,yBAAyB,EAAE,OAAO,CAAC;IAEnC;;;;;OAKG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB,kGAAkG;IAClG,uBAAuB,EAAE,0BAA0B,EAAE,GAAG,SAAS,CAAC;IAClE;;;OAGG;IACH,iBAAiB,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,0BAA0B,EAAE,GAAG,SAAS,CAAC;IAC9F;;;OAGG;IACH,mBAAmB,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC;IAC/D,oEAAoE;IACpE,wBAAwB,EAAE,MAAM,CAAC;IAEjC,sEAAsE;IACtE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;OAGG;IACH,qBAAqB,EAAE,CAAC,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACjG,qGAAqG;IACrG,WAAW,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACpD,qFAAqF;IACrF,oBAAoB,EAAE,MAAM,IAAI,CAAC;IACjC,+FAA6F;IAC7F,qBAAqB,EAAE,MAAM,IAAI,CAAC;CACrC;AAED;;;;GAIG;AACH,UAAU,2BAA2B;IACjC,wFAAsF;IACtF,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC7C,oGAAoG;IACpG,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,mFAAmF;IACnF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC1D,2FAA2F;IAC3F,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC7B,oGAAoG;IACpG,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iGAAiG;IACjG,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,MAAM,EACN,OAAO,EACP,eAAe,EACf,MAAM,EACN,aAAa,EACb,WAAW,EACd,EAAE,2BAA2B,GAAG,2BAA2B,CA6G3D"}
1
+ {"version":3,"file":"useObjectShareDialog.d.ts","sourceRoot":"","sources":["../../src/share/useObjectShareDialog.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAQ1E,OAAO,EACH,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAClC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAsB1E;;;;;;;GAOG;AACH,MAAM,WAAW,2BAA2B;IACxC,yFAAyF;IACzF,KAAK,EAAE,2BAA2B,CAAC;IACnC,yEAAyE;IACzE,OAAO,EAAE,6BAA6B,CAAC;IAEvC,8EAA8E;IAC9E,eAAe,EAAE,OAAO,CAAC;IACzB,qDAAqD;IACrD,gBAAgB,EAAE,OAAO,CAAC;IAC1B,4EAA0E;IAC1E,0BAA0B,EAAE,OAAO,CAAC;IACpC,+EAA+E;IAC/E,yBAAyB,EAAE,OAAO,CAAC;IAEnC;;;;;OAKG;IACH,SAAS,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB,kGAAkG;IAClG,uBAAuB,EAAE,0BAA0B,EAAE,GAAG,SAAS,CAAC;IAClE;;;OAGG;IACH,iBAAiB,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,0BAA0B,EAAE,GAAG,SAAS,CAAC;IAC9F,2EAA2E;IAC3E,wBAAwB,EAAE,CACtB,OAAO,EAAE,mBAAmB,KAC3B,OAAO,CAAC,MAAM,CAAC,0BAA0B,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,CAAC;IACrE;;;OAGG;IACH,mBAAmB,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC;IAC/D,oEAAoE;IACpE,wBAAwB,EAAE,MAAM,CAAC;IACjC,oFAAoF;IACpF,mBAAmB,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,OAAO,CAAC;IAE/D,sEAAsE;IACtE,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB;;;OAGG;IACH,qBAAqB,EAAE,CAAC,OAAO,EAAE,mBAAmB,EAAE,KAAK,EAAE,0BAA0B,KAAK,IAAI,CAAC;IACjG,qGAAqG;IACrG,WAAW,EAAE,CAAC,OAAO,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACpD,qFAAqF;IACrF,oBAAoB,EAAE,MAAM,IAAI,CAAC;IACjC,+FAA6F;IAC7F,qBAAqB,EAAE,MAAM,IAAI,CAAC;CACrC;AAED;;;;GAIG;AACH,UAAU,2BAA2B;IACjC,wFAAsF;IACtF,MAAM,EAAE,wBAAwB,GAAG,SAAS,CAAC;IAC7C,oGAAoG;IACpG,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,mFAAmF;IACnF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC1D,2FAA2F;IAC3F,MAAM,CAAC,EAAE,iBAAiB,EAAE,CAAC;IAC7B,oGAAoG;IACpG,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,iGAAiG;IACjG,WAAW,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,EACjC,MAAM,EACN,OAAO,EACP,eAAe,EACf,MAAM,EACN,aAAa,EACb,WAAW,EACd,EAAE,2BAA2B,GAAG,2BAA2B,CAwI3D"}
@@ -2,8 +2,17 @@
2
2
  import { useCallback, useEffect, useState } from "react";
3
3
  import { useIntl } from "react-intl";
4
4
  import { objectShareMessages } from "./messages.js";
5
- import { changesEffectiveLevel, removalChangesEffectiveLevel } from "./objectShareController.helpers.js";
5
+ import { changesEffectiveLevel, levelsBelow, removalChangesEffectiveLevel, } from "./objectShareController.helpers.js";
6
6
  import { useObjectShareController } from "./useObjectShareController.js";
7
+ /**
8
+ * Level picks an inherited grant already covers, which the controller refuses as
9
+ * no-ops ({@link changesEffectiveLevel}). Lowering a direct grant that sits ABOVE
10
+ * what is inherited is NOT one of them: that does move the effective level (direct
11
+ * EDIT under inherited SHARE, picking VIEW yields SHARE).
12
+ */
13
+ function inheritedCoveredLevels(grantee) {
14
+ return removalChangesEffectiveLevel(grantee) ? [] : levelsBelow(grantee.level);
15
+ }
7
16
  /**
8
17
  * Owns everything {@link ObjectShareDialog} needs to render for one dialog session:
9
18
  * the controller, the self-restriction confirm flow, the mutation-gating flags, and
@@ -72,12 +81,28 @@ export function useObjectShareDialog({ target, onClose, onSummaryChange, labels,
72
81
  }
73
82
  }, [pendingSelfChange, actions]);
74
83
  const onSelfRestrictCancel = useCallback(() => setPendingSelfChange(undefined), []);
75
- const rowDisabledLevels = useCallback((grantee) => state.selfManagedGranteeId === grantee.id ? state.selfManagedDisabledLevels : undefined, [state.selfManagedGranteeId, state.selfManagedDisabledLevels]);
76
- // Levels below an inherited one are deliberately NOT disabled: lowering the
77
- // direct grant still reduces the effective level whenever it sits above what is
78
- // inherited (direct EDIT under an inherited SHARE picking VIEW yields SHARE).
79
- // The row's warning badge is what explains the inherited floor.
84
+ const inheritedCoveredTooltip = intl.formatMessage(objectShareMessages.granteeLevelInheritedCovered);
85
+ const rowDisabledLevels = useCallback((grantee) => {
86
+ const self = state.selfManagedGranteeId === grantee.id ? (state.selfManagedDisabledLevels ?? []) : [];
87
+ // Disjoint: self caps levels ABOVE the row, coverage disables those BELOW.
88
+ const merged = [...self, ...inheritedCoveredLevels(grantee)];
89
+ return merged.length > 0 ? merged : undefined;
90
+ }, [state.selfManagedGranteeId, state.selfManagedDisabledLevels]);
91
+ const rowDisabledLevelTooltips = useCallback((grantee) => {
92
+ const covered = inheritedCoveredLevels(grantee);
93
+ if (covered.length === 0) {
94
+ return undefined;
95
+ }
96
+ const map = {};
97
+ for (const level of covered) {
98
+ map[level] = inheritedCoveredTooltip;
99
+ }
100
+ return map;
101
+ }, [inheritedCoveredTooltip]);
80
102
  const isRowRemoveDisabled = useCallback((grantee) => grantee.directLevel === undefined, []);
103
+ // Only USER rows can be the caller's own, so a group row stays usable while the
104
+ // profile is unresolved.
105
+ const isRowControlsLocked = useCallback((grantee) => state.granteeControlsLocked && grantee.kind === "user", [state.granteeControlsLocked]);
81
106
  const isMutable = state.status === "success" && state.labelsResolved;
82
107
  const isLoading = state.status === "loading" || state.labelsInitializing;
83
108
  return {
@@ -91,7 +116,9 @@ export function useObjectShareDialog({ target, onClose, onSummaryChange, labels,
91
116
  isLoading,
92
117
  workspaceDisabledLevels: state.workspaceDisabledLevels,
93
118
  rowDisabledLevels,
119
+ rowDisabledLevelTooltips,
94
120
  isRowRemoveDisabled,
121
+ isRowControlsLocked,
95
122
  rowRemoveDisabledTooltip: intl.formatMessage(objectShareMessages.granteeRemoveInherited),
96
123
  onClose,
97
124
  onRowPermissionChange,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gooddata/sdk-ui-ext",
3
- "version": "11.53.0-alpha.6",
3
+ "version": "11.53.0-alpha.7",
4
4
  "description": "GoodData.UI SDK - Extensions",
5
5
  "license": "LicenseRef-LICENSE",
6
6
  "author": "GoodData Corporation",
@@ -63,20 +63,20 @@
63
63
  "ts-invariant": "0.10.3",
64
64
  "tslib": "2.8.1",
65
65
  "uuid": "11.1.1",
66
- "@gooddata/sdk-backend-spi": "11.53.0-alpha.6",
67
- "@gooddata/sdk-backend-base": "11.53.0-alpha.6",
68
- "@gooddata/sdk-embedding": "11.53.0-alpha.6",
69
- "@gooddata/sdk-model": "11.53.0-alpha.6",
70
- "@gooddata/sdk-ui": "11.53.0-alpha.6",
71
- "@gooddata/sdk-ui-filters": "11.53.0-alpha.6",
72
- "@gooddata/sdk-ui-geo": "11.53.0-alpha.6",
73
- "@gooddata/sdk-ui-charts": "11.53.0-alpha.6",
74
- "@gooddata/sdk-ui-kit": "11.53.0-alpha.6",
75
- "@gooddata/sdk-ui-pivot": "11.53.0-alpha.6",
76
- "@gooddata/sdk-ui-semantic-search": "11.53.0-alpha.6",
77
- "@gooddata/sdk-ui-vis-commons": "11.53.0-alpha.6",
78
- "@gooddata/sdk-ui-theme-provider": "11.53.0-alpha.6",
79
- "@gooddata/util": "11.53.0-alpha.6"
66
+ "@gooddata/sdk-backend-base": "11.53.0-alpha.7",
67
+ "@gooddata/sdk-backend-spi": "11.53.0-alpha.7",
68
+ "@gooddata/sdk-embedding": "11.53.0-alpha.7",
69
+ "@gooddata/sdk-model": "11.53.0-alpha.7",
70
+ "@gooddata/sdk-ui": "11.53.0-alpha.7",
71
+ "@gooddata/sdk-ui-charts": "11.53.0-alpha.7",
72
+ "@gooddata/sdk-ui-geo": "11.53.0-alpha.7",
73
+ "@gooddata/sdk-ui-kit": "11.53.0-alpha.7",
74
+ "@gooddata/sdk-ui-pivot": "11.53.0-alpha.7",
75
+ "@gooddata/sdk-ui-filters": "11.53.0-alpha.7",
76
+ "@gooddata/sdk-ui-semantic-search": "11.53.0-alpha.7",
77
+ "@gooddata/sdk-ui-theme-provider": "11.53.0-alpha.7",
78
+ "@gooddata/sdk-ui-vis-commons": "11.53.0-alpha.7",
79
+ "@gooddata/util": "11.53.0-alpha.7"
80
80
  },
81
81
  "devDependencies": {
82
82
  "@microsoft/api-documenter": "^7.17.0",
@@ -124,12 +124,12 @@
124
124
  "typescript": "5.9.3",
125
125
  "vitest": "4.1.8",
126
126
  "vitest-dom": "0.1.1",
127
- "@gooddata/eslint-config": "11.53.0-alpha.6",
128
- "@gooddata/i18n-toolkit": "11.53.0-alpha.6",
129
- "@gooddata/oxlint-config": "11.53.0-alpha.6",
130
- "@gooddata/reference-workspace": "11.53.0-alpha.6",
131
- "@gooddata/sdk-backend-mockingbird": "11.53.0-alpha.6",
132
- "@gooddata/stylelint-config": "11.53.0-alpha.6"
127
+ "@gooddata/eslint-config": "11.53.0-alpha.7",
128
+ "@gooddata/reference-workspace": "11.53.0-alpha.7",
129
+ "@gooddata/i18n-toolkit": "11.53.0-alpha.7",
130
+ "@gooddata/oxlint-config": "11.53.0-alpha.7",
131
+ "@gooddata/sdk-backend-mockingbird": "11.53.0-alpha.7",
132
+ "@gooddata/stylelint-config": "11.53.0-alpha.7"
133
133
  },
134
134
  "peerDependencies": {
135
135
  "react": "^18.0.0 || ^19.0.0",
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=geoConfigBuilder.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"geoConfigBuilder.test.d.ts","sourceRoot":"","sources":["../../../../../src/internal/components/pluggableVisualizations/geoChartNext/geoConfigBuilder.test.ts"],"names":[],"mappings":""}
@@ -1,415 +0,0 @@
1
- // (C) 2025-2026 GoodData Corporation
2
- import { describe, expect, it } from "vitest";
3
- import { idRef, newAttribute, newBucket, newInsightDefinition } from "@gooddata/sdk-model";
4
- import { BucketNames } from "@gooddata/sdk-ui";
5
- import { ANALYTICAL_ENVIRONMENT, DASHBOARDS_ENVIRONMENT } from "../../../constants/properties.js";
6
- import { buildAreaVisualizationConfig } from "../geoAreaChart/geoAreaConfigBuilder.js";
7
- import { buildGeoVisualizationConfig, geoConfigFromInsight, geoInsightConversion, } from "./geoConfigBuilder.js";
8
- describe("geoConfigFromInsight", () => {
9
- it("keeps mapStyle configuration", () => {
10
- const areaAttribute = newAttribute(idRef("label.area", "displayForm"), (attribute) => attribute.localId("area_df"));
11
- const insight = newInsightDefinition("local:geoArea", (builder) => builder.buckets([newBucket(BucketNames.AREA, areaAttribute)]).properties({
12
- controls: {
13
- mapStyle: "gd://custom-style",
14
- },
15
- }));
16
- const config = geoConfigFromInsight(insight);
17
- expect(config.mapStyle).toBe("gd://custom-style");
18
- });
19
- it("keeps zoom configuration", () => {
20
- const areaAttribute = newAttribute(idRef("label.area", "displayForm"), (attribute) => attribute.localId("area_df"));
21
- const insight = newInsightDefinition("local:geoArea", (builder) => builder.buckets([newBucket(BucketNames.AREA, areaAttribute)]).properties({
22
- controls: {
23
- zoom: 4,
24
- },
25
- }));
26
- const config = geoConfigFromInsight(insight);
27
- expect(config.zoom).toBe(4);
28
- });
29
- it("normalizes legacy legend positions from insight properties", () => {
30
- const locationAttribute = newAttribute(idRef("nm_location", "displayForm"), (attribute) => attribute.localId("location_id"));
31
- const insight = newInsightDefinition("local:geoPushpin", (builder) => builder.buckets([newBucket(BucketNames.LOCATION, locationAttribute)]).properties({
32
- controls: {
33
- legend: {
34
- position: "top",
35
- },
36
- },
37
- }));
38
- const config = geoConfigFromInsight(insight);
39
- expect(config.legend?.position).toBe("top-right");
40
- });
41
- it("maps legacy tileset visualization properties to basemap", () => {
42
- const locationAttribute = newAttribute(idRef("nm_location", "displayForm"), (attribute) => attribute.localId("location_id"));
43
- const insight = newInsightDefinition("local:geoPushpin", (builder) => builder.buckets([newBucket(BucketNames.LOCATION, locationAttribute)]).properties({
44
- controls: {
45
- tileset: "satellite",
46
- viewport: {
47
- area: "continent_na",
48
- },
49
- },
50
- }));
51
- const config = geoConfigFromInsight(insight);
52
- expect(config.basemap).toBe("satellite");
53
- expect(config.viewport?.area).toBe("continent_na");
54
- });
55
- it("keeps explicit basemap values unchanged", () => {
56
- const locationAttribute = newAttribute(idRef("nm_location", "displayForm"), (attribute) => attribute.localId("location_id"));
57
- const insight = newInsightDefinition("local:geoPushpin", (builder) => builder.buckets([newBucket(BucketNames.LOCATION, locationAttribute)]).properties({
58
- controls: {
59
- basemap: "monochrome",
60
- tileset: "satellite",
61
- },
62
- }));
63
- const config = geoConfigFromInsight(insight);
64
- expect(config.basemap).toBe("monochrome");
65
- });
66
- it("keeps oneIcon points configuration", () => {
67
- const locationAttribute = newAttribute(idRef("nm_location", "displayForm"), (attribute) => attribute.localId("location_id"));
68
- const insight = newInsightDefinition("local:geoPushpin", (builder) => builder.buckets([newBucket(BucketNames.LOCATION, locationAttribute)]).properties({
69
- controls: {
70
- points: {
71
- shapeType: "oneIcon",
72
- icon: "airport",
73
- },
74
- },
75
- }));
76
- const config = geoConfigFromInsight(insight);
77
- expect(config.points).toEqual({
78
- shapeType: "oneIcon",
79
- icon: "airport",
80
- });
81
- });
82
- });
83
- describe("geoInsightConversion", () => {
84
- it("returns area bucket attribute when converting AREA bucket", () => {
85
- const areaAttribute = newAttribute(idRef("label.area", "displayForm"), (attribute) => attribute.localId("area_df"));
86
- const insight = newInsightDefinition("local:geoArea", (builder) => builder.buckets([newBucket(BucketNames.AREA, areaAttribute)]));
87
- const conversion = geoInsightConversion("area", BucketNames.AREA);
88
- const ctx = {};
89
- const attribute = conversion.itemAccessor(insight, ctx);
90
- expect(attribute?.attribute?.localIdentifier).toBe("area_df");
91
- });
92
- it("uses clean localId for latitude without a_ prefix", () => {
93
- const locationAttribute = newAttribute(idRef("nm_location", "displayForm"), (attribute) => attribute.localId("location_id"));
94
- const insight = newInsightDefinition("local:geoPushpin", (builder) => builder.buckets([newBucket(BucketNames.LOCATION, locationAttribute)]).properties({
95
- controls: {
96
- latitude: "nm_latitude",
97
- longitude: "nm_longitude",
98
- },
99
- }));
100
- const conversion = geoInsightConversion("latitude", BucketNames.LATITUDE);
101
- const ctx = {
102
- backend: { capabilities: { supportsSeparateLatitudeLongitudeLabels: true } },
103
- };
104
- const attribute = conversion.itemAccessor(insight, ctx);
105
- expect(attribute?.attribute?.localIdentifier).toBe("latitude_df");
106
- expect(attribute?.attribute?.displayForm).toEqual(idRef("nm_latitude", "displayForm"));
107
- });
108
- it("uses clean localId for longitude without a_ prefix", () => {
109
- const locationAttribute = newAttribute(idRef("nm_location", "displayForm"), (attribute) => attribute.localId("location_id"));
110
- const insight = newInsightDefinition("local:geoPushpin", (builder) => builder.buckets([newBucket(BucketNames.LOCATION, locationAttribute)]).properties({
111
- controls: {
112
- latitude: "nm_latitude",
113
- longitude: "nm_longitude",
114
- },
115
- }));
116
- const conversion = geoInsightConversion("longitude", BucketNames.LONGITUDE);
117
- const ctx = {
118
- backend: { capabilities: { supportsSeparateLatitudeLongitudeLabels: true } },
119
- };
120
- const attribute = conversion.itemAccessor(insight, ctx);
121
- expect(attribute?.attribute?.localIdentifier).toBe("longitude_df");
122
- expect(attribute?.attribute?.displayForm).toEqual(idRef("nm_longitude", "displayForm"));
123
- });
124
- });
125
- describe("buildGeoVisualizationConfig", () => {
126
- const options = {
127
- messages: {},
128
- };
129
- it("applies viewport navigation in dashboards, leaves embedded unset, and disables in AD", () => {
130
- const dashboardWidgetConfig = buildGeoVisualizationConfig({
131
- options: {
132
- ...options,
133
- config: {
134
- isInEditMode: false,
135
- },
136
- },
137
- supportedControls: {},
138
- colorMapping: undefined,
139
- environment: DASHBOARDS_ENVIRONMENT,
140
- });
141
- const embeddedConfig = buildGeoVisualizationConfig({
142
- options: {
143
- ...options,
144
- config: {},
145
- },
146
- supportedControls: {},
147
- colorMapping: undefined,
148
- environment: "",
149
- });
150
- const adConfig = buildGeoVisualizationConfig({
151
- options: {
152
- ...options,
153
- config: {
154
- isInEditMode: true,
155
- },
156
- },
157
- supportedControls: {},
158
- colorMapping: undefined,
159
- environment: ANALYTICAL_ENVIRONMENT,
160
- });
161
- expect(dashboardWidgetConfig.applyViewportNavigation).toBe(true);
162
- expect(embeddedConfig.applyViewportNavigation).toBeUndefined();
163
- expect(adConfig.applyViewportNavigation).toBe(false);
164
- });
165
- it("normalizes legacy legend positions and keeps new corner values", () => {
166
- const config = buildGeoVisualizationConfig({
167
- options,
168
- supportedControls: {
169
- legend: {
170
- position: "bottom",
171
- },
172
- },
173
- colorMapping: undefined,
174
- environment: "",
175
- });
176
- const configWithCorner = buildGeoVisualizationConfig({
177
- options,
178
- supportedControls: {
179
- legend: {
180
- position: "bottom-left",
181
- },
182
- },
183
- colorMapping: undefined,
184
- environment: "",
185
- });
186
- expect(config.legend?.position).toBe("bottom-right");
187
- expect(configWithCorner.legend?.position).toBe("bottom-left");
188
- });
189
- it("preserves basemap even when the broad basemap FF is disabled", () => {
190
- const supportedControls = {
191
- basemap: "none",
192
- };
193
- const disabledConfig = buildGeoVisualizationConfig({
194
- options,
195
- supportedControls,
196
- colorMapping: undefined,
197
- environment: ANALYTICAL_ENVIRONMENT,
198
- });
199
- const enabledConfig = buildGeoVisualizationConfig({
200
- options,
201
- supportedControls,
202
- colorMapping: undefined,
203
- environment: ANALYTICAL_ENVIRONMENT,
204
- featureFlags: { enableGeoBasemapConfig: true },
205
- });
206
- expect(disabledConfig.enableGeoBasemapConfig).toBe(false);
207
- expect(disabledConfig.basemap).toBe("none");
208
- expect(enabledConfig.enableGeoBasemapConfig).toBe(true);
209
- expect(enabledConfig.basemap).toBe("none");
210
- });
211
- it("does not let raw config or custom visualization config override sanitized supported controls", () => {
212
- const rawGeoStyleConfig = {
213
- basemap: "none",
214
- };
215
- const config = buildGeoVisualizationConfig({
216
- options: {
217
- ...options,
218
- config: {
219
- isInEditMode: false,
220
- ...rawGeoStyleConfig,
221
- },
222
- customVisualizationConfig: {
223
- ...rawGeoStyleConfig,
224
- },
225
- },
226
- supportedControls: {
227
- basemap: "monochrome",
228
- },
229
- colorMapping: undefined,
230
- environment: ANALYTICAL_ENVIRONMENT,
231
- });
232
- expect(config.basemap).toBe("monochrome");
233
- });
234
- it("maps legacy tileset supported controls to basemap", () => {
235
- const config = buildGeoVisualizationConfig({
236
- options: {
237
- ...options,
238
- config: {
239
- isInEditMode: false,
240
- },
241
- },
242
- supportedControls: {
243
- tileset: "satellite",
244
- },
245
- colorMapping: undefined,
246
- environment: ANALYTICAL_ENVIRONMENT,
247
- });
248
- expect(config.basemap).toBe("satellite");
249
- });
250
- it("does not forward bounds when viewport config is disabled", () => {
251
- const config = buildGeoVisualizationConfig({
252
- options,
253
- supportedControls: {
254
- center: { lat: 40, lng: -74 },
255
- zoom: 3,
256
- bounds: {
257
- southWest: { lat: 35, lng: -80 },
258
- northEast: { lat: 45, lng: -68 },
259
- },
260
- viewport: { area: "custom" },
261
- },
262
- colorMapping: undefined,
263
- environment: ANALYTICAL_ENVIRONMENT,
264
- featureFlags: {
265
- enableGeoChartsViewportConfig: false,
266
- },
267
- });
268
- expect(config.enableGeoChartsViewportConfig).toBe(false);
269
- expect(config.bounds).toBeUndefined();
270
- expect(config.center).toEqual({ lat: 40, lng: -74 });
271
- expect(config.zoom).toBe(3);
272
- });
273
- it("propagates customTooltip from supportedControls into the rendered config", () => {
274
- const customTooltip = {
275
- enabled: true,
276
- content: "**{label/region}** — Revenue: {metric/revenue}",
277
- placement: "above",
278
- };
279
- const config = buildGeoVisualizationConfig({
280
- options,
281
- supportedControls: { customTooltip },
282
- colorMapping: undefined,
283
- environment: DASHBOARDS_ENVIRONMENT,
284
- });
285
- expect(config.customTooltip).toEqual(customTooltip);
286
- });
287
- it("surfaces enableCustomTooltip=false from feature flags so the render gate can fire", () => {
288
- const config = buildGeoVisualizationConfig({
289
- options,
290
- supportedControls: {},
291
- colorMapping: undefined,
292
- environment: DASHBOARDS_ENVIRONMENT,
293
- featureFlags: { enableCustomTooltip: false },
294
- });
295
- expect(config.enableCustomTooltip).toBe(false);
296
- });
297
- });
298
- describe("buildAreaVisualizationConfig", () => {
299
- const options = {
300
- messages: {},
301
- };
302
- it("applies viewport navigation in dashboards, leaves embedded unset, and disables in AD", () => {
303
- const dashboardWidgetConfig = buildAreaVisualizationConfig({
304
- options: {
305
- ...options,
306
- config: {
307
- isInEditMode: false,
308
- },
309
- },
310
- supportedControls: {},
311
- colorMapping: undefined,
312
- environment: DASHBOARDS_ENVIRONMENT,
313
- });
314
- const embeddedConfig = buildAreaVisualizationConfig({
315
- options: {
316
- ...options,
317
- config: {},
318
- },
319
- supportedControls: {},
320
- colorMapping: undefined,
321
- environment: "",
322
- });
323
- const adConfig = buildAreaVisualizationConfig({
324
- options: {
325
- ...options,
326
- config: {
327
- isInEditMode: true,
328
- },
329
- },
330
- supportedControls: {},
331
- colorMapping: undefined,
332
- environment: ANALYTICAL_ENVIRONMENT,
333
- });
334
- expect(dashboardWidgetConfig.applyViewportNavigation).toBe(true);
335
- expect(embeddedConfig.applyViewportNavigation).toBeUndefined();
336
- expect(adConfig.applyViewportNavigation).toBe(false);
337
- });
338
- it("normalizes legacy legend positions for geo area charts", () => {
339
- const config = buildAreaVisualizationConfig({
340
- options,
341
- supportedControls: {
342
- legend: {
343
- position: "left",
344
- },
345
- },
346
- colorMapping: undefined,
347
- environment: "",
348
- });
349
- expect(config.legend?.position).toBe("top-left");
350
- });
351
- it("preserves sanitized basemap config even when the broad basemap FF is disabled", () => {
352
- const supportedControls = {
353
- basemap: "monochrome",
354
- };
355
- const disabledConfig = buildAreaVisualizationConfig({
356
- options,
357
- supportedControls,
358
- colorMapping: undefined,
359
- environment: ANALYTICAL_ENVIRONMENT,
360
- });
361
- const enabledConfig = buildAreaVisualizationConfig({
362
- options,
363
- supportedControls,
364
- colorMapping: undefined,
365
- environment: ANALYTICAL_ENVIRONMENT,
366
- featureFlags: { enableGeoBasemapConfig: true },
367
- });
368
- expect(disabledConfig.enableGeoBasemapConfig).toBe(false);
369
- expect(disabledConfig.basemap).toBe("monochrome");
370
- expect(enabledConfig.enableGeoBasemapConfig).toBe(true);
371
- expect(enabledConfig.basemap).toBe("monochrome");
372
- });
373
- it("maps legacy tileset controls to basemap", () => {
374
- const config = buildAreaVisualizationConfig({
375
- options: {
376
- ...options,
377
- config: {
378
- isInEditMode: false,
379
- },
380
- },
381
- supportedControls: {
382
- controls: {
383
- tileset: "satellite",
384
- },
385
- },
386
- colorMapping: undefined,
387
- environment: ANALYTICAL_ENVIRONMENT,
388
- });
389
- expect(config.basemap).toBe("satellite");
390
- });
391
- it("propagates customTooltip from supportedControls into the rendered config", () => {
392
- const customTooltip = {
393
- enabled: true,
394
- content: "# {label/state}\n{metric/population}",
395
- placement: "above",
396
- };
397
- const config = buildAreaVisualizationConfig({
398
- options,
399
- supportedControls: { customTooltip },
400
- colorMapping: undefined,
401
- environment: DASHBOARDS_ENVIRONMENT,
402
- });
403
- expect(config.customTooltip).toEqual(customTooltip);
404
- });
405
- it("surfaces enableCustomTooltip=false from feature flags so the render gate can fire", () => {
406
- const config = buildAreaVisualizationConfig({
407
- options,
408
- supportedControls: {},
409
- colorMapping: undefined,
410
- environment: DASHBOARDS_ENVIRONMENT,
411
- featureFlags: { enableCustomTooltip: false },
412
- });
413
- expect(config.enableCustomTooltip).toBe(false);
414
- });
415
- });