@gooddata/sdk-ui-ext 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.
Files changed (44) hide show
  1. package/esm/internal/components/dialogs/userManagementDialogs/AddWorkspaceToSubjects.d.ts +1 -0
  2. package/esm/internal/components/dialogs/userManagementDialogs/AddWorkspaceToSubjects.d.ts.map +1 -1
  3. package/esm/internal/components/dialogs/userManagementDialogs/AddWorkspaceToSubjects.js +2 -2
  4. package/esm/internal/components/dialogs/userManagementDialogs/UserEditDialog.d.ts +1 -0
  5. package/esm/internal/components/dialogs/userManagementDialogs/UserEditDialog.d.ts.map +1 -1
  6. package/esm/internal/components/dialogs/userManagementDialogs/UserEditDialog.js +2 -2
  7. package/esm/internal/components/dialogs/userManagementDialogs/UserGroupEditDialog.d.ts +1 -0
  8. package/esm/internal/components/dialogs/userManagementDialogs/UserGroupEditDialog.d.ts.map +1 -1
  9. package/esm/internal/components/dialogs/userManagementDialogs/UserGroupEditDialog.js +2 -2
  10. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/AddSingleWorkspaceSelect.d.ts.map +1 -1
  11. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/AddSingleWorkspaceSelect.js +1 -3
  12. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/AddWorkspace.d.ts +2 -1
  13. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/AddWorkspace.d.ts.map +1 -1
  14. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/AddWorkspace.js +2 -2
  15. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/GranularPermissions.d.ts +2 -1
  16. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/GranularPermissions.d.ts.map +1 -1
  17. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/GranularPermissions.js +5 -2
  18. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/granularPermissionUtils.d.ts.map +1 -1
  19. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/granularPermissionUtils.js +9 -1
  20. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/locales.d.ts +6 -0
  21. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/locales.d.ts.map +1 -1
  22. package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/locales.js +4 -0
  23. package/esm/internal/translations/en-US.localization-bundle.d.ts +8 -0
  24. package/esm/internal/translations/en-US.localization-bundle.d.ts.map +1 -1
  25. package/esm/internal/translations/en-US.localization-bundle.js +8 -0
  26. package/esm/sdk-ui-ext.d.ts +3 -0
  27. package/esm/share/ObjectShareDialog.js +6 -4
  28. package/esm/share/messages.d.ts +11 -0
  29. package/esm/share/messages.d.ts.map +1 -1
  30. package/esm/share/messages.js +7 -0
  31. package/esm/share/objectShareController.types.d.ts +10 -8
  32. package/esm/share/objectShareController.types.d.ts.map +1 -1
  33. package/esm/share/useAccessList.d.ts +19 -1
  34. package/esm/share/useAccessList.d.ts.map +1 -1
  35. package/esm/share/useAccessList.js +20 -3
  36. package/esm/share/useObjectShareController.d.ts.map +1 -1
  37. package/esm/share/useObjectShareController.js +15 -10
  38. package/esm/share/useObjectShareDialog.d.ts +6 -2
  39. package/esm/share/useObjectShareDialog.d.ts.map +1 -1
  40. package/esm/share/useObjectShareDialog.js +33 -6
  41. package/package.json +21 -21
  42. package/esm/internal/components/pluggableVisualizations/geoChartNext/geoConfigBuilder.test.d.ts +0 -2
  43. package/esm/internal/components/pluggableVisualizations/geoChartNext/geoConfigBuilder.test.d.ts.map +0 -1
  44. package/esm/internal/components/pluggableVisualizations/geoChartNext/geoConfigBuilder.test.js +0 -415
@@ -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.5",
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-base": "11.53.0-alpha.5",
67
- "@gooddata/sdk-backend-spi": "11.53.0-alpha.5",
68
- "@gooddata/sdk-embedding": "11.53.0-alpha.5",
69
- "@gooddata/sdk-model": "11.53.0-alpha.5",
70
- "@gooddata/sdk-ui": "11.53.0-alpha.5",
71
- "@gooddata/sdk-ui-charts": "11.53.0-alpha.5",
72
- "@gooddata/sdk-ui-filters": "11.53.0-alpha.5",
73
- "@gooddata/sdk-ui-geo": "11.53.0-alpha.5",
74
- "@gooddata/sdk-ui-kit": "11.53.0-alpha.5",
75
- "@gooddata/sdk-ui-pivot": "11.53.0-alpha.5",
76
- "@gooddata/sdk-ui-semantic-search": "11.53.0-alpha.5",
77
- "@gooddata/sdk-ui-theme-provider": "11.53.0-alpha.5",
78
- "@gooddata/util": "11.53.0-alpha.5",
79
- "@gooddata/sdk-ui-vis-commons": "11.53.0-alpha.5"
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.5",
128
- "@gooddata/i18n-toolkit": "11.53.0-alpha.5",
129
- "@gooddata/reference-workspace": "11.53.0-alpha.5",
130
- "@gooddata/oxlint-config": "11.53.0-alpha.5",
131
- "@gooddata/sdk-backend-mockingbird": "11.53.0-alpha.5",
132
- "@gooddata/stylelint-config": "11.53.0-alpha.5"
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":""}