@datalayer/core 1.1.66 → 1.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/README.md +41 -18
  2. package/lib/api/constants.d.ts +1 -1
  3. package/lib/api/constants.js +1 -1
  4. package/lib/api/contents/attachments.js +3 -7
  5. package/lib/api/contents/datasets.d.ts +48 -0
  6. package/lib/api/contents/datasets.js +44 -7
  7. package/lib/api/contents/runtimeMounts.js +1 -1
  8. package/lib/api/contents/sandboxUid.d.ts +13 -45
  9. package/lib/api/contents/sandboxUid.js +14 -65
  10. package/lib/api/evals/client.d.ts +402 -0
  11. package/lib/api/evals/client.js +359 -0
  12. package/lib/api/evals/index.d.ts +10 -0
  13. package/lib/api/evals/index.js +18 -0
  14. package/lib/api/evals/request.d.ts +43 -0
  15. package/lib/api/evals/request.js +67 -0
  16. package/lib/api/evals/status.d.ts +27 -0
  17. package/lib/api/evals/status.js +122 -0
  18. package/lib/api/evals/types.d.ts +1335 -0
  19. package/lib/api/evals/types.js +5 -0
  20. package/lib/api/iam/connectedAgents.d.ts +29 -0
  21. package/lib/api/iam/connectedAgents.js +35 -0
  22. package/lib/api/iam/identityProviders.d.ts +76 -0
  23. package/lib/api/iam/identityProviders.js +187 -0
  24. package/lib/api/iam/index.d.ts +1 -0
  25. package/lib/api/iam/index.js +1 -0
  26. package/lib/api/iam/mcpPolicy.d.ts +102 -1
  27. package/lib/api/iam/mcpPolicy.js +38 -2
  28. package/lib/api/iam/profile.d.ts +17 -1
  29. package/lib/api/iam/profile.js +27 -0
  30. package/lib/api/iam/scimTokens.d.ts +79 -0
  31. package/lib/api/iam/scimTokens.js +141 -0
  32. package/lib/api/iam/secrets.js +9 -21
  33. package/lib/api/iam/trials.d.ts +38 -0
  34. package/lib/api/iam/trials.js +66 -0
  35. package/lib/api/index.d.ts +4 -0
  36. package/lib/api/index.js +4 -0
  37. package/lib/api/mcp/observability.d.ts +25 -9
  38. package/lib/api/mcp/observability.js +63 -50
  39. package/lib/api/orchestration/client.d.ts +53 -0
  40. package/lib/api/orchestration/client.js +105 -0
  41. package/lib/api/orchestration/events.d.ts +88 -0
  42. package/lib/api/orchestration/events.js +245 -0
  43. package/lib/api/orchestration/generated.d.ts +693 -0
  44. package/lib/api/orchestration/generated.js +687 -0
  45. package/lib/api/orchestration/index.d.ts +30 -0
  46. package/lib/api/orchestration/index.js +34 -0
  47. package/lib/api/orchestration/lifecycle.d.ts +39 -0
  48. package/lib/api/orchestration/lifecycle.js +57 -0
  49. package/lib/api/orchestration/measures.d.ts +55 -0
  50. package/lib/api/orchestration/measures.js +99 -0
  51. package/lib/api/otel/dashboards.d.ts +56 -0
  52. package/lib/api/otel/dashboards.js +50 -0
  53. package/lib/api/otel/index.d.ts +1 -0
  54. package/lib/api/otel/index.js +1 -0
  55. package/lib/api/otel/metrics.d.ts +16 -0
  56. package/lib/api/otel/metrics.js +15 -0
  57. package/lib/api/scheduler/client.d.ts +32 -0
  58. package/lib/api/scheduler/client.js +42 -0
  59. package/lib/api/scheduler/index.d.ts +8 -0
  60. package/lib/api/scheduler/index.js +16 -0
  61. package/lib/api/scheduler/request.d.ts +28 -0
  62. package/lib/api/scheduler/request.js +50 -0
  63. package/lib/api/scheduler/types.d.ts +88 -0
  64. package/lib/api/scheduler/types.js +5 -0
  65. package/lib/api/spacer/comments.d.ts +97 -0
  66. package/lib/api/spacer/comments.js +45 -0
  67. package/lib/api/spacer/index.d.ts +9 -0
  68. package/lib/api/spacer/index.js +17 -0
  69. package/lib/api/spacer/notebooks.d.ts +33 -0
  70. package/lib/api/spacer/notebooks.js +39 -0
  71. package/lib/api/spacer/request.d.ts +25 -0
  72. package/lib/api/spacer/request.js +46 -0
  73. package/lib/api/spacer/spaces.d.ts +68 -0
  74. package/lib/api/spacer/spaces.js +45 -0
  75. package/lib/api/utils/validation.d.ts +4 -4
  76. package/lib/api/utils/validation.js +10 -7
  77. package/lib/client/constants.d.ts +1 -0
  78. package/lib/client/constants.js +1 -0
  79. package/lib/components/animation/AnimatedText.d.ts +1 -44
  80. package/lib/components/animation/AnimatedText.js +6 -122
  81. package/lib/components/anonymous/AnonymousKeyExpired.d.ts +56 -0
  82. package/lib/components/anonymous/AnonymousKeyExpired.js +96 -0
  83. package/lib/components/anonymous/AnonymousKeyTimer.d.ts +63 -0
  84. package/lib/components/anonymous/AnonymousKeyTimer.js +140 -0
  85. package/lib/components/anonymous/index.d.ts +7 -0
  86. package/lib/components/anonymous/index.js +15 -0
  87. package/lib/components/avatars/UserAvatar.d.ts +7 -1
  88. package/lib/components/avatars/UserAvatar.js +15 -1
  89. package/lib/components/billing/BillingEntitySelect.d.ts +6 -0
  90. package/lib/components/billing/BillingEntitySelect.js +49 -10
  91. package/lib/components/billing/eligibility.d.ts +22 -0
  92. package/lib/components/billing/eligibility.js +27 -0
  93. package/lib/components/billing/index.d.ts +1 -0
  94. package/lib/components/billing/index.js +1 -0
  95. package/lib/components/collaboration/LiveEditorCollaborators.d.ts +5 -0
  96. package/lib/components/collaboration/LiveEditorCollaborators.js +3 -1
  97. package/lib/components/display/DatalayerBox.d.ts +2 -3
  98. package/lib/components/display/DatalayerBox.js +1 -1
  99. package/lib/components/display/NavLink.js +3 -2
  100. package/lib/components/labels/StatusLabels.d.ts +2 -10
  101. package/lib/components/labels/StatusLabels.js +2 -26
  102. package/lib/components/principal/PrincipalAppearance.d.ts +21 -42
  103. package/lib/components/principal/PrincipalAppearance.js +232 -174
  104. package/lib/components/principal/PrincipalAvatar.d.ts +8 -1
  105. package/lib/components/principal/PrincipalAvatar.js +2 -2
  106. package/lib/components/principal/PrincipalDetailsOverlay.d.ts +8 -1
  107. package/lib/components/principal/PrincipalDetailsOverlay.js +2 -2
  108. package/lib/components/screencapture/Screencapture.js +46 -3
  109. package/lib/components/sharing/ShareAccessComponent.d.ts +45 -4
  110. package/lib/components/sharing/ShareAccessComponent.js +110 -78
  111. package/lib/components/sharing/SharingEditor.d.ts +5 -1
  112. package/lib/components/sharing/SharingEditor.js +9 -4
  113. package/lib/components/sharing/index.d.ts +1 -0
  114. package/lib/components/sharing/index.js +1 -0
  115. package/lib/components/sharing/sandboxSharing.d.ts +26 -0
  116. package/lib/components/sharing/sandboxSharing.js +41 -0
  117. package/lib/components/spaces/SpaceDetailsOverlay.d.ts +39 -0
  118. package/lib/components/spaces/SpaceDetailsOverlay.js +80 -0
  119. package/lib/components/spaces/SpaceDisplay.d.ts +38 -0
  120. package/lib/components/spaces/SpaceDisplay.js +92 -0
  121. package/lib/components/spaces/index.d.ts +4 -0
  122. package/lib/components/spaces/index.js +7 -0
  123. package/lib/components/spaces/spaceDisplayModel.d.ts +93 -0
  124. package/lib/components/spaces/spaceDisplayModel.js +170 -0
  125. package/lib/hooks/cacheConverters.d.ts +0 -7
  126. package/lib/hooks/cacheConverters.js +0 -25
  127. package/lib/hooks/index.d.ts +1 -0
  128. package/lib/hooks/index.js +1 -0
  129. package/lib/hooks/useBillingEntityStore.js +3 -0
  130. package/lib/hooks/useCache.d.ts +168 -25
  131. package/lib/hooks/useCache.js +1424 -307
  132. package/lib/hooks/useContents.d.ts +22 -1
  133. package/lib/hooks/useContents.js +90 -21
  134. package/lib/hooks/useMcp.d.ts +87 -1
  135. package/lib/hooks/useMcp.js +247 -12
  136. package/lib/hooks/useNavigate.d.ts +41 -3
  137. package/lib/hooks/useNavigate.js +106 -52
  138. package/lib/hooks/usePrincipalCacheStore.js +3 -0
  139. package/lib/hooks/usePrincipalStore.js +3 -0
  140. package/lib/hooks/useSpaceCacheStore.d.ts +50 -0
  141. package/lib/hooks/useSpaceCacheStore.js +85 -0
  142. package/lib/models/CreditsDTO.d.ts +6 -5
  143. package/lib/models/CreditsDTO.js +7 -5
  144. package/lib/models/McpBinding.d.ts +6 -0
  145. package/lib/models/Organization.d.ts +69 -0
  146. package/lib/models/Organization.js +96 -0
  147. package/lib/models/Secret.d.ts +1 -2
  148. package/lib/models/Secret.js +2 -18
  149. package/lib/models/StartedBy.d.ts +34 -0
  150. package/lib/models/StartedBy.js +36 -0
  151. package/lib/models/Team.d.ts +2 -0
  152. package/lib/models/Team.js +2 -0
  153. package/lib/models/User.d.ts +4 -0
  154. package/lib/models/User.js +3 -0
  155. package/lib/models/UserSettings.d.ts +13 -0
  156. package/lib/models/UserSettings.js +9 -0
  157. package/lib/models/contents/__fixtures__/v1-contracts.json +158 -30
  158. package/lib/navigation/components.js +2 -3
  159. package/lib/routes/publicPaths.js +4 -0
  160. package/lib/state/index.d.ts +1 -0
  161. package/lib/state/index.js +1 -0
  162. package/lib/state/sessionEnd.d.ts +55 -0
  163. package/lib/state/sessionEnd.js +162 -0
  164. package/lib/state/substates/CoreState.js +3 -3
  165. package/lib/state/substates/IAMState.js +7 -0
  166. package/lib/state/substates/LayoutState.js +12 -0
  167. package/lib/state/substates/ProfileState.d.ts +1 -0
  168. package/lib/state/substates/ProfileState.js +1 -0
  169. package/lib/utils/Lazy.d.ts +20 -0
  170. package/lib/utils/Lazy.js +32 -6
  171. package/lib/utils/Screencapture.js +3 -0
  172. package/lib/utils/WithSuspense.d.ts +11 -1
  173. package/lib/utils/WithSuspense.js +11 -1
  174. package/lib/views/mcp/AdmittedClients.d.ts +44 -0
  175. package/lib/views/mcp/AdmittedClients.js +59 -0
  176. package/lib/views/mcp/ApprovalQueue.d.ts +66 -0
  177. package/lib/views/mcp/ApprovalQueue.js +95 -0
  178. package/lib/views/mcp/ConnectedAgents.js +38 -3
  179. package/lib/views/mcp/EnterpriseConsole.d.ts +1 -1
  180. package/lib/views/mcp/EnterpriseConsole.js +23 -1
  181. package/lib/views/mcp/IdentityProviders.d.ts +33 -0
  182. package/lib/views/mcp/IdentityProviders.js +299 -0
  183. package/lib/views/mcp/McpDashboard.js +90 -7
  184. package/lib/views/mcp/McpObservability.d.ts +30 -1
  185. package/lib/views/mcp/McpObservability.js +105 -19
  186. package/lib/views/mcp/NotebookRuns.d.ts +39 -0
  187. package/lib/views/mcp/NotebookRuns.js +44 -0
  188. package/lib/views/mcp/OrganizationPolicy.js +2 -1
  189. package/lib/views/mcp/PersonalPolicy.js +2 -1
  190. package/lib/views/mcp/PolicyForm.d.ts +17 -1
  191. package/lib/views/mcp/PolicyForm.js +25 -3
  192. package/lib/views/mcp/PolicyHistory.d.ts +13 -0
  193. package/lib/views/mcp/PolicyHistory.js +14 -1
  194. package/lib/views/mcp/RunDetail.d.ts +87 -0
  195. package/lib/views/mcp/RunDetail.js +186 -0
  196. package/lib/views/mcp/ScimProvisioning.d.ts +54 -0
  197. package/lib/views/mcp/ScimProvisioning.js +173 -0
  198. package/lib/views/mcp/TeamPolicies.js +66 -5
  199. package/lib/views/mcp/ToolAccess.d.ts +60 -0
  200. package/lib/views/mcp/ToolAccess.js +101 -0
  201. package/lib/views/mcp/TraceTimeline.d.ts +81 -0
  202. package/lib/views/mcp/TraceTimeline.js +132 -0
  203. package/lib/views/mcp/index.d.ts +5 -0
  204. package/lib/views/mcp/index.js +5 -0
  205. package/lib/views/otel/simpleAuthStore.js +3 -0
  206. package/lib/views/secrets/SecretEdit.js +3 -2
  207. package/lib/views/secrets/SecretNew.js +5 -1
  208. package/package.json +269 -264
  209. package/scripts/generate-mcp-types.py +1 -1
  210. 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
