@gooddata/sdk-ui-ext 11.61.0-alpha.2 → 11.61.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +20 -20
- package/esm/internal/components/configurationControls/colors/ColorsSection.d.ts.map +1 -1
- package/esm/internal/components/configurationControls/colors/ColorsSection.js +4 -9
- package/esm/internal/components/configurationControls/colors/coloredItemsList/ColoredItemsList.d.ts.map +1 -1
- package/esm/internal/components/configurationControls/colors/coloredItemsList/ColoredItemsList.js +6 -4
- package/esm/internal/components/configurationControls/colors/coloredItemsList/LineStyleDialog.d.ts.map +1 -1
- package/esm/internal/components/configurationControls/colors/coloredItemsList/LineStyleDialog.js +16 -11
- package/esm/internal/components/dialogs/userManagementDialogs/AddWorkspaceToSubjects.d.ts +1 -0
- package/esm/internal/components/dialogs/userManagementDialogs/AddWorkspaceToSubjects.d.ts.map +1 -1
- package/esm/internal/components/dialogs/userManagementDialogs/AddWorkspaceToSubjects.js +2 -2
- package/esm/internal/components/dialogs/userManagementDialogs/UserEditDialog.d.ts +1 -0
- package/esm/internal/components/dialogs/userManagementDialogs/UserEditDialog.d.ts.map +1 -1
- package/esm/internal/components/dialogs/userManagementDialogs/UserEditDialog.js +2 -2
- package/esm/internal/components/dialogs/userManagementDialogs/UserGroupEditDialog.d.ts +1 -0
- package/esm/internal/components/dialogs/userManagementDialogs/UserGroupEditDialog.d.ts.map +1 -1
- package/esm/internal/components/dialogs/userManagementDialogs/UserGroupEditDialog.js +2 -2
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/AddWorkspace.d.ts +2 -1
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/AddWorkspace.d.ts.map +1 -1
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/AddWorkspace.js +4 -4
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/GranularPermissions.d.ts +2 -1
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/GranularPermissions.d.ts.map +1 -1
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/GranularPermissions.js +24 -24
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/granularPermissionUtils.d.ts +3 -3
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/granularPermissionUtils.d.ts.map +1 -1
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/granularPermissionUtils.js +21 -15
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/locales.d.ts +6 -0
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/locales.d.ts.map +1 -1
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/WorkspaceItem/locales.js +4 -0
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/useAddWorkspace.d.ts.map +1 -1
- package/esm/internal/components/dialogs/userManagementDialogs/Workspace/useAddWorkspace.js +10 -3
- package/esm/internal/translations/de-DE.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/de-DE.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/de-DE.localization-bundle.js +2 -1
- package/esm/internal/translations/en-AU.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/en-AU.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/en-AU.localization-bundle.js +2 -1
- package/esm/internal/translations/en-GB.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/en-GB.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/en-GB.localization-bundle.js +2 -1
- package/esm/internal/translations/en-US.localization-bundle.d.ts +16 -0
- package/esm/internal/translations/en-US.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/en-US.localization-bundle.js +17 -1
- package/esm/internal/translations/es-419.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/es-419.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/es-419.localization-bundle.js +2 -1
- package/esm/internal/translations/es-ES.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/es-ES.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/es-ES.localization-bundle.js +2 -1
- package/esm/internal/translations/fi-FI.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/fi-FI.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/fi-FI.localization-bundle.js +2 -1
- package/esm/internal/translations/fr-CA.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/fr-CA.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/fr-CA.localization-bundle.js +2 -1
- package/esm/internal/translations/fr-FR.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/fr-FR.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/fr-FR.localization-bundle.js +2 -1
- package/esm/internal/translations/id-ID.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/id-ID.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/id-ID.localization-bundle.js +2 -1
- package/esm/internal/translations/it-IT.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/it-IT.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/it-IT.localization-bundle.js +3 -2
- package/esm/internal/translations/ja-JP.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/ja-JP.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/ja-JP.localization-bundle.js +2 -1
- package/esm/internal/translations/ko-KR.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/ko-KR.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/ko-KR.localization-bundle.js +2 -1
- package/esm/internal/translations/nl-NL.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/nl-NL.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/nl-NL.localization-bundle.js +2 -1
- package/esm/internal/translations/pl-PL.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/pl-PL.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/pl-PL.localization-bundle.js +2 -1
- package/esm/internal/translations/pt-BR.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/pt-BR.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/pt-BR.localization-bundle.js +2 -1
- package/esm/internal/translations/pt-PT.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/pt-PT.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/pt-PT.localization-bundle.js +2 -1
- package/esm/internal/translations/ru-RU.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/ru-RU.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/ru-RU.localization-bundle.js +2 -1
- package/esm/internal/translations/sl-SI.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/sl-SI.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/sl-SI.localization-bundle.js +2 -1
- package/esm/internal/translations/th-TH.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/th-TH.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/th-TH.localization-bundle.js +2 -1
- package/esm/internal/translations/tr-TR.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/tr-TR.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/tr-TR.localization-bundle.js +2 -1
- package/esm/internal/translations/uk-UA.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/uk-UA.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/uk-UA.localization-bundle.js +2 -1
- package/esm/internal/translations/vi-VN.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/vi-VN.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/vi-VN.localization-bundle.js +2 -1
- package/esm/internal/translations/zh-HK.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/zh-HK.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/zh-HK.localization-bundle.js +2 -1
- package/esm/internal/translations/zh-Hans.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/zh-Hans.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/zh-Hans.localization-bundle.js +2 -1
- package/esm/internal/translations/zh-Hant.localization-bundle.d.ts +2 -1
- package/esm/internal/translations/zh-Hant.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/zh-Hant.localization-bundle.js +2 -1
- package/esm/internal/utils/colors.d.ts +1 -0
- package/esm/internal/utils/colors.d.ts.map +1 -1
- package/esm/internal/utils/colors.js +14 -7
- package/esm/sdk-ui-ext.d.ts +4 -1
- package/esm/share/ObjectShareDialog.js +10 -7
- package/esm/share/messages.d.ts +21 -2
- package/esm/share/messages.d.ts.map +1 -1
- package/esm/share/messages.js +13 -2
- package/esm/share/objectShareController.helpers.d.ts +2 -0
- package/esm/share/objectShareController.helpers.d.ts.map +1 -1
- package/esm/share/objectShareController.helpers.js +2 -0
- package/esm/share/objectShareController.types.d.ts +26 -13
- package/esm/share/objectShareController.types.d.ts.map +1 -1
- package/esm/share/useAccessList.d.ts +11 -0
- package/esm/share/useAccessList.d.ts.map +1 -1
- package/esm/share/useAccessList.js +18 -1
- package/esm/share/useObjectShareController.d.ts.map +1 -1
- package/esm/share/useObjectShareController.js +52 -21
- package/esm/share/useObjectShareDialog.d.ts +3 -1
- package/esm/share/useObjectShareDialog.d.ts.map +1 -1
- package/esm/share/useObjectShareDialog.js +44 -8
- package/package.json +21 -21
|
@@ -6,6 +6,19 @@ import { objectShareMessages } from "./messages.js";
|
|
|
6
6
|
import { EMPTY_IDS, NO_LABELS, changesEffectiveLevel, granularGranteeFor, levelsAbove, levelsBelow, mergeDisabledLevels, sortGrantees, toGranularGrantee, } from "./objectShareController.helpers.js";
|
|
7
7
|
import { useAccessList } from "./useAccessList.js";
|
|
8
8
|
import { useLabelScope } from "./useLabelScope.js";
|
|
9
|
+
function resolveRoleAccess({ loaded, isWorkspaceManager, canManageVisualizations, kind, callerLevel, }) {
|
|
10
|
+
if (!loaded) {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
if (isWorkspaceManager) {
|
|
14
|
+
return "workspaceManager";
|
|
15
|
+
}
|
|
16
|
+
// The backend's EDIT is required too: inherited visualizations stay view-only for a holder.
|
|
17
|
+
if (canManageVisualizations && kind === "insight" && callerLevel === "EDIT") {
|
|
18
|
+
return "visualizationManager";
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
9
22
|
/**
|
|
10
23
|
* Manages the share-dialog state and backend I/O for ONE dialog session: the hook
|
|
11
24
|
* is mounted while the dialog is open, for a single target that must not change
|
|
@@ -35,7 +48,15 @@ export function useObjectShareController(target, options) {
|
|
|
35
48
|
const [subview, setSubview] = useState("main");
|
|
36
49
|
const [pendingGrantees, setPendingGrantees] = useState([]);
|
|
37
50
|
const [pendingGeneralAccess, setPendingGeneralAccess] = useState(undefined);
|
|
38
|
-
const { hasList, grantees, isWorkspaceManager, selfIdentityResolved, generalAccess, workspaceLevel, workspaceInheritedLevel, workspaceLevelSaving, summary, status, loadError, commit, loadOptions, applyGranteeAdd, applyGranteeLevel, applyGranteeLock, applyGranteeRemove, settleGranteeEdit, failGranteeEdit, applyRuleEdit, settleRuleEdit, failRuleEdit, draft: draftValue, } = useAccessList(target, { draft, initialDraft, initialDraftGeneralAccess });
|
|
51
|
+
const { hasList, grantees, isWorkspaceManager, canManageVisualizations, callerLevel, selfIdentityResolved, generalAccess, workspaceLevel, workspaceInheritedLevel, workspaceLevelSaving, summary, status, loadError, commit, loadOptions, applyGranteeAdd, applyGranteeLevel, applyGranteeLock, applyGranteeRemove, settleGranteeEdit, failGranteeEdit, applyRuleEdit, settleRuleEdit, failRuleEdit, draft: draftValue, } = useAccessList(target, { draft, initialDraft, initialDraftGeneralAccess });
|
|
52
|
+
const roleAccess = resolveRoleAccess({
|
|
53
|
+
loaded: !draft && status === "success",
|
|
54
|
+
isWorkspaceManager,
|
|
55
|
+
canManageVisualizations,
|
|
56
|
+
kind: target?.kind,
|
|
57
|
+
callerLevel,
|
|
58
|
+
});
|
|
59
|
+
const roleLockedGranteeId = roleAccess === "visualizationManager" ? grantees.find((g) => g.isSelf)?.id : undefined;
|
|
39
60
|
// Grantee ids the label-scope probe resolves against — a removing row is excluded
|
|
40
61
|
// so its scope is dropped, not re-seeded.
|
|
41
62
|
const committedGranteeIds = useMemo(() => {
|
|
@@ -218,7 +239,11 @@ export function useObjectShareController(target, options) {
|
|
|
218
239
|
// Also refused before the label scope resolves: the re-grade below would run
|
|
219
240
|
// over the assumed-all fallback and mint grants the grantee never held. The
|
|
220
241
|
// UI gates on the same fact (isMutable); the controller stays authoritative.
|
|
221
|
-
if (!grantee ||
|
|
242
|
+
if (!grantee ||
|
|
243
|
+
grantee.pending ||
|
|
244
|
+
!labelsResolved ||
|
|
245
|
+
granteeId === roleLockedGranteeId ||
|
|
246
|
+
!changesEffectiveLevel(grantee, level)) {
|
|
222
247
|
return;
|
|
223
248
|
}
|
|
224
249
|
applyGranteeLevel(granteeId, level);
|
|
@@ -278,6 +303,7 @@ export function useObjectShareController(target, options) {
|
|
|
278
303
|
applyGranteeLevel,
|
|
279
304
|
settleGranteeEdit,
|
|
280
305
|
failGranteeEdit,
|
|
306
|
+
roleLockedGranteeId,
|
|
281
307
|
]);
|
|
282
308
|
const removeGrantee = useCallback(async (granteeId) => {
|
|
283
309
|
const grantee = grantees.find((g) => g.id === granteeId);
|
|
@@ -288,7 +314,11 @@ export function useObjectShareController(target, options) {
|
|
|
288
314
|
// this keeps the controller — not the UI — authoritative. Same for an
|
|
289
315
|
// unresolved label scope: the revoke below would run over the assumed-all
|
|
290
316
|
// fallback and revoke (then compensate with) grants that never existed.
|
|
291
|
-
if (!grantee ||
|
|
317
|
+
if (!grantee ||
|
|
318
|
+
grantee.pending ||
|
|
319
|
+
!labelsResolved ||
|
|
320
|
+
grantee.directLevel === undefined ||
|
|
321
|
+
granteeId === roleLockedGranteeId) {
|
|
292
322
|
return;
|
|
293
323
|
}
|
|
294
324
|
// Mark the row removed but keep it visible (muted) until the write lands.
|
|
@@ -375,6 +405,7 @@ export function useObjectShareController(target, options) {
|
|
|
375
405
|
settleGranteeEdit,
|
|
376
406
|
failGranteeEdit,
|
|
377
407
|
setSelectedLabelIdsByGrantee,
|
|
408
|
+
roleLockedGranteeId,
|
|
378
409
|
]);
|
|
379
410
|
const changeGranteeLabels = useCallback(async (granteeId, requested) => {
|
|
380
411
|
const grantee = grantees.find((g) => g.id === granteeId);
|
|
@@ -607,7 +638,7 @@ export function useObjectShareController(target, options) {
|
|
|
607
638
|
// Sorted for display only; the overlay stays in write-through order, so
|
|
608
639
|
// add/rollback logic is unaffected. Memoized apart from the state assembly so
|
|
609
640
|
// the array identity changes only when the rows do, not on every state change.
|
|
610
|
-
const sortedGrantees = useMemo(() => sortGrantees(grantees), [grantees]);
|
|
641
|
+
const sortedGrantees = useMemo(() => sortGrantees(grantees).map((g) => g.id === roleLockedGranteeId ? { ...g, level: "EDIT", effectivePermission: undefined } : g), [grantees, roleLockedGranteeId]);
|
|
611
642
|
const state = useMemo(() => {
|
|
612
643
|
// Row policy is classified here, not in the dialog, so a consumer
|
|
613
644
|
// injecting this controller into its own UI gets the same classification.
|
|
@@ -615,22 +646,18 @@ export function useObjectShareController(target, options) {
|
|
|
615
646
|
// it special is that the access is THEIRS. A manager is exempt, their access
|
|
616
647
|
// comes from the role, so there is no ceiling to cap and no lockout to warn of.
|
|
617
648
|
const ownRow = grantees.find((g) => g.isSelf);
|
|
618
|
-
const selfRow = isWorkspaceManager ? undefined : ownRow;
|
|
649
|
+
const selfRow = isWorkspaceManager || roleLockedGranteeId ? undefined : ownRow;
|
|
619
650
|
const selfManagedGranteeId = selfRow?.id;
|
|
620
|
-
// The caller cannot grant above what they hold, and the server refuses such a
|
|
621
|
-
//
|
|
622
|
-
//
|
|
623
|
-
//
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
651
|
+
// The caller cannot grant above what they hold, and the server refuses such a write.
|
|
652
|
+
// The backend's own answer covers groups, parent workspaces and workspace permissions.
|
|
653
|
+
// Without it, only the caller's own row proves a level, and only for a known
|
|
654
|
+
// non-manager: a limit that guesses wrong would block a grant the backend allows.
|
|
655
|
+
const grantableDisabledLevels = callerLevel === undefined
|
|
656
|
+
? isWorkspaceManager === false && selfRow
|
|
657
|
+
? levelsAbove(selfRow.level)
|
|
658
|
+
: undefined
|
|
659
|
+
: levelsAbove(callerLevel);
|
|
629
660
|
const granteeControlsLocked = !selfIdentityResolved && !isWorkspaceManager && grantees.some((g) => g.kind === "user");
|
|
630
|
-
// Policy in `IObjectShareControllerState.showAdminAccessNote`: role-based access is
|
|
631
|
-
// explained by a note, not a grantee row, so it does not depend on the caller having
|
|
632
|
-
// (or lacking) a row of their own.
|
|
633
|
-
const showAdminAccessNote = !draft && status === "success" && isWorkspaceManager === true;
|
|
634
661
|
return {
|
|
635
662
|
subview,
|
|
636
663
|
status,
|
|
@@ -640,11 +667,13 @@ export function useObjectShareController(target, options) {
|
|
|
640
667
|
selfManagedGranteeId,
|
|
641
668
|
// Policy, not just classification: the caller's own row can't be raised
|
|
642
669
|
// above itself, an inherited workspace level can't be undercut.
|
|
643
|
-
selfManagedDisabledLevels: selfRow ? levelsAbove(selfRow.level) : undefined,
|
|
670
|
+
selfManagedDisabledLevels: selfRow ? levelsAbove(callerLevel ?? selfRow.level) : undefined,
|
|
644
671
|
workspaceDisabledLevels: mergeDisabledLevels(workspaceInheritedLevel ? levelsBelow(workspaceInheritedLevel) : undefined, grantableDisabledLevels),
|
|
645
672
|
grantableDisabledLevels,
|
|
673
|
+
callerLevel,
|
|
646
674
|
granteeControlsLocked,
|
|
647
|
-
|
|
675
|
+
roleAccess,
|
|
676
|
+
roleLockedGranteeId,
|
|
648
677
|
...effectiveWorkspace,
|
|
649
678
|
workspaceInheritedLevel: workspaceInheritedLevel,
|
|
650
679
|
workspaceLevelLocked: generalAccess !== "WORKSPACE" || workspaceInheritedLevel === "EDIT",
|
|
@@ -664,7 +693,9 @@ export function useObjectShareController(target, options) {
|
|
|
664
693
|
summary,
|
|
665
694
|
selfIdentityResolved,
|
|
666
695
|
isWorkspaceManager,
|
|
667
|
-
|
|
696
|
+
roleAccess,
|
|
697
|
+
roleLockedGranteeId,
|
|
698
|
+
callerLevel,
|
|
668
699
|
grantees,
|
|
669
700
|
sortedGrantees,
|
|
670
701
|
effectiveWorkspace,
|
|
@@ -57,7 +57,9 @@ export interface IObjectShareDialogViewModel {
|
|
|
57
57
|
*/
|
|
58
58
|
isRowRemoveDisabled: (grantee: IObjectShareGrantee) => boolean;
|
|
59
59
|
/** Tooltip explaining why Remove access is disabled on this row. */
|
|
60
|
-
rowRemoveDisabledTooltip: string;
|
|
60
|
+
rowRemoveDisabledTooltip: (grantee: IObjectShareGrantee) => string;
|
|
61
|
+
/** Whether this row's direct grant is above the caller's level, so nothing on it may change. */
|
|
62
|
+
isRowAboveCaller: (grantee: IObjectShareGrantee) => boolean;
|
|
61
63
|
/** Whether this row's controls must stay disabled (see `granteeControlsLocked`). */
|
|
62
64
|
isRowControlsLocked: (grantee: IObjectShareGrantee) => boolean;
|
|
63
65
|
/** Close the whole dialog, handing the draft over and discarding any staged self-restriction. */
|
|
@@ -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;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"useObjectShareDialog.d.ts","sourceRoot":"","sources":["../../src/share/useObjectShareDialog.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
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, levelsBelow, removalChangesEffectiveLevel, } from "./objectShareController.helpers.js";
|
|
5
|
+
import { ALL_LEVELS, changesEffectiveLevel, levelsAbove, levelsBelow, removalChangesEffectiveLevel, } from "./objectShareController.helpers.js";
|
|
6
6
|
import { useObjectShareController } from "./useObjectShareController.js";
|
|
7
7
|
/**
|
|
8
8
|
* Level picks an inherited grant already covers, which the controller refuses as
|
|
@@ -54,9 +54,10 @@ export function useObjectShareDialog({ target, onClose, onSummaryChange, draft,
|
|
|
54
54
|
onClose();
|
|
55
55
|
}, [currentDraft, onDraftChange, onClose]);
|
|
56
56
|
// A row belongs to the signed-in user's own sole grant when the controller has
|
|
57
|
-
// classified it as self-managed —
|
|
57
|
+
// classified it as self-managed — lowering it routes through the confirm, raising it
|
|
58
|
+
// (allowed when a group grants more) commits directly.
|
|
58
59
|
const onRowPermissionChange = useCallback((grantee, level) => {
|
|
59
|
-
if (state.selfManagedGranteeId === grantee.id) {
|
|
60
|
+
if (state.selfManagedGranteeId === grantee.id && levelsBelow(grantee.level).includes(level)) {
|
|
60
61
|
// Stage the confirm only for a pick that would really move the level the
|
|
61
62
|
// user effectively holds. Comparing against the displayed level instead
|
|
62
63
|
// opened "Restrict your access?" for a pick under an inherited floor, which
|
|
@@ -95,7 +96,34 @@ export function useObjectShareDialog({ target, onClose, onSummaryChange, draft,
|
|
|
95
96
|
}, [pendingSelfChange, actions]);
|
|
96
97
|
const onSelfRestrictCancel = useCallback(() => setPendingSelfChange(undefined), []);
|
|
97
98
|
const inheritedCoveredTooltip = intl.formatMessage(objectShareMessages.granteeLevelInheritedCovered);
|
|
99
|
+
// The server refuses changing or removing a grant above the caller's own level.
|
|
100
|
+
const isRowAboveCaller = useCallback((grantee) => state.callerLevel !== undefined &&
|
|
101
|
+
grantee.directLevel !== undefined &&
|
|
102
|
+
levelsAbove(state.callerLevel).includes(grantee.directLevel), [state.callerLevel]);
|
|
103
|
+
const coveredByWorkspacePermissionTooltip = intl.formatMessage(objectShareMessages.granteeCoveredByWorkspacePermission);
|
|
104
|
+
const aboveCallerUserTooltip = intl.formatMessage(objectShareMessages.granteeAboveCallerUser);
|
|
105
|
+
const aboveCallerGroupTooltip = intl.formatMessage(objectShareMessages.granteeAboveCallerGroup);
|
|
106
|
+
const rowLock = useCallback((grantee) => {
|
|
107
|
+
if (isRowAboveCaller(grantee)) {
|
|
108
|
+
const tooltip = grantee.kind === "group" ? aboveCallerGroupTooltip : aboveCallerUserTooltip;
|
|
109
|
+
return { levels: [...ALL_LEVELS], tooltip };
|
|
110
|
+
}
|
|
111
|
+
if (state.roleLockedGranteeId === grantee.id) {
|
|
112
|
+
return { levels: levelsBelow("EDIT"), tooltip: coveredByWorkspacePermissionTooltip };
|
|
113
|
+
}
|
|
114
|
+
return undefined;
|
|
115
|
+
}, [
|
|
116
|
+
isRowAboveCaller,
|
|
117
|
+
state.roleLockedGranteeId,
|
|
118
|
+
aboveCallerUserTooltip,
|
|
119
|
+
aboveCallerGroupTooltip,
|
|
120
|
+
coveredByWorkspacePermissionTooltip,
|
|
121
|
+
]);
|
|
98
122
|
const rowDisabledLevels = useCallback((grantee) => {
|
|
123
|
+
const lock = rowLock(grantee);
|
|
124
|
+
if (lock) {
|
|
125
|
+
return lock.levels;
|
|
126
|
+
}
|
|
99
127
|
const self = state.selfManagedGranteeId === grantee.id ? (state.selfManagedDisabledLevels ?? []) : [];
|
|
100
128
|
// Self caps levels ABOVE the row and coverage disables those BELOW, so those
|
|
101
129
|
// two are disjoint; the grant limit can overlap either.
|
|
@@ -107,8 +135,12 @@ export function useObjectShareDialog({ target, onClose, onSummaryChange, draft,
|
|
|
107
135
|
]),
|
|
108
136
|
];
|
|
109
137
|
return merged.length > 0 ? merged : undefined;
|
|
110
|
-
}, [state.selfManagedGranteeId, state.selfManagedDisabledLevels, state.grantableDisabledLevels]);
|
|
138
|
+
}, [rowLock, state.selfManagedGranteeId, state.selfManagedDisabledLevels, state.grantableDisabledLevels]);
|
|
111
139
|
const rowDisabledLevelTooltips = useCallback((grantee) => {
|
|
140
|
+
const lock = rowLock(grantee);
|
|
141
|
+
if (lock) {
|
|
142
|
+
return Object.fromEntries(lock.levels.map((level) => [level, lock.tooltip]));
|
|
143
|
+
}
|
|
112
144
|
const covered = inheritedCoveredLevels(grantee);
|
|
113
145
|
if (covered.length === 0) {
|
|
114
146
|
return undefined;
|
|
@@ -118,8 +150,11 @@ export function useObjectShareDialog({ target, onClose, onSummaryChange, draft,
|
|
|
118
150
|
map[level] = inheritedCoveredTooltip;
|
|
119
151
|
}
|
|
120
152
|
return map;
|
|
121
|
-
}, [inheritedCoveredTooltip]);
|
|
122
|
-
const isRowRemoveDisabled = useCallback((grantee) => grantee.directLevel === undefined, []);
|
|
153
|
+
}, [rowLock, inheritedCoveredTooltip]);
|
|
154
|
+
const isRowRemoveDisabled = useCallback((grantee) => grantee.directLevel === undefined || rowLock(grantee) !== undefined, [rowLock]);
|
|
155
|
+
const removeInheritedTooltip = intl.formatMessage(objectShareMessages.granteeRemoveInherited);
|
|
156
|
+
const rowRemoveDisabledTooltip = useCallback((grantee) => rowLock(grantee)?.tooltip ?? removeInheritedTooltip, [rowLock, removeInheritedTooltip]);
|
|
157
|
+
const grantLimitTooltip = intl.formatMessage(objectShareMessages.toastEscalationRefused);
|
|
123
158
|
// Only USER rows can be the caller's own, so a group row stays usable while the
|
|
124
159
|
// profile is unresolved.
|
|
125
160
|
const isRowControlsLocked = useCallback((grantee) => state.granteeControlsLocked && grantee.kind === "user", [state.granteeControlsLocked]);
|
|
@@ -136,12 +171,13 @@ export function useObjectShareDialog({ target, onClose, onSummaryChange, draft,
|
|
|
136
171
|
isLoading,
|
|
137
172
|
workspaceDisabledLevels: state.workspaceDisabledLevels,
|
|
138
173
|
grantableDisabledLevels: state.grantableDisabledLevels,
|
|
139
|
-
grantLimitTooltip
|
|
174
|
+
grantLimitTooltip,
|
|
140
175
|
rowDisabledLevels,
|
|
141
176
|
rowDisabledLevelTooltips,
|
|
142
177
|
isRowRemoveDisabled,
|
|
143
178
|
isRowControlsLocked,
|
|
144
|
-
rowRemoveDisabledTooltip
|
|
179
|
+
rowRemoveDisabledTooltip,
|
|
180
|
+
isRowAboveCaller,
|
|
145
181
|
onClose: closeDialog,
|
|
146
182
|
onRowPermissionChange,
|
|
147
183
|
onRowRemove,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-ext",
|
|
3
|
-
"version": "11.61.0-alpha.
|
|
3
|
+
"version": "11.61.0-alpha.4",
|
|
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.61.0-alpha.
|
|
67
|
-
"@gooddata/sdk-
|
|
68
|
-
"@gooddata/sdk-
|
|
69
|
-
"@gooddata/sdk-
|
|
70
|
-
"@gooddata/sdk-
|
|
71
|
-
"@gooddata/sdk-ui-
|
|
72
|
-
"@gooddata/sdk-ui-
|
|
73
|
-
"@gooddata/sdk-ui-geo": "11.61.0-alpha.
|
|
74
|
-
"@gooddata/sdk-ui-
|
|
75
|
-
"@gooddata/sdk-ui-
|
|
76
|
-
"@gooddata/sdk-ui-
|
|
77
|
-
"@gooddata/sdk-ui-
|
|
78
|
-
"@gooddata/sdk-ui-
|
|
79
|
-
"@gooddata/util": "11.61.0-alpha.
|
|
66
|
+
"@gooddata/sdk-backend-base": "11.61.0-alpha.4",
|
|
67
|
+
"@gooddata/sdk-backend-spi": "11.61.0-alpha.4",
|
|
68
|
+
"@gooddata/sdk-embedding": "11.61.0-alpha.4",
|
|
69
|
+
"@gooddata/sdk-model": "11.61.0-alpha.4",
|
|
70
|
+
"@gooddata/sdk-ui": "11.61.0-alpha.4",
|
|
71
|
+
"@gooddata/sdk-ui-charts": "11.61.0-alpha.4",
|
|
72
|
+
"@gooddata/sdk-ui-filters": "11.61.0-alpha.4",
|
|
73
|
+
"@gooddata/sdk-ui-geo": "11.61.0-alpha.4",
|
|
74
|
+
"@gooddata/sdk-ui-kit": "11.61.0-alpha.4",
|
|
75
|
+
"@gooddata/sdk-ui-pivot": "11.61.0-alpha.4",
|
|
76
|
+
"@gooddata/sdk-ui-semantic-search": "11.61.0-alpha.4",
|
|
77
|
+
"@gooddata/sdk-ui-theme-provider": "11.61.0-alpha.4",
|
|
78
|
+
"@gooddata/sdk-ui-vis-commons": "11.61.0-alpha.4",
|
|
79
|
+
"@gooddata/util": "11.61.0-alpha.4"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@microsoft/api-documenter": "7.30.16",
|
|
@@ -120,12 +120,12 @@
|
|
|
120
120
|
"typescript": "7.0.2",
|
|
121
121
|
"vitest": "4.1.11",
|
|
122
122
|
"vitest-dom": "0.1.1",
|
|
123
|
-
"@gooddata/
|
|
124
|
-
"@gooddata/
|
|
125
|
-
"@gooddata/i18n-toolkit": "11.61.0-alpha.
|
|
126
|
-
"@gooddata/
|
|
127
|
-
"@gooddata/
|
|
128
|
-
"@gooddata/
|
|
123
|
+
"@gooddata/eslint-config": "11.61.0-alpha.4",
|
|
124
|
+
"@gooddata/oxlint-config": "11.61.0-alpha.4",
|
|
125
|
+
"@gooddata/i18n-toolkit": "11.61.0-alpha.4",
|
|
126
|
+
"@gooddata/stylelint-config": "11.61.0-alpha.4",
|
|
127
|
+
"@gooddata/sdk-backend-mockingbird": "11.61.0-alpha.4",
|
|
128
|
+
"@gooddata/reference-workspace": "11.61.0-alpha.4"
|
|
129
129
|
},
|
|
130
130
|
"peerDependencies": {
|
|
131
131
|
"react": "^18.0.0 || ^19.0.0",
|