@gooddata/sdk-ui-ext 11.52.0-alpha.6 → 11.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/dataLoaders/InsightDataLoader.d.ts +6 -0
- package/esm/dataLoaders/InsightDataLoader.d.ts.map +1 -1
- package/esm/dataLoaders/InsightDataLoader.js +4 -1
- package/esm/dataLoaders/index.d.ts +13 -0
- package/esm/dataLoaders/index.d.ts.map +1 -1
- package/esm/dataLoaders/index.js +14 -0
- package/esm/index.d.ts +1 -1
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +1 -1
- package/esm/insightView/InsightRenderer.d.ts +2 -5
- package/esm/insightView/InsightRenderer.d.ts.map +1 -1
- package/esm/insightView/InsightRenderer.js +1 -2
- package/esm/internal/components/pluggableVisualizations/mekko/PluggableMekko.d.ts +6 -1
- package/esm/internal/components/pluggableVisualizations/mekko/PluggableMekko.d.ts.map +1 -1
- package/esm/internal/components/pluggableVisualizations/mekko/PluggableMekko.js +25 -4
- package/esm/internal/components/pluggableVisualizations/pivotTable/PluggablePivotTable.d.ts.map +1 -1
- package/esm/internal/components/pluggableVisualizations/pivotTable/PluggablePivotTable.js +0 -1
- package/esm/internal/translations/de-DE.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/de-DE.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/de-DE.localization-bundle.js +2 -0
- package/esm/internal/translations/en-AU.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/en-AU.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/en-AU.localization-bundle.js +2 -0
- package/esm/internal/translations/en-GB.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/en-GB.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/en-GB.localization-bundle.js +2 -0
- package/esm/internal/translations/en-US.localization-bundle.d.ts +4 -0
- package/esm/internal/translations/en-US.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/en-US.localization-bundle.js +4 -0
- package/esm/internal/translations/es-419.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/es-419.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/es-419.localization-bundle.js +2 -0
- package/esm/internal/translations/es-ES.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/es-ES.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/es-ES.localization-bundle.js +2 -0
- package/esm/internal/translations/fi-FI.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/fi-FI.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/fi-FI.localization-bundle.js +2 -0
- package/esm/internal/translations/fr-CA.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/fr-CA.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/fr-CA.localization-bundle.js +2 -0
- package/esm/internal/translations/fr-FR.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/fr-FR.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/fr-FR.localization-bundle.js +2 -0
- package/esm/internal/translations/id-ID.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/id-ID.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/id-ID.localization-bundle.js +2 -0
- package/esm/internal/translations/it-IT.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/it-IT.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/it-IT.localization-bundle.js +2 -0
- package/esm/internal/translations/ja-JP.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/ja-JP.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/ja-JP.localization-bundle.js +2 -0
- package/esm/internal/translations/ko-KR.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/ko-KR.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/ko-KR.localization-bundle.js +2 -0
- package/esm/internal/translations/nl-NL.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/nl-NL.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/nl-NL.localization-bundle.js +2 -0
- package/esm/internal/translations/pl-PL.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/pl-PL.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/pl-PL.localization-bundle.js +2 -0
- package/esm/internal/translations/pt-BR.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/pt-BR.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/pt-BR.localization-bundle.js +2 -0
- package/esm/internal/translations/pt-PT.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/pt-PT.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/pt-PT.localization-bundle.js +2 -0
- package/esm/internal/translations/ru-RU.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/ru-RU.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/ru-RU.localization-bundle.js +2 -0
- package/esm/internal/translations/sl-SI.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/sl-SI.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/sl-SI.localization-bundle.js +2 -0
- package/esm/internal/translations/th-TH.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/th-TH.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/th-TH.localization-bundle.js +2 -0
- package/esm/internal/translations/tr-TR.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/tr-TR.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/tr-TR.localization-bundle.js +2 -0
- package/esm/internal/translations/uk-UA.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/uk-UA.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/uk-UA.localization-bundle.js +2 -0
- package/esm/internal/translations/vi-VN.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/vi-VN.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/vi-VN.localization-bundle.js +2 -0
- package/esm/internal/translations/zh-HK.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/zh-HK.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/zh-HK.localization-bundle.js +2 -0
- package/esm/internal/translations/zh-Hans.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/zh-Hans.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/zh-Hans.localization-bundle.js +2 -0
- package/esm/internal/translations/zh-Hant.localization-bundle.d.ts +2 -0
- package/esm/internal/translations/zh-Hant.localization-bundle.d.ts.map +1 -1
- package/esm/internal/translations/zh-Hant.localization-bundle.js +2 -0
- package/esm/notificationsPanel/Notification/Notification.d.ts.map +1 -1
- package/esm/notificationsPanel/Notification/Notification.js +6 -3
- package/esm/notificationsPanel/NotificationFiltersDetail/NotificationFiltersDetail.d.ts +3 -3
- package/esm/notificationsPanel/NotificationFiltersDetail/NotificationFiltersDetail.d.ts.map +1 -1
- package/esm/notificationsPanel/NotificationFiltersDetail/NotificationFiltersDetail.js +4 -4
- package/esm/notificationsPanel/NotificationFiltersDetail/NotificationFiltersDetailDialog.d.ts +9 -3
- package/esm/notificationsPanel/NotificationFiltersDetail/NotificationFiltersDetailDialog.d.ts.map +1 -1
- package/esm/notificationsPanel/NotificationFiltersDetail/NotificationFiltersDetailDialog.js +4 -4
- package/esm/sdk-ui-ext.d.ts +13 -0
- package/esm/share/ObjectShareDialog.js +22 -6
- package/esm/share/messages.d.ts +7 -0
- package/esm/share/messages.d.ts.map +1 -1
- package/esm/share/messages.js +5 -0
- package/esm/share/objectShareController.helpers.d.ts +117 -17
- package/esm/share/objectShareController.helpers.d.ts.map +1 -1
- package/esm/share/objectShareController.helpers.js +181 -44
- package/esm/share/objectShareController.types.d.ts +34 -10
- package/esm/share/objectShareController.types.d.ts.map +1 -1
- package/esm/share/useAccessList.d.ts +6 -0
- package/esm/share/useAccessList.d.ts.map +1 -1
- package/esm/share/useAccessList.js +26 -6
- package/esm/share/useLabelScope.d.ts +46 -1
- package/esm/share/useLabelScope.d.ts.map +1 -1
- package/esm/share/useLabelScope.js +98 -6
- package/esm/share/useObjectShareController.d.ts.map +1 -1
- package/esm/share/useObjectShareController.js +213 -45
- package/esm/share/useObjectShareDialog.d.ts +7 -0
- package/esm/share/useObjectShareDialog.d.ts.map +1 -1
- package/esm/share/useObjectShareDialog.js +22 -2
- package/package.json +21 -21
|
@@ -115,25 +115,117 @@ export function levelsAbove(level) {
|
|
|
115
115
|
export function levelsBelow(level) {
|
|
116
116
|
return LEVELS_STRONGEST_FIRST.filter((l) => LEVEL_RANK[l] < LEVEL_RANK[level]);
|
|
117
117
|
}
|
|
118
|
+
/** The stronger of two levels; undefined only when both are. */
|
|
119
|
+
export function maxLevel(a, b) {
|
|
120
|
+
if (a === undefined) {
|
|
121
|
+
return b;
|
|
122
|
+
}
|
|
123
|
+
if (b === undefined) {
|
|
124
|
+
return a;
|
|
125
|
+
}
|
|
126
|
+
return LEVEL_RANK[a] >= LEVEL_RANK[b] ? a : b;
|
|
127
|
+
}
|
|
118
128
|
/**
|
|
119
|
-
* The
|
|
120
|
-
* grant already covers it. Set
|
|
121
|
-
* a
|
|
122
|
-
*
|
|
129
|
+
* The inherited permission to surface as a warning, or undefined when the direct
|
|
130
|
+
* grant already covers it. Set when the grantee *inherits* a level (via a group or
|
|
131
|
+
* a parent workspace) that the direct grant does not reach — including the
|
|
132
|
+
* inherited-only case (`direct` undefined), where the whole displayed level comes
|
|
133
|
+
* from inheritance.
|
|
123
134
|
*/
|
|
124
135
|
export function effectivePermissionAbove(direct, inheritedLevel) {
|
|
125
|
-
|
|
136
|
+
if (!inheritedLevel) {
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
|
139
|
+
return direct === undefined || LEVEL_RANK[inheritedLevel] > LEVEL_RANK[direct]
|
|
140
|
+
? inheritedLevel
|
|
141
|
+
: undefined;
|
|
126
142
|
}
|
|
127
|
-
/**
|
|
143
|
+
/**
|
|
144
|
+
* The permission-derived fields of a grantee row, given the raw direct and
|
|
145
|
+
* inherited permission sets.
|
|
146
|
+
*
|
|
147
|
+
* The displayed `level` is the EFFECTIVE one — the stronger of the direct grant and
|
|
148
|
+
* anything inherited (from a group, or from a parent workspace in a hierarchy) —
|
|
149
|
+
* so a grantee who only inherits EDIT reads as "Can edit & share" rather than
|
|
150
|
+
* falling back to VIEW. `directLevel` keeps what THIS workspace grants (undefined
|
|
151
|
+
* when the access is inherited-only): it is what writes re-grade and what decides
|
|
152
|
+
* whether there is anything here to remove.
|
|
153
|
+
*/
|
|
128
154
|
function granteeAccess(permissions, inheritedPermissions) {
|
|
129
|
-
const
|
|
155
|
+
const direct = strongestLevel(permissions);
|
|
130
156
|
const inheritedLevel = strongestLevel(inheritedPermissions);
|
|
157
|
+
// A listed grantee with NEITHER set is a revoked-but-still-listed entry. VIEW is the
|
|
158
|
+
// historical placeholder for its level, and it counts as the DIRECT one: leaving
|
|
159
|
+
// `directLevel` undefined would classify the row as inherited-only, disabling Remove
|
|
160
|
+
// and claiming inherited access that does not exist.
|
|
161
|
+
const directLevel = direct ?? (inheritedLevel === undefined ? "VIEW" : undefined);
|
|
131
162
|
return {
|
|
132
|
-
level,
|
|
133
|
-
|
|
163
|
+
level: maxLevel(directLevel, inheritedLevel) ?? "VIEW",
|
|
164
|
+
directLevel,
|
|
165
|
+
effectivePermission: effectivePermissionAbove(direct, inheritedLevel),
|
|
134
166
|
inheritedLevel,
|
|
135
167
|
};
|
|
136
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* Whether picking `level` for this grantee would change the level they EFFECTIVELY hold.
|
|
171
|
+
*
|
|
172
|
+
* The permission menu shows the effective level, so a pick is only meaningful if it moves
|
|
173
|
+
* that: under an inherited EDIT, picking SHARE or VIEW cannot lower anything, it would just
|
|
174
|
+
* rewrite the grant made here where nobody can see it. Conversely a direct EDIT under an
|
|
175
|
+
* inherited SHARE CAN be lowered to VIEW, because the effective level then drops to SHARE.
|
|
176
|
+
*
|
|
177
|
+
* The single source of this rule. Everything that reacts to a pick must agree: the
|
|
178
|
+
* controller refuses a pick that changes nothing, so any confirm staged for one would ask
|
|
179
|
+
* the user to approve a change that then silently does not happen.
|
|
180
|
+
*
|
|
181
|
+
* @internal
|
|
182
|
+
*/
|
|
183
|
+
export function changesEffectiveLevel(grantee, level) {
|
|
184
|
+
return maxLevel(level, grantee.inheritedLevel) !== grantee.level;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Whether revoking this grantee's direct grant would change the level they EFFECTIVELY
|
|
188
|
+
* hold. False when inheritance alone already covers the displayed level: the revoke still
|
|
189
|
+
* removes the local grant, but restricts nothing the grantee can do — so no
|
|
190
|
+
* "Restrict your access?" confirm may be staged for it ({@link changesEffectiveLevel}'s
|
|
191
|
+
* rule, applied to removal).
|
|
192
|
+
*
|
|
193
|
+
* @internal
|
|
194
|
+
*/
|
|
195
|
+
export function removalChangesEffectiveLevel(grantee) {
|
|
196
|
+
return grantee.inheritedLevel !== grantee.level;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* The row fields to apply when THIS workspace's direct grant moves to `direct`:
|
|
200
|
+
* the displayed level recomposes against whatever is inherited, so a re-grade below
|
|
201
|
+
* an inherited level cannot make the row understate the grantee's real access.
|
|
202
|
+
*
|
|
203
|
+
* @internal
|
|
204
|
+
*/
|
|
205
|
+
export function withDirectLevel(grantee, direct) {
|
|
206
|
+
return {
|
|
207
|
+
...grantee,
|
|
208
|
+
level: maxLevel(direct, grantee.inheritedLevel) ?? direct,
|
|
209
|
+
directLevel: direct,
|
|
210
|
+
effectivePermission: effectivePermissionAbove(direct, grantee.inheritedLevel),
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* The row a grantee falls back to once their direct grant is revoked but inherited
|
|
215
|
+
* access remains — the row survives the removal as inherited-only rather than
|
|
216
|
+
* disappearing and reappearing on the next load.
|
|
217
|
+
*
|
|
218
|
+
* @internal
|
|
219
|
+
*/
|
|
220
|
+
export function withoutDirectGrant(grantee, inheritedLevel) {
|
|
221
|
+
return {
|
|
222
|
+
...grantee,
|
|
223
|
+
level: inheritedLevel,
|
|
224
|
+
directLevel: undefined,
|
|
225
|
+
effectivePermission: inheritedLevel,
|
|
226
|
+
pending: undefined,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
137
229
|
export function granteesFromAccessList(list) {
|
|
138
230
|
if (!list) {
|
|
139
231
|
return [];
|
|
@@ -185,11 +277,7 @@ export function mergeGrantees(base, edits, selfId, selfIdentity) {
|
|
|
185
277
|
return settled.grantee;
|
|
186
278
|
}
|
|
187
279
|
if (g && settled?.kind === "level") {
|
|
188
|
-
return
|
|
189
|
-
...g,
|
|
190
|
-
level: settled.level,
|
|
191
|
-
effectivePermission: effectivePermissionAbove(settled.level, g.inheritedLevel),
|
|
192
|
-
};
|
|
280
|
+
return withDirectLevel(g, settled.level);
|
|
193
281
|
}
|
|
194
282
|
return g;
|
|
195
283
|
};
|
|
@@ -203,19 +291,29 @@ export function mergeGrantees(base, edits, selfId, selfIdentity) {
|
|
|
203
291
|
}
|
|
204
292
|
if (edit.kind === "removed") {
|
|
205
293
|
// Visible (muted, at its last committed state) only while the revoke is
|
|
206
|
-
// in flight
|
|
207
|
-
// keep the base row hidden.
|
|
294
|
+
// in flight.
|
|
208
295
|
const committed = edit.pending ? committedRow(g, edit.settled) : undefined;
|
|
209
|
-
|
|
296
|
+
if (committed) {
|
|
297
|
+
return { ...committed, pending: "removing" };
|
|
298
|
+
}
|
|
299
|
+
// A settled removal revokes only what THIS workspace granted. When the
|
|
300
|
+
// grantee still inherits access (a group, a parent workspace), the row
|
|
301
|
+
// survives as inherited-only — dropping it would claim the removal took
|
|
302
|
+
// away access it cannot reach. With nothing inherited the row is gone and
|
|
303
|
+
// the entry persists to keep the base row hidden.
|
|
304
|
+
return g?.inheritedLevel ? withoutDirectGrant(g, g.inheritedLevel) : undefined;
|
|
305
|
+
}
|
|
306
|
+
if (edit.kind === "locked") {
|
|
307
|
+
// Access unchanged: render whatever the row had COMMITTED and add the saving
|
|
308
|
+
// marker. Rendering the fetched row instead would undo the committed state
|
|
309
|
+
// for the duration of the write — a removal survivor would reappear with the
|
|
310
|
+
// direct grant it just lost.
|
|
311
|
+
const committed = edit.settled ? renderEntry(g, { ...edit.settled, pending: false }) : g;
|
|
312
|
+
return committed ? { ...committed, pending: edit.pending ? "saving" : undefined } : undefined;
|
|
210
313
|
}
|
|
211
314
|
if (edit.kind === "level") {
|
|
212
315
|
return g
|
|
213
|
-
? {
|
|
214
|
-
...g,
|
|
215
|
-
level: edit.level,
|
|
216
|
-
effectivePermission: effectivePermissionAbove(edit.level, g.inheritedLevel),
|
|
217
|
-
pending: edit.pending ? "saving" : undefined,
|
|
218
|
-
}
|
|
316
|
+
? { ...withDirectLevel(g, edit.level), pending: edit.pending ? "saving" : undefined }
|
|
219
317
|
: undefined;
|
|
220
318
|
}
|
|
221
319
|
return { ...edit.grantee, pending: edit.pending ? "saving" : undefined };
|
|
@@ -275,21 +373,51 @@ export function buildLabelMutations(principal, desiredLabelIds, currentLabelIds,
|
|
|
275
373
|
if (wanted === had) {
|
|
276
374
|
continue;
|
|
277
375
|
}
|
|
278
|
-
writes.push({
|
|
376
|
+
writes.push({
|
|
377
|
+
ref: label.ref,
|
|
378
|
+
grantee: granularGranteeFor(principal, wanted ? (principal.level ?? "VIEW") : "none"),
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
return writes;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* Pure: the per-label writes that re-grade `principal`'s EXISTING label scope to
|
|
385
|
+
* `principal.level`. Unlike {@link buildLabelMutations} this is not a set diff —
|
|
386
|
+
* the scope is unchanged and every in-scope label is rewritten — so it is what a
|
|
387
|
+
* permission-level change on the object needs to keep its labels in step. `labels` is
|
|
388
|
+
* the permissionable set, so every write targets a label that can take a grant.
|
|
389
|
+
*
|
|
390
|
+
* The primary label is deliberately EXCLUDED. Its access is implicit — {@link
|
|
391
|
+
* buildLabelMutations} never grants or revokes it — so a grant written here would be
|
|
392
|
+
* one nothing can take away: a later removal diffs the primary as unchanged and leaves
|
|
393
|
+
* the grantee holding the primary label after their object access is gone.
|
|
394
|
+
*/
|
|
395
|
+
export function buildLabelRegrades(principals, scopeLabelIds, labels) {
|
|
396
|
+
const writes = [];
|
|
397
|
+
for (const label of labels) {
|
|
398
|
+
if (label.isPrimary || !scopeLabelIds.has(label.id)) {
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
writes.push({
|
|
402
|
+
id: label.id,
|
|
403
|
+
ref: label.ref,
|
|
404
|
+
grantees: principals.map((p) => granularGranteeFor(p, p.level ?? "VIEW")),
|
|
405
|
+
});
|
|
279
406
|
}
|
|
280
407
|
return writes;
|
|
281
408
|
}
|
|
282
409
|
/**
|
|
283
|
-
* Multi-principal variant of {@link buildLabelMutations}
|
|
284
|
-
* writes so each label is one write carrying every
|
|
285
|
-
* Keys on `label.id`, not the raw `ObjRef` — a Map
|
|
286
|
-
* object identity and fail to merge
|
|
410
|
+
* Multi-principal variant of {@link buildLabelMutations}, each principal moving its
|
|
411
|
+
* own scope: groups the per-label writes so each label is one write carrying every
|
|
412
|
+
* principal that changes on it. Keys on `label.id`, not the raw `ObjRef` — a Map
|
|
413
|
+
* keyed on ObjRef would key on object identity and fail to merge
|
|
414
|
+
* equal-but-distinct refs.
|
|
287
415
|
*/
|
|
288
|
-
export function
|
|
416
|
+
export function buildLabelMutationsForScopes(changes, labels) {
|
|
289
417
|
const byLabel = new Map();
|
|
290
418
|
for (const label of labels) {
|
|
291
|
-
for (const
|
|
292
|
-
const writes = buildLabelMutations(principal, desiredLabelIds, currentLabelIds, [label]);
|
|
419
|
+
for (const change of changes) {
|
|
420
|
+
const writes = buildLabelMutations(change.principal, change.desiredLabelIds, change.currentLabelIds, [label]);
|
|
293
421
|
if (writes.length === 0) {
|
|
294
422
|
continue;
|
|
295
423
|
}
|
|
@@ -305,20 +433,29 @@ export const NO_LABELS = [];
|
|
|
305
433
|
/** Shared empty id-set for "no labels in scope" diffs. */
|
|
306
434
|
export const EMPTY_IDS = new Set();
|
|
307
435
|
/**
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
*
|
|
436
|
+
* Where `granteeId`'s access to this object comes from, or `undefined` when they hold it
|
|
437
|
+
* at all. The two flags are INDEPENDENT: a grantee can hold a grant made here *and*
|
|
438
|
+
* inherit one from a group or a parent workspace, and both facts matter — `direct` says
|
|
439
|
+
* there is something here to revoke, `inherited` says access survives revoking it.
|
|
440
|
+
* Collapsing them to a single winner is what made a dual-granted label read as
|
|
441
|
+
* inaccessible once its local grant was revoked.
|
|
442
|
+
*
|
|
443
|
+
* Inspects the raw grants rather than `granteesFromAccessList`, which normalizes every
|
|
444
|
+
* listed user/group to a VIEW level even when it carries no permissions — so a
|
|
445
|
+
* revoked-but-still-listed entry would otherwise read as granted, mis-scoping a per-label
|
|
446
|
+
* checkbox to a label the grantee can't actually access.
|
|
313
447
|
*/
|
|
314
|
-
export function
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
448
|
+
export function granteeGrantIn(list, id) {
|
|
449
|
+
const sourceOf = (permissions, inherited) => permissions.length > 0 || inherited.length > 0
|
|
450
|
+
? { direct: permissions.length > 0, inherited: inherited.length > 0 }
|
|
451
|
+
: undefined;
|
|
452
|
+
for (const g of list.grants) {
|
|
453
|
+
if (isGranularUserAccess(g) && id === granteeId("user", g.user.ref)) {
|
|
454
|
+
return sourceOf(g.permissions, g.inheritedPermissions);
|
|
318
455
|
}
|
|
319
|
-
if (isGranularUserGroupAccess(g)) {
|
|
320
|
-
return
|
|
456
|
+
if (isGranularUserGroupAccess(g) && id === granteeId("group", g.userGroup.ref)) {
|
|
457
|
+
return sourceOf(g.permissions, g.inheritedPermissions);
|
|
321
458
|
}
|
|
322
|
-
|
|
323
|
-
|
|
459
|
+
}
|
|
460
|
+
return undefined;
|
|
324
461
|
}
|
|
@@ -46,18 +46,31 @@ export interface IObjectShareGrantee extends IGranteeIdentityFacts {
|
|
|
46
46
|
* profile, so it holds for rows of any origin (fetched or optimistic).
|
|
47
47
|
*/
|
|
48
48
|
isSelf?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* EFFECTIVE permission level shown on the row — the stronger of {@link directLevel}
|
|
51
|
+
* and {@link inheritedLevel}, so a grantee who only inherits a level is not
|
|
52
|
+
* understated as VIEW.
|
|
53
|
+
*/
|
|
49
54
|
level: ObjectSharePermissionLevel;
|
|
50
55
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
56
|
+
* Permission level granted by THIS workspace, or undefined when the grantee's
|
|
57
|
+
* access is inherited-only (a group, or a parent workspace in a hierarchy).
|
|
58
|
+
* This — not {@link level} — is what a re-grade writes and what decides whether
|
|
59
|
+
* there is a grant here to remove: inherited access cannot be revoked from here.
|
|
60
|
+
*/
|
|
61
|
+
directLevel?: ObjectSharePermissionLevel;
|
|
62
|
+
/**
|
|
63
|
+
* Inherited permission to surface as a warning: set when inheritance carries the
|
|
64
|
+
* grantee above their direct grant (including inherited-only, where the whole
|
|
65
|
+
* displayed level is inherited). Undefined when the direct grant already covers
|
|
66
|
+
* the effective permission. Drives the row's warning badge.
|
|
55
67
|
*/
|
|
56
68
|
effectivePermission?: ObjectSharePermissionLevel;
|
|
57
69
|
/**
|
|
58
|
-
* Strongest permission the grantee inherits (
|
|
59
|
-
* the current direct
|
|
60
|
-
* can be
|
|
70
|
+
* Strongest permission the grantee inherits (via a group, or a parent workspace),
|
|
71
|
+
* regardless of the current direct level. Retained from the fetch so the
|
|
72
|
+
* displayed level and badge can be recomposed locally when the direct level
|
|
73
|
+
* changes (no refetch).
|
|
61
74
|
*/
|
|
62
75
|
inheritedLevel?: ObjectSharePermissionLevel;
|
|
63
76
|
/**
|
|
@@ -164,11 +177,22 @@ export interface IObjectShareControllerState {
|
|
|
164
177
|
*/
|
|
165
178
|
labelsInitializing: boolean;
|
|
166
179
|
/**
|
|
167
|
-
* Per-grantee label scope: grantee id → the label ids that grantee can access
|
|
168
|
-
* The primary label is always included.
|
|
169
|
-
*
|
|
180
|
+
* Per-grantee label scope: grantee id → the label ids that grantee can access,
|
|
181
|
+
* whether granted here or inherited. The primary label is always included.
|
|
182
|
+
*
|
|
183
|
+
* A MISSING entry means the scope is not resolved for that grantee — only then may a
|
|
184
|
+
* consumer fall back to all labels, and only once {@link labelsResolved}. An entry
|
|
185
|
+
* that is an EMPTY array is a resolved answer: no non-primary label is in scope.
|
|
170
186
|
*/
|
|
171
187
|
selectedLabelIdsByGrantee: Record<string, string[]>;
|
|
188
|
+
/**
|
|
189
|
+
* The subset of {@link selectedLabelIdsByGrantee} a grantee only INHERITS (from a
|
|
190
|
+
* group, or a parent workspace) with no grant on the label in this workspace.
|
|
191
|
+
* Those labels are in scope but cannot be re-scoped here: there is nothing local
|
|
192
|
+
* to revoke, so consumers render them locked. Same rule as a grantee row whose
|
|
193
|
+
* object access is inherited-only, which cannot be removed either.
|
|
194
|
+
*/
|
|
195
|
+
inheritedLabelIdsByGrantee: Record<string, string[]>;
|
|
172
196
|
/** Pending confirm — when set, the confirm dialog is visible. */
|
|
173
197
|
pendingGeneralAccess?: GeneralAccessValue;
|
|
174
198
|
/** Grantees staged in the add-grantee dialog before confirmation. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"objectShareController.types.d.ts","sourceRoot":"","sources":["../../src/share/objectShareController.types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC5E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAEzG,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE1E;;;;;GAKG;AACH,MAAM,MAAM,0BAA0B,GAAG,wBAAwB,CAAC;AAElE;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IAClC,uDAAuD;IACvD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,MAAM,WAAW,aAAc,SAAQ,qBAAqB;IACxD,EAAE,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAoB,SAAQ,qBAAqB;IAC9D,kFAAkF;IAClF,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,0BAA0B,CAAC;IAClC;;;;;OAKG;IACH,mBAAmB,CAAC,EAAE,0BAA0B,CAAC;IACjD
|
|
1
|
+
{"version":3,"file":"objectShareController.types.d.ts","sourceRoot":"","sources":["../../src/share/objectShareController.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -65,6 +65,12 @@ export interface IAccessList {
|
|
|
65
65
|
* plain level entry would drop the row from the merged view.
|
|
66
66
|
*/
|
|
67
67
|
applyGranteeLevel: (id: string, level: ObjectSharePermissionLevel) => void;
|
|
68
|
+
/**
|
|
69
|
+
* Lock a row for a write that leaves its access unchanged (a label-scope edit):
|
|
70
|
+
* adds the pending marker only. Use this rather than re-applying the displayed
|
|
71
|
+
* level, which would persist the EFFECTIVE level as the row's direct grant.
|
|
72
|
+
*/
|
|
73
|
+
applyGranteeLock: (id: string) => void;
|
|
68
74
|
/** Overlay a pending removal; the row renders muted until the write settles. */
|
|
69
75
|
applyGranteeRemove: (id: string) => void;
|
|
70
76
|
/** Commit the pending edit for `id` after a successful write. */
|
|
@@ -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,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,
|
|
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"}
|
|
@@ -5,7 +5,7 @@ import { convertError, useBackendStrict, useCancelablePromise, useWorkspaceStric
|
|
|
5
5
|
import { useToastMessage } from "@gooddata/sdk-ui-kit";
|
|
6
6
|
import { composeEffectiveWorkspaceAccess, deriveGeneralAccess, deriveInheritedWorkspaceLevel, deriveWorkspacePermissionLevel, } from "./accessSummary.js";
|
|
7
7
|
import { objectShareMessages } from "./messages.js";
|
|
8
|
-
import { assigneeIdentityFacts, assigneeMatchesQuery,
|
|
8
|
+
import { assigneeIdentityFacts, assigneeMatchesQuery, granteeId, granteesFromAccessList, mergeGrantees, userDisplayPair, userIdentityFacts, withDirectLevel, } from "./objectShareController.helpers.js";
|
|
9
9
|
/**
|
|
10
10
|
* Owns the backend access list for ONE dialog session: the hook is mounted while
|
|
11
11
|
* the dialog is open, for a single target that must not change while mounted
|
|
@@ -167,16 +167,25 @@ export function useAccessList(target) {
|
|
|
167
167
|
const settled = current ? { ...current, settled: undefined } : undefined;
|
|
168
168
|
if (current?.kind === "added") {
|
|
169
169
|
// Overlay-born row: stay an `added` entry, or the merge would drop it.
|
|
170
|
-
const grantee =
|
|
171
|
-
...current.grantee,
|
|
172
|
-
level,
|
|
173
|
-
effectivePermission: effectivePermissionAbove(level, current.grantee.inheritedLevel),
|
|
174
|
-
};
|
|
170
|
+
const grantee = withDirectLevel(current.grantee, level);
|
|
175
171
|
return { ...prev, [id]: { kind: "added", grantee, pending: true, settled } };
|
|
176
172
|
}
|
|
177
173
|
return { ...prev, [id]: { kind: "level", level, pending: true, settled } };
|
|
178
174
|
});
|
|
179
175
|
}, []);
|
|
176
|
+
// Lock a row for a write that does NOT change its access (a label-scope edit). The
|
|
177
|
+
// lock WRAPS whatever the row committed rather than modifying it: reusing the
|
|
178
|
+
// existing entry and flipping `pending` would re-arm it, and `pending` means
|
|
179
|
+
// something different per kind — a settled removal would read as a revoke in flight
|
|
180
|
+
// and render the row as removing at its pre-removal level. Both settling and failing
|
|
181
|
+
// unwrap back to the entry underneath, because a label write changes neither.
|
|
182
|
+
const applyGranteeLock = useCallback((id) => {
|
|
183
|
+
setGranteeEdits((prev) => {
|
|
184
|
+
const current = prev[id];
|
|
185
|
+
const settled = current ? { ...current, settled: undefined } : undefined;
|
|
186
|
+
return { ...prev, [id]: { kind: "locked", pending: true, settled } };
|
|
187
|
+
});
|
|
188
|
+
}, []);
|
|
180
189
|
const applyGranteeRemove = useCallback((id) => {
|
|
181
190
|
setGranteeEdits((prev) => {
|
|
182
191
|
const current = prev[id];
|
|
@@ -190,6 +199,16 @@ export function useAccessList(target) {
|
|
|
190
199
|
if (!current) {
|
|
191
200
|
return prev;
|
|
192
201
|
}
|
|
202
|
+
// A lock is a wrapper over the row's committed state, so settling it unwraps —
|
|
203
|
+
// same as failing. Keeping a settled `locked` entry would discard the entry it
|
|
204
|
+
// wrapped and drop the row back to its fetched state.
|
|
205
|
+
if (current.kind === "locked") {
|
|
206
|
+
if (!current.settled) {
|
|
207
|
+
const { [id]: _omit, ...rest } = prev;
|
|
208
|
+
return rest;
|
|
209
|
+
}
|
|
210
|
+
return { ...prev, [id]: current.settled };
|
|
211
|
+
}
|
|
193
212
|
// A settled removal always keeps its entry: for a base row (including a
|
|
194
213
|
// removed re-added one) it is what keeps the row hidden; for an
|
|
195
214
|
// overlay-born row it renders nothing and is harmless.
|
|
@@ -238,6 +257,7 @@ export function useAccessList(target) {
|
|
|
238
257
|
loadOptions,
|
|
239
258
|
applyGranteeAdd,
|
|
240
259
|
applyGranteeLevel,
|
|
260
|
+
applyGranteeLock,
|
|
241
261
|
applyGranteeRemove,
|
|
242
262
|
settleGranteeEdit,
|
|
243
263
|
failGranteeEdit,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { IObjectPermissionsObject } from "@gooddata/sdk-backend-spi";
|
|
2
|
-
import { type LabelScopePrincipal } from "./objectShareController.helpers.js";
|
|
2
|
+
import { type ILabelScopeChange, type LabelScopePrincipal } from "./objectShareController.helpers.js";
|
|
3
3
|
import type { IObjectShareLabel } from "./types.js";
|
|
4
4
|
/**
|
|
5
5
|
* Per-label access scope for the share dialog: which labels each grantee can
|
|
@@ -38,6 +38,30 @@ export interface ILabelScope {
|
|
|
38
38
|
/** Per-grantee label scope: grantee id → label ids in scope (primary always in). */
|
|
39
39
|
selectedLabelIdsByGrantee: Record<string, string[]>;
|
|
40
40
|
setSelectedLabelIdsByGrantee: React.Dispatch<React.SetStateAction<Record<string, string[]>>>;
|
|
41
|
+
/**
|
|
42
|
+
* In-scope labels whose access the grantee INHERITS, per grantee id — including ones
|
|
43
|
+
* they also hold a local grant on. Callers render these locked: unchecking cannot take
|
|
44
|
+
* the access away. Derived straight from the probe, never optimistic, because only the
|
|
45
|
+
* backend can say where a grant lives.
|
|
46
|
+
*/
|
|
47
|
+
inheritedLabelIdsByGrantee: Record<string, string[]>;
|
|
48
|
+
/**
|
|
49
|
+
* Labels THIS workspace grants the grantee, per grantee id — the only ones a write may
|
|
50
|
+
* target, and the complement of "inherited only". An optimistic overlay, not a
|
|
51
|
+
* derivation: the per-label probe runs once per session, so after the dialog revokes or
|
|
52
|
+
* grants a label the probe's answer is stale and acting on it re-creates access that was
|
|
53
|
+
* just removed. Every label write reports its outcome through
|
|
54
|
+
* {@link recordDirectLabelWrites}.
|
|
55
|
+
*/
|
|
56
|
+
directLabelIdsByGrantee: Record<string, string[]>;
|
|
57
|
+
/**
|
|
58
|
+
* Record the outcome of the dialog's OWN label writes so the direct set stays true:
|
|
59
|
+
* `granted` ids gain a local grant, `revoked` ids lose theirs. Pass only the writes
|
|
60
|
+
* that actually landed.
|
|
61
|
+
*/
|
|
62
|
+
recordDirectLabelWrites: (granteeId: string, granted: readonly string[], revoked: readonly string[]) => void;
|
|
63
|
+
/** Forget a grantee's label bookkeeping once their row is gone for good. */
|
|
64
|
+
forgetGranteeLabels: (granteeId: string) => void;
|
|
41
65
|
/**
|
|
42
66
|
* The single per-label write path. Diffs `desired` vs `current` over the
|
|
43
67
|
* permissionable labels and issues one `manageObjectPermissions` per changed
|
|
@@ -49,6 +73,27 @@ export interface ILabelScope {
|
|
|
49
73
|
ok: boolean;
|
|
50
74
|
failedLabelIds: string[];
|
|
51
75
|
}>;
|
|
76
|
+
/**
|
|
77
|
+
* Per-principal variant of {@link reconcileLabelScope}: each principal moves its
|
|
78
|
+
* OWN scope, for grantees added in one step that each picked a different label
|
|
79
|
+
* scope. Still one write per label carrying every principal that changes on it,
|
|
80
|
+
* so a shared label costs one call regardless of how the scopes differ.
|
|
81
|
+
*/
|
|
82
|
+
reconcileLabelScopes: (changes: ILabelScopeChange[]) => Promise<{
|
|
83
|
+
ok: boolean;
|
|
84
|
+
failedLabelIds: string[];
|
|
85
|
+
}>;
|
|
86
|
+
/**
|
|
87
|
+
* Re-grades an UNCHANGED label scope to each principal's `level` — what a
|
|
88
|
+
* permission-level change on the object needs so its labels don't keep the level
|
|
89
|
+
* they were granted at. Not a diff: every in-scope label is rewritten (a diff
|
|
90
|
+
* over an unchanged set produces no writes). Same independent settling and
|
|
91
|
+
* `failedLabelIds` reporting as {@link reconcileLabelScope}.
|
|
92
|
+
*/
|
|
93
|
+
regradeLabelScope: (principals: LabelScopePrincipal[], scopeLabelIds: ReadonlySet<string>) => Promise<{
|
|
94
|
+
ok: boolean;
|
|
95
|
+
failedLabelIds: string[];
|
|
96
|
+
}>;
|
|
52
97
|
}
|
|
53
98
|
/**
|
|
54
99
|
* Owns label-scope resolution + writes for {@link useObjectShareController}.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLabelScope.d.ts","sourceRoot":"","sources":["../../src/share/useLabelScope.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAK1E,OAAO,EACH,KAAK,mBAAmB,
|
|
1
|
+
{"version":3,"file":"useLabelScope.d.ts","sourceRoot":"","sources":["../../src/share/useLabelScope.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AAK1E,OAAO,EACH,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EAI3B,MAAM,oCAAoC,CAAC;AAC5C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA6EpD;;;;;;GAMG;AACH,MAAM,WAAW,WAAW;IACxB;;;;OAIG;IACH,eAAe,EAAE,iBAAiB,EAAE,CAAC;IACrC;;;;;;;;OAQG;IACH,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;;;;OAQG;IACH,kBAAkB,EAAE,OAAO,CAAC;IAC5B,sFAAoF;IACpF,yBAAyB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACpD,4BAA4B,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7F;;;;;OAKG;IACH,0BAA0B,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACrD;;;;;;;OAOG;IACH,uBAAuB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAClD;;;;OAIG;IACH,uBAAuB,EAAE,CACrB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,SAAS,MAAM,EAAE,EAC1B,OAAO,EAAE,SAAS,MAAM,EAAE,KACzB,IAAI,CAAC;IACV,4EAA4E;IAC5E,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD;;;;;;OAMG;IACH,mBAAmB,EAAE,CACjB,UAAU,EAAE,mBAAmB,EAAE,EACjC,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,EACpC,eAAe,EAAE,WAAW,CAAC,MAAM,CAAC,KACnC,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACxD;;;;;OAKG;IACH,oBAAoB,EAAE,CAClB,OAAO,EAAE,iBAAiB,EAAE,KAC3B,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;IACxD;;;;;;OAMG;IACH,iBAAiB,EAAE,CACf,UAAU,EAAE,mBAAmB,EAAE,EACjC,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,KACjC,OAAO,CAAC;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC,CAAC;CAC3D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,aAAa,CACzB,MAAM,EAAE,wBAAwB,GAAG,SAAS,EAC5C,MAAM,EAAE,iBAAiB,EAAE,EAC3B,OAAO,EAAE,OAAO,EAChB,mBAAmB,EAAE,MAAM,EAAE,EAC7B,WAAW,EAAE,OAAO,EACpB,aAAa,EAAE,OAAO,GACvB,WAAW,CA6Ob"}
|