- croppedCanvas.width = cropWidth;
135
- croppedCanvas.height = cropHeigth;
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, cropWidth * scale, cropHeigth * scale, 0, 0, cropWidth * scale, cropHeigth * 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
- type PrincipalKind = 'personal' | 'team' | 'organization';
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<ItemAccessLevel, SharingLevelPayload>>;
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?: ItemAccessLevel;
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
- export declare function ShareAccessComponent({ isOpen, requestUrl, transport, resourceLabel, resourceName, resourceDescription: _resourceDescription, expanded, onSharingAccessRestrictedChange, defaultAccessLevel, principalKinds, displayMode, onClose, }: ShareAccessComponentProps): JSX.Element | null;
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, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
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 ACCESS_LEVELS = ['view', 'update', 'execute'];
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
- view: { userUids: [], teamUids: [], organizationUids: [] },
218
- update: { userUids: [], teamUids: [], organizationUids: [] },
219
- execute: { userUids: [], teamUids: [], organizationUids: [] },
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
- : 'organizationUids';
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
- const next = {
250
- view: { ...state.view },
251
- update: { ...state.update },
252
- execute: { ...state.execute },
253
- };
254
- for (const level of ACCESS_LEVELS) {
255
- next[level][bucket] = next[level][bucket].filter(value => value.toLowerCase() !== lower);
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 ACCESS_LEVELS) {
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
- const view = access.view || {};
291
- const update = access.update || {};
292
- const execute = access.execute || {};
293
- return {
294
- view: {
295
- userUids: [...(view.userUids || [])],
296
- teamUids: [...(view.teamUids || [])],
297
- organizationUids: [...(view.organizationUids || [])],
298
- },
299
- update: {
300
- userUids: [...(update.userUids || [])],
301
- teamUids: [...(update.teamUids || [])],
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 [access, setAccess] = useState(emptyAccessByLevel());
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
- view: {
1021
- userUids: snapshot.view.userUids,
1022
- teamUids: snapshot.view.teamUids,
1023
- organizationUids: snapshot.view.organizationUids,
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
- update: {
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
- return { self, otherUsers, orgs, teams };
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
- : PeopleIcon;
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: ", ACCESS_LEVEL_LABELS[selectedAccessLevel]] }) }), _jsx(Button, { variant: "invisible", size: "small", leadingVisual: isExpanded ? ChevronUpIcon : ChevronDownIcon, onClick: () => setIsExpanded(previous => !previous), "aria-label": isExpanded
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: ACCESS_LEVELS.map(level => (_jsx(ActionList.Item, { selected: selectedAccessLevel === level, onSelect: () => setSelectedAccessLevel(level), children: ACCESS_LEVEL_LABELS[level] }, level))) }) })] })] }), !isExpanded && (_jsxs(Box, { sx: {
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 ? (_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)] }))] }), _jsxs(Box, { sx: {
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: ACCESS_LEVEL_LABELS[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: {
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>>;