@datalayer/core 1.1.66 → 1.2.12
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/README.md +43 -20
- package/lib/api/constants.d.ts +1 -1
- package/lib/api/constants.js +1 -1
- package/lib/api/contents/attachments.js +3 -7
- package/lib/api/contents/datasets.d.ts +48 -0
- package/lib/api/contents/datasets.js +44 -7
- package/lib/api/contents/runtimeMounts.js +1 -1
- package/lib/api/contents/sandboxUid.d.ts +13 -45
- package/lib/api/contents/sandboxUid.js +14 -65
- package/lib/api/evals/client.d.ts +402 -0
- package/lib/api/evals/client.js +359 -0
- package/lib/api/evals/index.d.ts +10 -0
- package/lib/api/evals/index.js +18 -0
- package/lib/api/evals/request.d.ts +43 -0
- package/lib/api/evals/request.js +67 -0
- package/lib/api/evals/status.d.ts +27 -0
- package/lib/api/evals/status.js +122 -0
- package/lib/api/evals/types.d.ts +1335 -0
- package/lib/api/evals/types.js +5 -0
- package/lib/api/iam/authentication.js +6 -4
- package/lib/api/iam/connectedAgents.d.ts +29 -0
- package/lib/api/iam/connectedAgents.js +35 -0
- package/lib/api/iam/healthz.js +2 -2
- package/lib/api/iam/identityProviders.d.ts +76 -0
- package/lib/api/iam/identityProviders.js +187 -0
- package/lib/api/iam/index.d.ts +1 -0
- package/lib/api/iam/index.js +1 -0
- package/lib/api/iam/mcpPolicy.d.ts +102 -1
- package/lib/api/iam/mcpPolicy.js +38 -2
- package/lib/api/iam/oauth2.js +18 -12
- package/lib/api/iam/profile.d.ts +17 -1
- package/lib/api/iam/profile.js +27 -0
- package/lib/api/iam/scimTokens.d.ts +79 -0
- package/lib/api/iam/scimTokens.js +141 -0
- package/lib/api/iam/secrets.js +10 -23
- package/lib/api/iam/trials.d.ts +38 -0
- package/lib/api/iam/trials.js +66 -0
- package/lib/api/index.d.ts +4 -0
- package/lib/api/index.js +4 -0
- package/lib/api/mcp/observability.d.ts +34 -11
- package/lib/api/mcp/observability.js +97 -59
- package/lib/api/orchestration/client.d.ts +53 -0
- package/lib/api/orchestration/client.js +105 -0
- package/lib/api/orchestration/events.d.ts +88 -0
- package/lib/api/orchestration/events.js +245 -0
- package/lib/api/orchestration/generated.d.ts +693 -0
- package/lib/api/orchestration/generated.js +687 -0
- package/lib/api/orchestration/index.d.ts +30 -0
- package/lib/api/orchestration/index.js +34 -0
- package/lib/api/orchestration/lifecycle.d.ts +39 -0
- package/lib/api/orchestration/lifecycle.js +57 -0
- package/lib/api/orchestration/measures.d.ts +55 -0
- package/lib/api/orchestration/measures.js +99 -0
- package/lib/api/otel/dashboards.d.ts +56 -0
- package/lib/api/otel/dashboards.js +50 -0
- package/lib/api/otel/index.d.ts +1 -0
- package/lib/api/otel/index.js +1 -0
- package/lib/api/otel/metrics.d.ts +16 -0
- package/lib/api/otel/metrics.js +15 -0
- package/lib/api/scheduler/client.d.ts +32 -0
- package/lib/api/scheduler/client.js +42 -0
- package/lib/api/scheduler/index.d.ts +8 -0
- package/lib/api/scheduler/index.js +16 -0
- package/lib/api/scheduler/request.d.ts +28 -0
- package/lib/api/scheduler/request.js +50 -0
- package/lib/api/scheduler/types.d.ts +88 -0
- package/lib/api/scheduler/types.js +5 -0
- package/lib/api/spacer/comments.d.ts +97 -0
- package/lib/api/spacer/comments.js +45 -0
- package/lib/api/spacer/index.d.ts +9 -0
- package/lib/api/spacer/index.js +17 -0
- package/lib/api/spacer/notebooks.d.ts +33 -0
- package/lib/api/spacer/notebooks.js +39 -0
- package/lib/api/spacer/request.d.ts +25 -0
- package/lib/api/spacer/request.js +46 -0
- package/lib/api/spacer/spaces.d.ts +68 -0
- package/lib/api/spacer/spaces.js +45 -0
- package/lib/api/utils/validation.d.ts +4 -4
- package/lib/api/utils/validation.js +10 -7
- package/lib/client/auth/strategies.js +1 -1
- package/lib/client/constants.d.ts +1 -0
- package/lib/client/constants.js +1 -0
- package/lib/client/mixins/IAMMixin.js +2 -2
- package/lib/components/animation/AnimatedText.d.ts +1 -44
- package/lib/components/animation/AnimatedText.js +6 -122
- package/lib/components/anonymous/AnonymousKeyExpired.d.ts +56 -0
- package/lib/components/anonymous/AnonymousKeyExpired.js +96 -0
- package/lib/components/anonymous/AnonymousKeyTimer.d.ts +63 -0
- package/lib/components/anonymous/AnonymousKeyTimer.js +140 -0
- package/lib/components/anonymous/index.d.ts +7 -0
- package/lib/components/anonymous/index.js +15 -0
- package/lib/components/avatars/UserAvatar.d.ts +7 -1
- package/lib/components/avatars/UserAvatar.js +15 -1
- package/lib/components/billing/BillingEntitySelect.d.ts +6 -0
- package/lib/components/billing/BillingEntitySelect.js +49 -10
- package/lib/components/billing/eligibility.d.ts +22 -0
- package/lib/components/billing/eligibility.js +27 -0
- package/lib/components/billing/index.d.ts +1 -0
- package/lib/components/billing/index.js +1 -0
- package/lib/components/checkout/StripeCheckout.d.ts +1 -1
- package/lib/components/checkout/StripeCheckout.js +1 -1
- package/lib/components/collaboration/LiveEditorCollaborators.d.ts +5 -0
- package/lib/components/collaboration/LiveEditorCollaborators.js +3 -1
- package/lib/components/display/DatalayerBox.d.ts +2 -3
- package/lib/components/display/DatalayerBox.js +1 -1
- package/lib/components/display/NavLink.js +3 -2
- package/lib/components/display/VisuallyHidden.d.ts +1 -2
- package/lib/components/labels/StatusLabels.d.ts +2 -10
- package/lib/components/labels/StatusLabels.js +2 -26
- package/lib/components/principal/PrincipalAppearance.d.ts +21 -42
- package/lib/components/principal/PrincipalAppearance.js +232 -174
- package/lib/components/principal/PrincipalAvatar.d.ts +8 -1
- package/lib/components/principal/PrincipalAvatar.js +2 -2
- package/lib/components/principal/PrincipalDetailsOverlay.d.ts +8 -1
- package/lib/components/principal/PrincipalDetailsOverlay.js +2 -2
- package/lib/components/screencapture/Screencapture.js +46 -3
- package/lib/components/sharing/ShareAccessComponent.d.ts +45 -4
- package/lib/components/sharing/ShareAccessComponent.js +110 -78
- package/lib/components/sharing/SharingEditor.d.ts +5 -1
- package/lib/components/sharing/SharingEditor.js +9 -4
- package/lib/components/sharing/index.d.ts +1 -0
- package/lib/components/sharing/index.js +1 -0
- package/lib/components/sharing/sandboxSharing.d.ts +26 -0
- package/lib/components/sharing/sandboxSharing.js +47 -0
- package/lib/components/spaces/SpaceDetailsOverlay.d.ts +39 -0
- package/lib/components/spaces/SpaceDetailsOverlay.js +80 -0
- package/lib/components/spaces/SpaceDisplay.d.ts +38 -0
- package/lib/components/spaces/SpaceDisplay.js +92 -0
- package/lib/components/spaces/index.d.ts +4 -0
- package/lib/components/spaces/index.js +7 -0
- package/lib/components/spaces/spaceDisplayModel.d.ts +93 -0
- package/lib/components/spaces/spaceDisplayModel.js +170 -0
- package/lib/config/Configuration.d.ts +4 -4
- package/lib/config/Configuration.js +7 -7
- package/lib/config/index.d.ts +1 -0
- package/lib/config/index.js +1 -0
- package/lib/config/planes.d.ts +45 -0
- package/lib/config/planes.js +53 -0
- package/lib/hooks/cacheConverters.d.ts +0 -7
- package/lib/hooks/cacheConverters.js +0 -25
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/useBackdrop.d.ts +4 -5
- package/lib/hooks/useBillingEntityStore.js +3 -0
- package/lib/hooks/useCache.d.ts +197 -44
- package/lib/hooks/useCache.js +1586 -494
- package/lib/hooks/useContents.d.ts +22 -1
- package/lib/hooks/useContents.js +90 -21
- package/lib/hooks/useMcp.d.ts +87 -1
- package/lib/hooks/useMcp.js +248 -13
- package/lib/hooks/useNavigate.d.ts +41 -3
- package/lib/hooks/useNavigate.js +116 -52
- package/lib/hooks/usePrincipalCacheStore.js +3 -0
- package/lib/hooks/usePrincipalStore.js +3 -0
- package/lib/hooks/useSpaceCacheStore.d.ts +50 -0
- package/lib/hooks/useSpaceCacheStore.js +85 -0
- package/lib/hooks/useWindowSize.js +1 -1
- package/lib/models/CreditsDTO.d.ts +6 -5
- package/lib/models/CreditsDTO.js +7 -5
- package/lib/models/IAMProvidersSpecs.d.ts +10 -5
- package/lib/models/IAMProvidersSpecs.js +0 -23
- package/lib/models/McpBinding.d.ts +6 -0
- package/lib/models/Organization.d.ts +69 -0
- package/lib/models/Organization.js +96 -0
- package/lib/models/Secret.d.ts +1 -2
- package/lib/models/Secret.js +2 -18
- package/lib/models/StartedBy.d.ts +34 -0
- package/lib/models/StartedBy.js +36 -0
- package/lib/models/Team.d.ts +2 -0
- package/lib/models/Team.js +2 -0
- package/lib/models/User.d.ts +4 -0
- package/lib/models/User.js +3 -0
- package/lib/models/UserSettings.d.ts +13 -0
- package/lib/models/UserSettings.js +9 -0
- package/lib/models/contents/__fixtures__/v1-contracts.json +158 -30
- package/lib/navigation/adapters/react-router.d.ts +1 -1
- package/lib/navigation/adapters/react-router.js +3 -0
- package/lib/navigation/components.js +2 -3
- package/lib/routes/publicPaths.js +4 -0
- package/lib/state/index.d.ts +1 -0
- package/lib/state/index.js +1 -0
- package/lib/state/sessionEnd.d.ts +55 -0
- package/lib/state/sessionEnd.js +162 -0
- package/lib/state/substates/CoreState.js +3 -16
- package/lib/state/substates/IAMState.d.ts +3 -3
- package/lib/state/substates/IAMState.js +7 -0
- package/lib/state/substates/LayoutState.js +12 -0
- package/lib/state/substates/NavigationState.d.ts +82 -0
- package/lib/state/substates/NavigationState.js +255 -0
- package/lib/state/substates/ProfileState.d.ts +1 -0
- package/lib/state/substates/ProfileState.js +1 -0
- package/lib/state/substates/index.d.ts +1 -0
- package/lib/state/substates/index.js +1 -0
- package/lib/utils/Lazy.d.ts +20 -0
- package/lib/utils/Lazy.js +32 -6
- package/lib/utils/Screencapture.d.ts +15 -0
- package/lib/utils/Screencapture.js +26 -20
- package/lib/utils/WithSuspense.d.ts +11 -1
- package/lib/utils/WithSuspense.js +11 -1
- package/lib/views/mcp/AdmittedClients.d.ts +44 -0
- package/lib/views/mcp/AdmittedClients.js +59 -0
- package/lib/views/mcp/ApprovalQueue.d.ts +66 -0
- package/lib/views/mcp/ApprovalQueue.js +95 -0
- package/lib/views/mcp/ConnectedAgents.js +38 -3
- package/lib/views/mcp/EnterpriseConsole.d.ts +1 -1
- package/lib/views/mcp/EnterpriseConsole.js +23 -1
- package/lib/views/mcp/IdentityProviders.d.ts +33 -0
- package/lib/views/mcp/IdentityProviders.js +299 -0
- package/lib/views/mcp/McpDashboard.js +90 -7
- package/lib/views/mcp/McpHome.js +1 -1
- package/lib/views/mcp/McpObservability.d.ts +30 -1
- package/lib/views/mcp/McpObservability.js +105 -19
- package/lib/views/mcp/NotebookRuns.d.ts +39 -0
- package/lib/views/mcp/NotebookRuns.js +44 -0
- package/lib/views/mcp/OrganizationPolicy.js +2 -1
- package/lib/views/mcp/PersonalPolicy.js +2 -1
- package/lib/views/mcp/PolicyForm.d.ts +17 -1
- package/lib/views/mcp/PolicyForm.js +25 -3
- package/lib/views/mcp/PolicyHistory.d.ts +13 -0
- package/lib/views/mcp/PolicyHistory.js +14 -1
- package/lib/views/mcp/RunDetail.d.ts +87 -0
- package/lib/views/mcp/RunDetail.js +186 -0
- package/lib/views/mcp/ScimProvisioning.d.ts +54 -0
- package/lib/views/mcp/ScimProvisioning.js +173 -0
- package/lib/views/mcp/TeamPolicies.js +66 -5
- package/lib/views/mcp/ToolAccess.d.ts +60 -0
- package/lib/views/mcp/ToolAccess.js +101 -0
- package/lib/views/mcp/TraceTimeline.d.ts +81 -0
- package/lib/views/mcp/TraceTimeline.js +132 -0
- package/lib/views/mcp/index.d.ts +5 -0
- package/lib/views/mcp/index.js +5 -0
- package/lib/views/otel/simpleAuthStore.js +3 -0
- package/lib/views/secrets/SecretEdit.js +3 -2
- package/lib/views/secrets/SecretNew.js +5 -1
- package/package.json +271 -264
- package/scripts/generate-mcp-types.py +16 -10
- package/scripts/generate-orchestration-types.py +920 -0
|
@@ -5,6 +5,13 @@ export type PrincipalAvatarProps = {
|
|
|
5
5
|
kind: PrincipalAvatarKind;
|
|
6
6
|
avatarUrl?: string;
|
|
7
7
|
avatarIcon?: string;
|
|
8
|
+
/**
|
|
9
|
+
* A literal emoji this platform draws for a face of its own — an agent —
|
|
10
|
+
* rather than a person's chosen picture or icon. Checked before
|
|
11
|
+
* `avatarUrl`/`avatarIcon`, and only for `kind: 'personal'`: an agent is a
|
|
12
|
+
* personal-shaped seat in every roster it appears in today.
|
|
13
|
+
*/
|
|
14
|
+
avatarEmoji?: string;
|
|
8
15
|
alt?: string;
|
|
9
16
|
size?: number;
|
|
10
17
|
square?: boolean;
|
|
@@ -17,5 +24,5 @@ export type PrincipalAvatarProps = {
|
|
|
17
24
|
ring?: boolean;
|
|
18
25
|
className?: string;
|
|
19
26
|
};
|
|
20
|
-
export declare function PrincipalAvatar({ kind, avatarUrl, avatarIcon, alt, size, square, ring, className, }: PrincipalAvatarProps): JSX.Element;
|
|
27
|
+
export declare function PrincipalAvatar({ kind, avatarUrl, avatarIcon, avatarEmoji, alt, size, square, ring, className, }: PrincipalAvatarProps): JSX.Element;
|
|
21
28
|
export default PrincipalAvatar;
|
|
@@ -6,7 +6,7 @@ import { getPrincipalAvatarIcon, } from './PrincipalAppearance.js';
|
|
|
6
6
|
function getFallbackIconSize(size) {
|
|
7
7
|
return Math.max(12, Math.round(size * 0.62));
|
|
8
8
|
}
|
|
9
|
-
export function PrincipalAvatar({ kind, avatarUrl, avatarIcon, alt, size = 20, square = false, ring = false, className, }) {
|
|
9
|
+
export function PrincipalAvatar({ kind, avatarUrl, avatarIcon, avatarEmoji, alt, size = 20, square = false, ring = false, className, }) {
|
|
10
10
|
const SelectedIcon = getPrincipalAvatarIcon(avatarIcon);
|
|
11
11
|
// Outside the edge rather than a border, so the avatar keeps the size it
|
|
12
12
|
// was asked for — see `UserAvatar`, which draws its ring the same way.
|
|
@@ -23,7 +23,7 @@ export function PrincipalAvatar({ kind, avatarUrl, avatarIcon, alt, size = 20, s
|
|
|
23
23
|
* person who had chosen one was a bare drawing among circles.
|
|
24
24
|
*/
|
|
25
25
|
if (kind === 'personal') {
|
|
26
|
-
return (_jsx(UserAvatar, { avatarUrl: avatarUrl, avatarIcon: avatarIcon, size: size, square: square, iconSize: getFallbackIconSize(size), ring: ring, className: className }));
|
|
26
|
+
return (_jsx(UserAvatar, { avatarUrl: avatarUrl, avatarIcon: avatarIcon, avatarEmoji: avatarEmoji, size: size, square: square, iconSize: getFallbackIconSize(size), ring: ring, className: className }));
|
|
27
27
|
}
|
|
28
28
|
if (SelectedIcon) {
|
|
29
29
|
return (_jsx(Box, { className: className, sx: {
|
|
@@ -14,6 +14,13 @@ export type PrincipalDetailsOverlayProps = {
|
|
|
14
14
|
origin?: string;
|
|
15
15
|
avatarUrl?: string;
|
|
16
16
|
avatarIcon?: string;
|
|
17
|
+
/**
|
|
18
|
+
* A literal emoji, for a face this platform draws rather than a person's
|
|
19
|
+
* own choice of picture or icon — an agent, checked before `avatarUrl`/
|
|
20
|
+
* `avatarIcon` since the emoji is its real identity here, not a
|
|
21
|
+
* placeholder standing in for one.
|
|
22
|
+
*/
|
|
23
|
+
avatarEmoji?: string;
|
|
17
24
|
/** Team-specific: parent organization display name. */
|
|
18
25
|
organizationName?: string;
|
|
19
26
|
/** Team-specific: number of members. */
|
|
@@ -51,7 +58,7 @@ export declare function buildPrincipalProfilePath({ kind, uid, handle, accountHa
|
|
|
51
58
|
* anchored on an avatar ({@link PrincipalHoverCard}) both render this, so
|
|
52
59
|
* the two never drift.
|
|
53
60
|
*/
|
|
54
|
-
export declare function PrincipalDetailsCard({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, avatarIcon, organizationName, memberCount, isPublic, isAdmin, onNavigate, }: PrincipalDetailsOverlayProps): JSX.Element;
|
|
61
|
+
export declare function PrincipalDetailsCard({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, avatarIcon, avatarEmoji, organizationName, memberCount, isPublic, isAdmin, onNavigate, }: PrincipalDetailsOverlayProps): JSX.Element;
|
|
55
62
|
/**
|
|
56
63
|
* A principal's details, shown from a click on their name.
|
|
57
64
|
*
|
|
@@ -84,7 +84,7 @@ export function buildPrincipalProfilePath({ kind, uid, handle, accountHandle, is
|
|
|
84
84
|
* anchored on an avatar ({@link PrincipalHoverCard}) both render this, so
|
|
85
85
|
* the two never drift.
|
|
86
86
|
*/
|
|
87
|
-
export function PrincipalDetailsCard({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, avatarIcon, organizationName, memberCount, isPublic, isAdmin = false, onNavigate, }) {
|
|
87
|
+
export function PrincipalDetailsCard({ kind, uid, displayName, name, description, handle, accountHandle, firstName, lastName, email, origin, avatarUrl, avatarIcon, avatarEmoji, organizationName, memberCount, isPublic, isAdmin = false, onNavigate, }) {
|
|
88
88
|
const navigate = useNavigate();
|
|
89
89
|
// Where a profile or organization link goes: the router of this subtree,
|
|
90
90
|
// unless the caller knows of one that can actually serve it — see
|
|
@@ -135,7 +135,7 @@ export function PrincipalDetailsCard({ kind, uid, displayName, name, description
|
|
|
135
135
|
const organizationPath = teamOrganizationHandle
|
|
136
136
|
? `/${teamOrganizationHandle.replace(/^@+/, '')}`
|
|
137
137
|
: '';
|
|
138
|
-
return (_jsxs(Box, { sx: { display: 'grid', gap: 3, p: 4, minWidth: 420 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(PrincipalAvatar, { kind: kind, avatarUrl: avatarUrl, avatarIcon: avatarIcon, alt: normalizedDisplayName, size: 40,
|
|
138
|
+
return (_jsxs(Box, { sx: { display: 'grid', gap: 3, p: 4, minWidth: 420 }, children: [_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(PrincipalAvatar, { kind: kind, avatarUrl: avatarUrl, avatarIcon: avatarIcon, avatarEmoji: avatarEmoji, alt: normalizedDisplayName, size: 40,
|
|
139
139
|
// The card sets the avatar on its own ground, the same colour
|
|
140
140
|
// the avatar itself is on: without an edge of its own it has
|
|
141
141
|
// no visible shape at all. Round, and ringed.
|
|
@@ -5,6 +5,13 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
5
5
|
*/
|
|
6
6
|
import { Component } from 'react';
|
|
7
7
|
import html2canvas from 'html2canvas';
|
|
8
|
+
/**
|
|
9
|
+
* The longest edge a capture is allowed, in device pixels.
|
|
10
|
+
*
|
|
11
|
+
* The library caps a stored image at 2 MB. 1600 keeps a full-width selection
|
|
12
|
+
* legible while leaving room under that ceiling as lossless PNG.
|
|
13
|
+
*/
|
|
14
|
+
const MAX_CAPTURE_EDGE = 1600;
|
|
8
15
|
export class Screencapture extends Component {
|
|
9
16
|
state = {
|
|
10
17
|
on: false,
|
|
@@ -128,13 +135,49 @@ export class Screencapture extends Component {
|
|
|
128
135
|
width: windowWidth,
|
|
129
136
|
height: windowHeight,
|
|
130
137
|
scale: scale,
|
|
138
|
+
/*
|
|
139
|
+
* Draw the pictures that come from somewhere else.
|
|
140
|
+
*
|
|
141
|
+
* Without this html2canvas leaves every cross-origin image out and
|
|
142
|
+
* keeps the space it occupied, so a markdown cell carrying an `<img>`
|
|
143
|
+
* from the web captured as a blank rectangle the right size. With it
|
|
144
|
+
* the image is fetched anonymously and drawn, and the canvas stays
|
|
145
|
+
* untainted so `toDataURL` below still works — which `allowTaint`
|
|
146
|
+
* would not: that draws the image and then makes the canvas
|
|
147
|
+
* unreadable, which is worse than the hole it fills.
|
|
148
|
+
*
|
|
149
|
+
* A host that sends no `Access-Control-Allow-Origin` still cannot be
|
|
150
|
+
* drawn. Nothing can be done about that from here.
|
|
151
|
+
*/
|
|
152
|
+
useCORS: true,
|
|
131
153
|
}).then(canvas => {
|
|
132
154
|
const croppedCanvas = document.createElement('canvas');
|
|
133
155
|
const croppedCanvasContext = croppedCanvas.getContext('2d');
|
|
134
|
-
|
|
135
|
-
|
|
156
|
+
/*
|
|
157
|
+
* Device pixels, not CSS pixels.
|
|
158
|
+
*
|
|
159
|
+
* `html2canvas` renders at `scale`, so the source rectangle below is
|
|
160
|
+
* measured in device pixels — and it was being drawn into a canvas
|
|
161
|
+
* sized in CSS ones. On any display with a pixel ratio above 1 the
|
|
162
|
+
* destination was twice the canvas, so the capture came back cut off
|
|
163
|
+
* at the right and the bottom.
|
|
164
|
+
*/
|
|
165
|
+
const sourceWidth = cropWidth * scale;
|
|
166
|
+
const sourceHeight = cropHeigth * scale;
|
|
167
|
+
/*
|
|
168
|
+
* And bounded, because a capture has somewhere to go.
|
|
169
|
+
*
|
|
170
|
+
* The library refuses an image over 2 MB, and a full-height selection
|
|
171
|
+
* on a retina screen is comfortably past that as lossless PNG — so an
|
|
172
|
+
* honest device-pixel capture has to be capped or it becomes a
|
|
173
|
+
* capture that cannot be published. Shrunk on the way into the canvas
|
|
174
|
+
* rather than after it, so there is one resample rather than two.
|
|
175
|
+
*/
|
|
176
|
+
const shrink = Math.min(1, MAX_CAPTURE_EDGE / Math.max(sourceWidth, sourceHeight));
|
|
177
|
+
croppedCanvas.width = Math.max(1, Math.round(sourceWidth * shrink));
|
|
178
|
+
croppedCanvas.height = Math.max(1, Math.round(sourceHeight * shrink));
|
|
136
179
|
if (croppedCanvasContext) {
|
|
137
|
-
croppedCanvasContext.drawImage(canvas, cropPositionLeft * scale, cropPositionTop * scale,
|
|
180
|
+
croppedCanvasContext.drawImage(canvas, cropPositionLeft * scale, cropPositionTop * scale, sourceWidth, sourceHeight, 0, 0, croppedCanvas.width, croppedCanvas.height);
|
|
138
181
|
}
|
|
139
182
|
if (croppedCanvas) {
|
|
140
183
|
const type = 'image/png';
|
|
@@ -1,13 +1,29 @@
|
|
|
1
1
|
import type { JSX } from 'react';
|
|
2
2
|
export type ItemAccessLevel = 'view' | 'update' | 'execute';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Who a resource can be shared with. `agent` is a service agent: sharing with
|
|
5
|
+
* one grants that agent alone — the grant is matched on the agent's own uid,
|
|
6
|
+
* never on the people who can act through it — so it is a principal in its own
|
|
7
|
+
* right rather than a shorthand for its organization.
|
|
8
|
+
*/
|
|
9
|
+
type PrincipalKind = 'personal' | 'team' | 'organization' | 'agent';
|
|
10
|
+
/**
|
|
11
|
+
* One level the dialog offers, and what it is called. A resource whose
|
|
12
|
+
* service grants other levels than view, update and execute names its own —
|
|
13
|
+
* a benchmark's Reviewer and Runner, for one.
|
|
14
|
+
*/
|
|
15
|
+
export type AccessLevelOption = {
|
|
16
|
+
level: string;
|
|
17
|
+
label: string;
|
|
18
|
+
};
|
|
4
19
|
type SharingLevelPayload = {
|
|
5
20
|
userUids?: string[];
|
|
6
21
|
teamUids?: string[];
|
|
7
22
|
organizationUids?: string[];
|
|
23
|
+
agentUids?: string[];
|
|
8
24
|
};
|
|
9
25
|
type SharingPayload = {
|
|
10
|
-
access?: Partial<Record<
|
|
26
|
+
access?: Partial<Record<string, SharingLevelPayload>>;
|
|
11
27
|
};
|
|
12
28
|
export type ShareAccessTransport = {
|
|
13
29
|
load: () => Promise<Record<string, any>>;
|
|
@@ -22,12 +38,37 @@ export type ShareAccessComponentProps = {
|
|
|
22
38
|
resourceDescription?: string;
|
|
23
39
|
expanded?: boolean;
|
|
24
40
|
onSharingAccessRestrictedChange?: (restricted: boolean, message?: string) => void;
|
|
25
|
-
defaultAccessLevel?:
|
|
41
|
+
defaultAccessLevel?: string;
|
|
42
|
+
/** The levels offered, lowest first; view, update and execute when not named. */
|
|
43
|
+
levels?: readonly AccessLevelOption[];
|
|
26
44
|
principalKinds?: readonly PrincipalKind[];
|
|
27
45
|
displayMode?: 'dialog' | 'inline';
|
|
28
46
|
onClose: () => void;
|
|
29
47
|
};
|
|
30
|
-
|
|
48
|
+
type AccessByLevel = Record<string, {
|
|
49
|
+
userUids: string[];
|
|
50
|
+
teamUids: string[];
|
|
51
|
+
organizationUids: string[];
|
|
52
|
+
agentUids: string[];
|
|
53
|
+
}>;
|
|
54
|
+
type ACLPrincipalEntry = {
|
|
55
|
+
kind: PrincipalKind;
|
|
56
|
+
uid: string;
|
|
57
|
+
levels: string[];
|
|
58
|
+
};
|
|
59
|
+
type OwnerPrincipal = {
|
|
60
|
+
kind: PrincipalKind;
|
|
61
|
+
uid: string;
|
|
62
|
+
handle: string;
|
|
63
|
+
displayName: string;
|
|
64
|
+
avatarUrl?: string;
|
|
65
|
+
origin?: string;
|
|
66
|
+
accountHandle?: string;
|
|
67
|
+
};
|
|
68
|
+
export declare function extractOwnerPrincipals(payload: any): OwnerPrincipal[];
|
|
69
|
+
export declare function buildAclEntries(state: AccessByLevel, principalKinds: readonly PrincipalKind[]): ACLPrincipalEntry[];
|
|
70
|
+
export declare function hydrateAccessFromSharing(sharing: SharingPayload, levels: readonly AccessLevelOption[]): AccessByLevel;
|
|
71
|
+
export declare function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLabel, resourceName, resourceDescription: _resourceDescription, expanded, onSharingAccessRestrictedChange, defaultAccessLevel, levels, principalKinds, displayMode, onClose, }: ShareAccessComponentProps): JSX.Element | null;
|
|
31
72
|
export default ShareAccessComponent;
|
|
32
73
|
export declare const ShareAccessDialog: typeof ShareAccessComponent;
|
|
33
74
|
export type ShareAccessDialogProps = ShareAccessComponentProps;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { ChevronDownIcon, ChevronUpIcon, KeyIcon, PersonIcon, OrganizationIcon, PeopleIcon, } from '@primer/octicons-react';
|
|
4
4
|
import { Box } from '@datalayer/primer-addons';
|
|
@@ -10,17 +10,17 @@ import { PrincipalBadge } from '../principal/PrincipalBadge.js';
|
|
|
10
10
|
// ---------------------------------------------------------------------------
|
|
11
11
|
// Constants.
|
|
12
12
|
// ---------------------------------------------------------------------------
|
|
13
|
-
const
|
|
13
|
+
const DEFAULT_ACCESS_LEVELS = [
|
|
14
|
+
{ level: 'view', label: 'Viewer' },
|
|
15
|
+
{ level: 'update', label: 'Editor' },
|
|
16
|
+
{ level: 'execute', label: 'Executor' },
|
|
17
|
+
];
|
|
14
18
|
const DEFAULT_PRINCIPAL_KINDS = [
|
|
15
19
|
'personal',
|
|
16
20
|
'team',
|
|
17
21
|
'organization',
|
|
22
|
+
'agent',
|
|
18
23
|
];
|
|
19
|
-
const ACCESS_LEVEL_LABELS = {
|
|
20
|
-
view: 'Viewer',
|
|
21
|
-
update: 'Editor',
|
|
22
|
-
execute: 'Executor',
|
|
23
|
-
};
|
|
24
24
|
// ---------------------------------------------------------------------------
|
|
25
25
|
// String / payload helpers.
|
|
26
26
|
// ---------------------------------------------------------------------------
|
|
@@ -40,6 +40,9 @@ function normalizePrincipalKind(kindRaw) {
|
|
|
40
40
|
if (kind === 'organization' || kind === 'org') {
|
|
41
41
|
return 'organization';
|
|
42
42
|
}
|
|
43
|
+
if (kind === 'agent') {
|
|
44
|
+
return 'agent';
|
|
45
|
+
}
|
|
43
46
|
return 'personal';
|
|
44
47
|
}
|
|
45
48
|
function toTitleCase(value) {
|
|
@@ -80,6 +83,9 @@ function ensurePrincipalDisplayName(kind, ...candidates) {
|
|
|
80
83
|
if (kind === 'team') {
|
|
81
84
|
return 'Team';
|
|
82
85
|
}
|
|
86
|
+
if (kind === 'agent') {
|
|
87
|
+
return 'Agent';
|
|
88
|
+
}
|
|
83
89
|
return 'Principal';
|
|
84
90
|
}
|
|
85
91
|
function formatPrincipalHandle(kind, handle, accountHandle) {
|
|
@@ -109,7 +115,7 @@ function principalKey(kind, uid) {
|
|
|
109
115
|
// ---------------------------------------------------------------------------
|
|
110
116
|
// Owner extraction (preserves all current fallbacks).
|
|
111
117
|
// ---------------------------------------------------------------------------
|
|
112
|
-
function extractOwnerPrincipals(payload) {
|
|
118
|
+
export function extractOwnerPrincipals(payload) {
|
|
113
119
|
const ownersFromSharing = Array.isArray(payload?.sharing?.owners)
|
|
114
120
|
? payload.sharing.owners
|
|
115
121
|
: [];
|
|
@@ -132,7 +138,11 @@ function extractOwnerPrincipals(payload) {
|
|
|
132
138
|
payload?.resource?.owner ||
|
|
133
139
|
payload?.sharing?.owner ||
|
|
134
140
|
{};
|
|
135
|
-
const ownerUid = pickFirstString(ownerPayload?.uid, ownerPayload?.owner_uid, ownerPayload?.ownerUid, ownerPayload?.id, payload?.owner_uid, payload?.ownerUid
|
|
141
|
+
const ownerUid = pickFirstString(ownerPayload?.uid, ownerPayload?.owner_uid, ownerPayload?.ownerUid, ownerPayload?.id, payload?.owner_uid, payload?.ownerUid,
|
|
142
|
+
// Runtimes names a sandbox's owner inside its `sharing` document rather
|
|
143
|
+
// than beside it. Without this the dialog draws no owner at all, which
|
|
144
|
+
// reads as a resource nobody owns.
|
|
145
|
+
payload?.sharing?.owner_uid, payload?.sharing?.ownerUid);
|
|
136
146
|
const ownerHandle = pickFirstString(ownerPayload?.handle_s, ownerPayload?.handle, ownerPayload?.owner_handle, ownerPayload?.ownerHandle, payload?.owner_handle, payload?.ownerHandle);
|
|
137
147
|
const kindFromOwnerPayload = normalizePrincipalKind(pickFirstString(ownerPayload?.kind, ownerPayload?.type, ownerPayload?.principal_kind, ownerPayload?.principalKind, payload?.owner_kind, payload?.ownerKind, payload?.owner_type, payload?.ownerType));
|
|
138
148
|
const accountHandle = pickFirstString(ownerPayload?.organization_handle_s, ownerPayload?.organizationHandle, ownerPayload?.organization_handle, payload?.space?.organization_handle_s, payload?.space?.organizationHandle, payload?.space?.organization_handle);
|
|
@@ -212,19 +222,20 @@ function extractOwnerPrincipals(payload) {
|
|
|
212
222
|
// ---------------------------------------------------------------------------
|
|
213
223
|
// AccessByLevel helpers.
|
|
214
224
|
// ---------------------------------------------------------------------------
|
|
215
|
-
function emptyAccessByLevel() {
|
|
216
|
-
return {
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
};
|
|
225
|
+
function emptyAccessByLevel(levels) {
|
|
226
|
+
return Object.fromEntries(levels.map(({ level }) => [
|
|
227
|
+
level,
|
|
228
|
+
{ userUids: [], teamUids: [], organizationUids: [], agentUids: [] },
|
|
229
|
+
]));
|
|
221
230
|
}
|
|
222
231
|
function bucketFor(kind) {
|
|
223
232
|
return kind === 'personal'
|
|
224
233
|
? 'userUids'
|
|
225
234
|
: kind === 'team'
|
|
226
235
|
? 'teamUids'
|
|
227
|
-
: '
|
|
236
|
+
: kind === 'agent'
|
|
237
|
+
? 'agentUids'
|
|
238
|
+
: 'organizationUids';
|
|
228
239
|
}
|
|
229
240
|
function hasPrincipal(state, level, kind, uid) {
|
|
230
241
|
const lower = uid.toLowerCase();
|
|
@@ -246,17 +257,15 @@ function withPrincipalAdded(state, level, kind, uid) {
|
|
|
246
257
|
function withPrincipalRemoved(state, kind, uid) {
|
|
247
258
|
const lower = uid.toLowerCase();
|
|
248
259
|
const bucket = bucketFor(kind);
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
return next;
|
|
260
|
+
return Object.fromEntries(Object.entries(state).map(([level, principals]) => [
|
|
261
|
+
level,
|
|
262
|
+
{
|
|
263
|
+
...principals,
|
|
264
|
+
[bucket]: principals[bucket].filter(value => value.toLowerCase() !== lower),
|
|
265
|
+
},
|
|
266
|
+
]));
|
|
258
267
|
}
|
|
259
|
-
function buildAclEntries(state, principalKinds) {
|
|
268
|
+
export function buildAclEntries(state, principalKinds) {
|
|
260
269
|
const allowed = new Set(principalKinds);
|
|
261
270
|
const byPrincipal = new Map();
|
|
262
271
|
const upsert = (kind, uid, level) => {
|
|
@@ -273,10 +282,11 @@ function buildAclEntries(state, principalKinds) {
|
|
|
273
282
|
existing.levels.push(level);
|
|
274
283
|
}
|
|
275
284
|
};
|
|
276
|
-
for (const level of
|
|
285
|
+
for (const level of Object.keys(state)) {
|
|
277
286
|
state[level].userUids.forEach(uid => upsert('personal', uid, level));
|
|
278
287
|
state[level].teamUids.forEach(uid => upsert('team', uid, level));
|
|
279
288
|
state[level].organizationUids.forEach(uid => upsert('organization', uid, level));
|
|
289
|
+
state[level].agentUids.forEach(uid => upsert('agent', uid, level));
|
|
280
290
|
}
|
|
281
291
|
return Array.from(byPrincipal.values()).sort((a, b) => {
|
|
282
292
|
if (a.kind !== b.kind) {
|
|
@@ -285,28 +295,20 @@ function buildAclEntries(state, principalKinds) {
|
|
|
285
295
|
return a.uid.localeCompare(b.uid);
|
|
286
296
|
});
|
|
287
297
|
}
|
|
288
|
-
function hydrateAccessFromSharing(sharing) {
|
|
298
|
+
export function hydrateAccessFromSharing(sharing, levels) {
|
|
289
299
|
const access = sharing.access || {};
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
organizationUids: [...(update.organizationUids || [])],
|
|
303
|
-
},
|
|
304
|
-
execute: {
|
|
305
|
-
userUids: [...(execute.userUids || [])],
|
|
306
|
-
teamUids: [...(execute.teamUids || [])],
|
|
307
|
-
organizationUids: [...(execute.organizationUids || [])],
|
|
308
|
-
},
|
|
309
|
-
};
|
|
300
|
+
return Object.fromEntries(levels.map(({ level }) => {
|
|
301
|
+
const given = access[level] || {};
|
|
302
|
+
return [
|
|
303
|
+
level,
|
|
304
|
+
{
|
|
305
|
+
userUids: [...(given.userUids || [])],
|
|
306
|
+
teamUids: [...(given.teamUids || [])],
|
|
307
|
+
organizationUids: [...(given.organizationUids || [])],
|
|
308
|
+
agentUids: [...(given.agentUids || [])],
|
|
309
|
+
},
|
|
310
|
+
];
|
|
311
|
+
}));
|
|
310
312
|
}
|
|
311
313
|
// ---------------------------------------------------------------------------
|
|
312
314
|
// Avatar shimmer (used while a user row is being hydrated).
|
|
@@ -325,6 +327,38 @@ function AvatarShimmer({ size = 20 }) {
|
|
|
325
327
|
},
|
|
326
328
|
} }));
|
|
327
329
|
}
|
|
330
|
+
// ---------------------------------------------------------------------------
|
|
331
|
+
// Row components.
|
|
332
|
+
// ---------------------------------------------------------------------------
|
|
333
|
+
/**
|
|
334
|
+
* An agent's avatar. A service agent has no picture, handle or banner of its
|
|
335
|
+
* own — it is a credential, not a person — so it is drawn as a key rather than
|
|
336
|
+
* pushed through the personal/team/organization avatar system.
|
|
337
|
+
*/
|
|
338
|
+
function AgentAvatar({ size = 20 }) {
|
|
339
|
+
return (_jsx(Box, { sx: {
|
|
340
|
+
display: 'inline-flex',
|
|
341
|
+
alignItems: 'center',
|
|
342
|
+
justifyContent: 'center',
|
|
343
|
+
width: size,
|
|
344
|
+
height: size,
|
|
345
|
+
borderRadius: 2,
|
|
346
|
+
bg: 'canvas.subtle',
|
|
347
|
+
color: 'fg.muted',
|
|
348
|
+
flexShrink: 0,
|
|
349
|
+
}, "aria-label": "Agent", children: _jsx(KeyIcon, { size: Math.max(12, Math.round(size * 0.6)) }) }));
|
|
350
|
+
}
|
|
351
|
+
/** An agent as it appears in a row of principals: key, name, and the label
|
|
352
|
+
* that says what it is, so an agent is never mistaken for a person. */
|
|
353
|
+
function AgentPrincipalChip({ displayName, size = 20, }) {
|
|
354
|
+
return (_jsxs(Box, { sx: {
|
|
355
|
+
display: 'inline-flex',
|
|
356
|
+
alignItems: 'center',
|
|
357
|
+
gap: 1,
|
|
358
|
+
minWidth: 0,
|
|
359
|
+
flexWrap: 'wrap',
|
|
360
|
+
}, children: [_jsx(AgentAvatar, { size: size }), _jsx(Text, { sx: { minWidth: 0 }, children: displayName }), _jsx(Label, { size: "small", children: "Agent" })] }));
|
|
361
|
+
}
|
|
328
362
|
function OwnerPrincipalRow({ ownerPrincipal, cache, showAvatarSkeleton = false, isPlatformAdmin, }) {
|
|
329
363
|
const entry = cache[principalKey(ownerPrincipal.kind, ownerPrincipal.uid)] || {};
|
|
330
364
|
const cachedHandle = entry.handle;
|
|
@@ -365,7 +399,7 @@ function AccessPrincipalRow({ entry, cache, showAvatarSkeleton = false, isPlatfo
|
|
|
365
399
|
alignItems: 'center',
|
|
366
400
|
gap: 1,
|
|
367
401
|
flexWrap: 'wrap',
|
|
368
|
-
}, children: showAvatarSkeleton ? (_jsxs(_Fragment, { children: [_jsx(AvatarShimmer, { size: 20 }), _jsx(Text, { children: resolvedDisplayName })] })) : (_jsx(PrincipalBadge, { principal: {
|
|
402
|
+
}, children: showAvatarSkeleton ? (_jsxs(_Fragment, { children: [_jsx(AvatarShimmer, { size: 20 }), _jsx(Text, { children: resolvedDisplayName })] })) : entry.kind === 'agent' ? (_jsx(AgentPrincipalChip, { displayName: resolvedDisplayName })) : (_jsx(PrincipalBadge, { principal: {
|
|
369
403
|
kind: entry.kind,
|
|
370
404
|
uid: entry.uid,
|
|
371
405
|
displayName: resolvedDisplayName,
|
|
@@ -378,7 +412,7 @@ function AccessPrincipalRow({ entry, cache, showAvatarSkeleton = false, isPlatfo
|
|
|
378
412
|
// ---------------------------------------------------------------------------
|
|
379
413
|
// Main component.
|
|
380
414
|
// ---------------------------------------------------------------------------
|
|
381
|
-
export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLabel, resourceName, resourceDescription: _resourceDescription, expanded = false, onSharingAccessRestrictedChange, defaultAccessLevel = 'view', principalKinds = DEFAULT_PRINCIPAL_KINDS, displayMode = 'dialog', onClose, }) {
|
|
415
|
+
export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLabel, resourceName, resourceDescription: _resourceDescription, expanded = false, onSharingAccessRestrictedChange, defaultAccessLevel = 'view', levels = DEFAULT_ACCESS_LEVELS, principalKinds = DEFAULT_PRINCIPAL_KINDS, displayMode = 'dialog', onClose, }) {
|
|
382
416
|
void _resourceDescription;
|
|
383
417
|
const { token, user } = useIAMStore();
|
|
384
418
|
const { configuration } = useCoreStore();
|
|
@@ -389,7 +423,8 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
389
423
|
const [isSaving, setIsSaving] = useState(false);
|
|
390
424
|
const [isExpanded, setIsExpanded] = useState(expanded);
|
|
391
425
|
const [selectedAccessLevel, setSelectedAccessLevel] = useState(defaultAccessLevel);
|
|
392
|
-
const
|
|
426
|
+
const levelLabels = useMemo(() => Object.fromEntries(levels.map(({ level, label }) => [level, label])), [levels]);
|
|
427
|
+
const [access, setAccess] = useState(() => emptyAccessByLevel(levels));
|
|
393
428
|
const [ownerPrincipals, setOwnerPrincipals] = useState([]);
|
|
394
429
|
const [shareablePrincipals, setShareablePrincipals] = useState([]);
|
|
395
430
|
const [isLoadingShareable, setIsLoadingShareable] = useState(false);
|
|
@@ -522,7 +557,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
522
557
|
if (!cancelled && isSharingAuthorizationMessage(message)) {
|
|
523
558
|
setSharingAccessMessage(message);
|
|
524
559
|
setIsSharingAccessConfirmed(true);
|
|
525
|
-
setAccess(emptyAccessByLevel());
|
|
560
|
+
setAccess(emptyAccessByLevel(levels));
|
|
526
561
|
setOwnerPrincipals([]);
|
|
527
562
|
return;
|
|
528
563
|
}
|
|
@@ -534,7 +569,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
534
569
|
if (!cancelled) {
|
|
535
570
|
setSharingAccessMessage(message);
|
|
536
571
|
setIsSharingAccessConfirmed(true);
|
|
537
|
-
setAccess(emptyAccessByLevel());
|
|
572
|
+
setAccess(emptyAccessByLevel(levels));
|
|
538
573
|
setOwnerPrincipals([]);
|
|
539
574
|
}
|
|
540
575
|
return;
|
|
@@ -546,7 +581,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
546
581
|
}
|
|
547
582
|
const sharing = (payload?.sharing || {});
|
|
548
583
|
const owners = extractOwnerPrincipals(payload);
|
|
549
|
-
const hydrated = hydrateAccessFromSharing(sharing);
|
|
584
|
+
const hydrated = hydrateAccessFromSharing(sharing, levels);
|
|
550
585
|
setOwnerPrincipals(owners);
|
|
551
586
|
owners.forEach(owner => {
|
|
552
587
|
mergePrincipalCacheEntry(owner.kind, owner.uid, {
|
|
@@ -589,6 +624,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
589
624
|
token,
|
|
590
625
|
resourceLabel,
|
|
591
626
|
resourceName,
|
|
627
|
+
levels,
|
|
592
628
|
mergePrincipalCacheEntry,
|
|
593
629
|
]);
|
|
594
630
|
// ----- Fetch shareable principals on open -----
|
|
@@ -1016,23 +1052,15 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
1016
1052
|
setIsSaving(true);
|
|
1017
1053
|
try {
|
|
1018
1054
|
const body = {
|
|
1019
|
-
access:
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1055
|
+
access: Object.fromEntries(Object.entries(snapshot).map(([level, principals]) => [
|
|
1056
|
+
level,
|
|
1057
|
+
{
|
|
1058
|
+
userUids: principals.userUids,
|
|
1059
|
+
teamUids: principals.teamUids,
|
|
1060
|
+
organizationUids: principals.organizationUids,
|
|
1061
|
+
agentUids: principals.agentUids,
|
|
1024
1062
|
},
|
|
1025
|
-
|
|
1026
|
-
userUids: snapshot.update.userUids,
|
|
1027
|
-
teamUids: snapshot.update.teamUids,
|
|
1028
|
-
organizationUids: snapshot.update.organizationUids,
|
|
1029
|
-
},
|
|
1030
|
-
execute: {
|
|
1031
|
-
userUids: snapshot.execute.userUids,
|
|
1032
|
-
teamUids: snapshot.execute.teamUids,
|
|
1033
|
-
organizationUids: snapshot.execute.organizationUids,
|
|
1034
|
-
},
|
|
1035
|
-
},
|
|
1063
|
+
])),
|
|
1036
1064
|
};
|
|
1037
1065
|
if (transport) {
|
|
1038
1066
|
await transport.save(body);
|
|
@@ -1169,7 +1197,8 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
1169
1197
|
const otherUsers = filtered.filter(p => p.kind === 'personal' && p.uid !== selfUid);
|
|
1170
1198
|
const orgs = filtered.filter(p => p.kind === 'organization');
|
|
1171
1199
|
const teams = filtered.filter(p => p.kind === 'team');
|
|
1172
|
-
|
|
1200
|
+
const agents = filtered.filter(p => p.kind === 'agent');
|
|
1201
|
+
return { self, otherUsers, orgs, teams, agents };
|
|
1173
1202
|
}, [shareablePrincipals, principalKindsSet, user?.uid]);
|
|
1174
1203
|
useEffect(() => {
|
|
1175
1204
|
if (isOpen) {
|
|
@@ -1192,7 +1221,9 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
1192
1221
|
? PersonIcon
|
|
1193
1222
|
: principal.kind === 'organization'
|
|
1194
1223
|
? OrganizationIcon
|
|
1195
|
-
:
|
|
1224
|
+
: principal.kind === 'agent'
|
|
1225
|
+
? KeyIcon
|
|
1226
|
+
: PeopleIcon;
|
|
1196
1227
|
return (_jsxs(Box, { as: "button", type: "button", onClick: () => {
|
|
1197
1228
|
if (!alreadyAdded) {
|
|
1198
1229
|
addPrincipal(principal.kind, principal.uid);
|
|
@@ -1222,7 +1253,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
1222
1253
|
alignItems: 'center',
|
|
1223
1254
|
gap: 2,
|
|
1224
1255
|
minWidth: 0,
|
|
1225
|
-
}, children: [_jsx(PrincipalAvatar, { kind: principal.kind, avatarUrl: principal.avatarUrl || undefined, alt: displayName, size: 22 }), _jsxs(Box, { sx: { display: 'grid', minWidth: 0 }, children: [_jsxs(Box, { sx: {
|
|
1256
|
+
}, children: [principal.kind === 'agent' ? (_jsx(AgentAvatar, { size: 22 })) : (_jsx(PrincipalAvatar, { kind: principal.kind, avatarUrl: principal.avatarUrl || undefined, alt: displayName, size: 22 })), _jsxs(Box, { sx: { display: 'grid', minWidth: 0 }, children: [_jsxs(Box, { sx: {
|
|
1226
1257
|
display: 'inline-flex',
|
|
1227
1258
|
alignItems: 'center',
|
|
1228
1259
|
gap: 1,
|
|
@@ -1270,9 +1301,9 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
1270
1301
|
alignItems: 'flex-start',
|
|
1271
1302
|
justifyContent: 'space-between',
|
|
1272
1303
|
gap: 2,
|
|
1273
|
-
}, children: [_jsx(Box, { sx: { display: 'grid', gap: 1 }, children: _jsxs(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: ["Share ", resourceName || `this ${resourceLabel.toLowerCase()}`, ". Pick a principal below \u2014 they will be granted the selected access level."] }) }), _jsxs(ActionMenu, { children: [_jsxs(Box, { sx: { display: 'inline-flex', alignItems: 'center', gap: 1 }, children: [_jsx(ActionMenu.Anchor, { children: _jsxs(Button, { variant: "default", size: "small", leadingVisual: KeyIcon, disabled: isSaving || isReadOnly, children: ["Access:
|
|
1304
|
+
}, children: [_jsx(Box, { sx: { display: 'grid', gap: 1 }, children: _jsxs(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: ["Share ", resourceName || `this ${resourceLabel.toLowerCase()}`, ". Pick a principal below \u2014 they will be granted the selected access level."] }) }), _jsxs(ActionMenu, { children: [_jsxs(Box, { sx: { display: 'inline-flex', alignItems: 'center', gap: 1 }, children: [_jsx(ActionMenu.Anchor, { children: _jsxs(Button, { variant: "default", size: "small", leadingVisual: KeyIcon, disabled: isSaving || isReadOnly, children: ["Access:", ' ', levelLabels[selectedAccessLevel] || selectedAccessLevel] }) }), _jsx(Button, { variant: "invisible", size: "small", leadingVisual: isExpanded ? ChevronUpIcon : ChevronDownIcon, onClick: () => setIsExpanded(previous => !previous), "aria-label": isExpanded
|
|
1274
1305
|
? 'Shrink sharing details'
|
|
1275
|
-
: 'Expand sharing details', children: isExpanded ? 'Shrink details' : 'Expand details' })] }), _jsx(ActionMenu.Overlay, { width: "small", children: _jsx(ActionList, { selectionVariant: "single", children:
|
|
1306
|
+
: 'Expand sharing details', children: isExpanded ? 'Shrink details' : 'Expand details' })] }), _jsx(ActionMenu.Overlay, { width: "small", children: _jsx(ActionList, { selectionVariant: "single", children: levels.map(({ level, label }) => (_jsx(ActionList.Item, { selected: selectedAccessLevel === level, onSelect: () => setSelectedAccessLevel(level), children: label }, level))) }) })] })] }), !isExpanded && (_jsxs(Box, { sx: {
|
|
1276
1307
|
px: 3,
|
|
1277
1308
|
py: 2,
|
|
1278
1309
|
borderRadius: 2,
|
|
@@ -1321,7 +1352,8 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
1321
1352
|
groupedShareable.self.length === 0 &&
|
|
1322
1353
|
groupedShareable.otherUsers.length === 0 &&
|
|
1323
1354
|
groupedShareable.orgs.length === 0 &&
|
|
1324
|
-
groupedShareable.teams.length === 0
|
|
1355
|
+
groupedShareable.teams.length === 0 &&
|
|
1356
|
+
groupedShareable.agents.length === 0 ? (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "No principals available to share with." })) : (_jsxs(Box, { sx: { display: 'grid', gap: 2 }, children: [renderShareableGroup('You', groupedShareable.self), renderShareableGroup('Other users', groupedShareable.otherUsers), renderShareableGroup('Your organizations', groupedShareable.orgs), renderShareableGroup('Your teams', groupedShareable.teams), renderShareableGroup('Agents', groupedShareable.agents)] }))] }), _jsxs(Box, { sx: {
|
|
1325
1357
|
px: 3,
|
|
1326
1358
|
py: 2,
|
|
1327
1359
|
borderRadius: 2,
|
|
@@ -1364,7 +1396,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
1364
1396
|
display: 'inline-flex',
|
|
1365
1397
|
alignItems: 'center',
|
|
1366
1398
|
gap: 2,
|
|
1367
|
-
}, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Searching\u2026" })] })) : searchResults.length === 0 ? (_jsx(Box, { sx: { px: 3, py: 2 }, children: _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "No principals found." }) })) : (_jsx(ActionList, { children: searchResults.map(result => (_jsxs(ActionList.Item, { onSelect: () => handleSearchResultSelect(result), children: [_jsx(ActionList.LeadingVisual, { children: _jsx(PrincipalAvatar, { kind: result.kind, avatarUrl: result.avatarUrl, alt: result.displayName, size: 18 }) }), _jsxs(Box, { sx: {
|
|
1399
|
+
}, children: [_jsx(Spinner, { size: "small" }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "Searching\u2026" })] })) : searchResults.length === 0 ? (_jsx(Box, { sx: { px: 3, py: 2 }, children: _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: "No principals found." }) })) : (_jsx(ActionList, { children: searchResults.map(result => (_jsxs(ActionList.Item, { onSelect: () => handleSearchResultSelect(result), children: [_jsx(ActionList.LeadingVisual, { children: result.kind === 'agent' ? (_jsx(AgentAvatar, { size: 18 })) : (_jsx(PrincipalAvatar, { kind: result.kind, avatarUrl: result.avatarUrl, alt: result.displayName, size: 18 })) }), _jsxs(Box, { sx: {
|
|
1368
1400
|
display: 'inline-flex',
|
|
1369
1401
|
alignItems: 'center',
|
|
1370
1402
|
gap: 1,
|
|
@@ -1406,7 +1438,7 @@ export function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLa
|
|
|
1406
1438
|
flexWrap: 'wrap',
|
|
1407
1439
|
gap: 1,
|
|
1408
1440
|
justifyContent: 'flex-end',
|
|
1409
|
-
}, children: entry.levels.map(level => (_jsx(Label, { size: "small", variant: "secondary", children:
|
|
1441
|
+
}, children: entry.levels.map(level => (_jsx(Label, { size: "small", variant: "secondary", children: levelLabels[level] || level }, level))) }), _jsx(Button, { size: "small", variant: "invisible", onClick: () => removePrincipal(entry.kind, entry.uid), disabled: isSaving, children: "Remove" })] }, principalKey(entry.kind, entry.uid)))) })) })] })] }))] }), _jsxs(Box, { sx: {
|
|
1410
1442
|
display: 'flex',
|
|
1411
1443
|
justifyContent: 'flex-end',
|
|
1412
1444
|
alignItems: 'center',
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Unlike `ShareAccessComponent` (which is bound to a server-side resource
|
|
6
6
|
* via `requestUrl`), this component edits a free-form
|
|
7
|
-
* `{ access: { view/update/execute: { userUids, teamUids, organizationUids
|
|
7
|
+
* `{ access: { view/update/execute: { userUids, teamUids, organizationUids,
|
|
8
|
+
* agentUids } } }`
|
|
8
9
|
* blob in memory. It is intended for "create" flows where the resource does
|
|
9
10
|
* not yet exist and the sharing payload must be POSTed alongside the rest of
|
|
10
11
|
* the configuration.
|
|
@@ -20,6 +21,9 @@ export type SharingLevelPayload = {
|
|
|
20
21
|
userUids?: string[];
|
|
21
22
|
teamUids?: string[];
|
|
22
23
|
organizationUids?: string[];
|
|
24
|
+
/** Service agents. A grant here is to that agent alone, matched on its own
|
|
25
|
+
* uid, never to the people who can act through it. */
|
|
26
|
+
agentUids?: string[];
|
|
23
27
|
};
|
|
24
28
|
export type SharingPayload = {
|
|
25
29
|
access?: Partial<Record<SharingAccessLevel, SharingLevelPayload>>;
|