@datalayer/core 1.2.19 → 1.2.20

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 (144) hide show
  1. package/lib/components/avatars/UserAvatar.d.ts +10 -11
  2. package/lib/components/avatars/UserAvatar.js +23 -28
  3. package/lib/components/avatars/UserProfileAvatar.js +1 -1
  4. package/lib/components/avatars/avatarChoice.d.ts +42 -0
  5. package/lib/components/avatars/avatarChoice.js +65 -0
  6. package/lib/components/avatars/index.d.ts +1 -0
  7. package/lib/components/avatars/index.js +1 -0
  8. package/lib/components/collaboration/LiveEditorCollaborators.d.ts +3 -4
  9. package/lib/components/collaboration/LiveEditorCollaborators.js +7 -5
  10. package/lib/components/emoji/faceEmojis.js +48 -0
  11. package/lib/components/emoji/fluent/loaders.js +46 -0
  12. package/lib/components/emoji/fluent/svg/1f30a.d.ts +2 -0
  13. package/lib/components/emoji/fluent/svg/1f30a.js +5 -0
  14. package/lib/components/emoji/fluent/svg/1f310.d.ts +2 -0
  15. package/lib/components/emoji/fluent/svg/1f310.js +5 -0
  16. package/lib/components/emoji/fluent/svg/1f324.d.ts +2 -0
  17. package/lib/components/emoji/fluent/svg/1f324.js +5 -0
  18. package/lib/components/emoji/fluent/svg/1f326.d.ts +2 -0
  19. package/lib/components/emoji/fluent/svg/1f326.js +5 -0
  20. package/lib/components/emoji/fluent/svg/1f327.d.ts +2 -0
  21. package/lib/components/emoji/fluent/svg/1f327.js +5 -0
  22. package/lib/components/emoji/fluent/svg/1f33e.d.ts +2 -0
  23. package/lib/components/emoji/fluent/svg/1f33e.js +5 -0
  24. package/lib/components/emoji/fluent/svg/1f372.d.ts +2 -0
  25. package/lib/components/emoji/fluent/svg/1f372.js +5 -0
  26. package/lib/components/emoji/fluent/svg/1f373.d.ts +2 -0
  27. package/lib/components/emoji/fluent/svg/1f373.js +5 -0
  28. package/lib/components/emoji/fluent/svg/1f39b.d.ts +2 -0
  29. package/lib/components/emoji/fluent/svg/1f39b.js +5 -0
  30. package/lib/components/emoji/fluent/svg/1f3ab.d.ts +2 -0
  31. package/lib/components/emoji/fluent/svg/1f3ab.js +5 -0
  32. package/lib/components/emoji/fluent/svg/1f41b.d.ts +2 -0
  33. package/lib/components/emoji/fluent/svg/1f41b.js +5 -0
  34. package/lib/components/emoji/fluent/svg/1f441.d.ts +2 -0
  35. package/lib/components/emoji/fluent/svg/1f441.js +5 -0
  36. package/lib/components/emoji/fluent/svg/1f465.d.ts +2 -0
  37. package/lib/components/emoji/fluent/svg/1f465.js +5 -0
  38. package/lib/components/emoji/fluent/svg/1f4b9.d.ts +2 -0
  39. package/lib/components/emoji/fluent/svg/1f4b9.js +5 -0
  40. package/lib/components/emoji/fluent/svg/1f4be.d.ts +2 -0
  41. package/lib/components/emoji/fluent/svg/1f4be.js +5 -0
  42. package/lib/components/emoji/fluent/svg/1f4c1.d.ts +2 -0
  43. package/lib/components/emoji/fluent/svg/1f4c1.js +5 -0
  44. package/lib/components/emoji/fluent/svg/1f4c2.d.ts +2 -0
  45. package/lib/components/emoji/fluent/svg/1f4c2.js +5 -0
  46. package/lib/components/emoji/fluent/svg/1f4c4.d.ts +2 -0
  47. package/lib/components/emoji/fluent/svg/1f4c4.js +5 -0
  48. package/lib/components/emoji/fluent/svg/1f4d3.d.ts +2 -0
  49. package/lib/components/emoji/fluent/svg/1f4d3.js +5 -0
  50. package/lib/components/emoji/fluent/svg/1f4d6.d.ts +2 -0
  51. package/lib/components/emoji/fluent/svg/1f4d6.js +5 -0
  52. package/lib/components/emoji/fluent/svg/1f4dc.d.ts +2 -0
  53. package/lib/components/emoji/fluent/svg/1f4dc.js +5 -0
  54. package/lib/components/emoji/fluent/svg/1f4e1.d.ts +2 -0
  55. package/lib/components/emoji/fluent/svg/1f4e1.js +5 -0
  56. package/lib/components/emoji/fluent/svg/1f4e2.d.ts +2 -0
  57. package/lib/components/emoji/fluent/svg/1f4e2.js +5 -0
  58. package/lib/components/emoji/fluent/svg/1f4e7.d.ts +2 -0
  59. package/lib/components/emoji/fluent/svg/1f4e7.js +5 -0
  60. package/lib/components/emoji/fluent/svg/1f500.d.ts +2 -0
  61. package/lib/components/emoji/fluent/svg/1f500.js +5 -0
  62. package/lib/components/emoji/fluent/svg/1f501.d.ts +2 -0
  63. package/lib/components/emoji/fluent/svg/1f501.js +5 -0
  64. package/lib/components/emoji/fluent/svg/1f504.d.ts +2 -0
  65. package/lib/components/emoji/fluent/svg/1f504.js +5 -0
  66. package/lib/components/emoji/fluent/svg/1f52d.d.ts +2 -0
  67. package/lib/components/emoji/fluent/svg/1f52d.js +5 -0
  68. package/lib/components/emoji/fluent/svg/1f552.d.ts +2 -0
  69. package/lib/components/emoji/fluent/svg/1f552.js +5 -0
  70. package/lib/components/emoji/fluent/svg/1f58b.d.ts +2 -0
  71. package/lib/components/emoji/fluent/svg/1f58b.js +5 -0
  72. package/lib/components/emoji/fluent/svg/1f5b2.d.ts +2 -0
  73. package/lib/components/emoji/fluent/svg/1f5b2.js +5 -0
  74. package/lib/components/emoji/fluent/svg/1f5c3.d.ts +2 -0
  75. package/lib/components/emoji/fluent/svg/1f5c3.js +5 -0
  76. package/lib/components/emoji/fluent/svg/1f5d1.d.ts +2 -0
  77. package/lib/components/emoji/fluent/svg/1f5d1.js +5 -0
  78. package/lib/components/emoji/fluent/svg/1f5dc.d.ts +2 -0
  79. package/lib/components/emoji/fluent/svg/1f5dc.js +5 -0
  80. package/lib/components/emoji/fluent/svg/1f604.d.ts +2 -0
  81. package/lib/components/emoji/fluent/svg/1f604.js +5 -0
  82. package/lib/components/emoji/fluent/svg/1f917.d.ts +2 -0
  83. package/lib/components/emoji/fluent/svg/1f917.js +5 -0
  84. package/lib/components/emoji/fluent/svg/1f9d1-200d-2696.d.ts +2 -0
  85. package/lib/components/emoji/fluent/svg/1f9d1-200d-2696.js +5 -0
  86. package/lib/components/emoji/fluent/svg/1fa79.d.ts +2 -0
  87. package/lib/components/emoji/fluent/svg/1fa79.js +5 -0
  88. package/lib/components/emoji/fluent/svg/1fa9d.d.ts +2 -0
  89. package/lib/components/emoji/fluent/svg/1fa9d.js +5 -0
  90. package/lib/components/emoji/fluent/svg/1fa9f.d.ts +2 -0
  91. package/lib/components/emoji/fluent/svg/1fa9f.js +5 -0
  92. package/lib/components/emoji/fluent/svg/23f3.d.ts +2 -0
  93. package/lib/components/emoji/fluent/svg/23f3.js +5 -0
  94. package/lib/components/emoji/fluent/svg/2611.d.ts +2 -0
  95. package/lib/components/emoji/fluent/svg/2611.js +5 -0
  96. package/lib/components/emoji/fluent/svg/2702.d.ts +2 -0
  97. package/lib/components/emoji/fluent/svg/2702.js +5 -0
  98. package/lib/components/emoji/fluent/svg/270f.d.ts +2 -0
  99. package/lib/components/emoji/fluent/svg/270f.js +5 -0
  100. package/lib/components/emoji/fluent/svg/2728.d.ts +2 -0
  101. package/lib/components/emoji/fluent/svg/2728.js +5 -0
  102. package/lib/components/emoji/fluent/svg/2b1c.d.ts +2 -0
  103. package/lib/components/emoji/fluent/svg/2b1c.js +5 -0
  104. package/lib/components/principal/Principal.js +1 -1
  105. package/lib/components/principal/PrincipalAppearance.d.ts +24 -1
  106. package/lib/components/principal/PrincipalAppearance.js +105 -34
  107. package/lib/components/principal/PrincipalAvatar.d.ts +5 -7
  108. package/lib/components/principal/PrincipalAvatar.js +12 -18
  109. package/lib/components/principal/PrincipalDetailsOverlay.d.ts +4 -7
  110. package/lib/components/principal/PrincipalDetailsOverlay.js +2 -2
  111. package/lib/components/principal/PrincipalSwitcherMenu.js +1 -1
  112. package/lib/hooks/unlinkIAMProvider.d.ts +22 -0
  113. package/lib/hooks/unlinkIAMProvider.js +24 -0
  114. package/lib/hooks/useCache.d.ts +8 -1
  115. package/lib/hooks/useCache.js +35 -4
  116. package/lib/hooks/useNavigate.js +8 -2
  117. package/lib/models/IAMProviderLinked.d.ts +9 -0
  118. package/lib/models/IAMProviderLinked.js +34 -5
  119. package/lib/models/McpTask.d.ts +18 -1
  120. package/lib/models/McpTask.js +15 -0
  121. package/lib/models/Profile.d.ts +2 -2
  122. package/lib/models/User.js +5 -12
  123. package/lib/models/UserOnboarding.d.ts +9 -0
  124. package/lib/models/UserOnboarding.js +33 -0
  125. package/lib/portable/index.d.ts +3 -2
  126. package/lib/portable/index.js +4 -2
  127. package/lib/portable/states.d.ts +39 -0
  128. package/lib/portable/states.js +71 -0
  129. package/lib/state/substates/NavigationState.d.ts +5 -3
  130. package/lib/state/substates/NavigationState.js +12 -3
  131. package/lib/views/mcp/AlertDestinations.js +2 -2
  132. package/lib/views/mcp/ApprovalQueue.js +2 -2
  133. package/lib/views/mcp/EnterpriseConsole.js +2 -2
  134. package/lib/views/mcp/McpDashboard.js +2 -2
  135. package/lib/views/mcp/McpHome.js +4 -4
  136. package/lib/views/mcp/McpObservability.js +5 -5
  137. package/lib/views/mcp/NotebookRuns.js +2 -2
  138. package/lib/views/mcp/OrganizationUsage.js +2 -2
  139. package/lib/views/mcp/Policies.js +2 -2
  140. package/lib/views/mcp/RunDetail.d.ts +1 -1
  141. package/lib/views/mcp/RunDetail.js +4 -1
  142. package/lib/views/mcp/ScimProvisioning.js +2 -2
  143. package/lib/views/mcp/ToolAccess.js +2 -2
  144. package/package.json +1 -1
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, useRef, useState } from 'react';
3
3
  import { ActionList, ActionMenu, Button, Heading, Label, Link, RelativeTime, Select, Spinner, Text, } from '@primer/react';
4
4
  import { Blankslate, DataTable, Dialog, Table, } from '@primer/react/experimental';
5
- import { Box } from '@datalayer/primer-addons';
5
+ import { Box, Card } from '@datalayer/primer-addons';
6
6
  import { ChecklistIcon, KebabHorizontalIcon, PlayIcon, PlugIcon, StackIcon, } from '@primer/octicons-react';
7
7
  import { ShareAccessDialog, sandboxSharingUrl } from '../../components/sharing/index.js';
8
8
  import { ClientBadge, McpErrorBlankslate } from '../../components/mcp/index.js';
@@ -54,7 +54,7 @@ const boundTo = (client) => {
54
54
  return '';
55
55
  };
56
56
  const countLook = (tone) => tone === 'danger' ? 'danger.fg' : 'fg.default';
57
- const Count = ({ label, value, tone = 'neutral', note, to, onOpen, }) => (_jsxs(Box, { p: 3, border: "1px solid", borderColor: "border.default", borderRadius: 2, bg: "canvas.default", minWidth: 0, children: [_jsx(Text, { sx: {
57
+ const Count = ({ label, value, tone = 'neutral', note, to, onOpen, }) => (_jsxs(Card, { border: true, shadow: "none", display: "block", p: 3, minWidth: 0, children: [_jsx(Text, { sx: {
58
58
  display: 'block',
59
59
  fontSize: 4,
60
60
  fontWeight: 'bold',
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useState } from 'react';
3
3
  import { AiAgentIcon } from '@datalayer/icons-react';
4
4
  import { Button, Heading, IconButton, Link, Text } from '@primer/react';
5
- import { Box } from '@datalayer/primer-addons';
5
+ import { Box, Card } from '@datalayer/primer-addons';
6
6
  import { CheckIcon, CopyIcon, KeyIcon, PulseIcon, RssIcon, ShieldCheckIcon, TelescopeIcon, ToolsIcon, } from '@primer/octicons-react';
7
7
  import { useConnectedAgents, useMcpActivity, useMcpMetrics, useTasks, } from '../../hooks/useMcp.js';
8
8
  import { useNavigate } from '../../hooks/index.js';
@@ -56,7 +56,7 @@ export const Copyable = ({ text }) => {
56
56
  } })] }));
57
57
  };
58
58
  /** One of the five summaries: a heading, what it holds, and the way in. */
59
- const Summary = ({ icon: Icon, title, children, action, to, onOpen, }) => (_jsxs(Box, { p: 3, border: "1px solid", borderColor: "border.default", borderRadius: 2, display: "grid", gap: 2, alignContent: "start", minWidth: 0, children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(Icon, { size: 16 }), to ? (_jsx(Link, { href: to, onClick: event => {
59
+ const Summary = ({ icon: Icon, title, children, action, to, onOpen, }) => (_jsxs(Card, { border: true, shadow: "none", p: 3, display: "grid", gap: 2, alignContent: "start", minWidth: 0, children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(Icon, { size: 16 }), to ? (_jsx(Link, { href: to, onClick: event => {
60
60
  // A modified click asks for a new tab; `href` is real, so let it.
61
61
  if (event.metaKey || event.ctrlKey || event.shiftKey) {
62
62
  return;
@@ -77,11 +77,11 @@ export const McpHome = ({ routes, clientDocsBase = '/docs/mcp-clients', showTitl
77
77
  const connected = agents.data ?? [];
78
78
  const runs = tasks.data?.items ?? [];
79
79
  const live = activity.data?.clients.length ?? 0;
80
- return (_jsxs(Box, { display: "grid", gap: 4, minWidth: 0, children: [showTitle && (_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "MCP" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "Connect your agents to your notebooks, data and sandboxes through the Model Context Protocol." })] })), showSetup && (_jsxs(_Fragment, { children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 3, flexWrap: "wrap", p: 3, borderRadius: 2, bg: "canvas.subtle", border: "1px solid", borderColor: "border.default", children: [_jsx(Text, { sx: { fontSize: 1 }, children: live > 0
80
+ return (_jsxs(Box, { display: "grid", gap: 4, minWidth: 0, children: [showTitle && (_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "MCP" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "Connect your agents to your notebooks, data and sandboxes through the Model Context Protocol." })] })), showSetup && (_jsxs(_Fragment, { children: [_jsxs(Card, { border: true, shadow: "none", variant: "subtle", flexDirection: "row", display: "flex", alignItems: "center", gap: 3, flexWrap: "wrap", p: 3, children: [_jsx(Text, { sx: { fontSize: 1 }, children: live > 0
81
81
  ? `${plural(live, 'client')} connected right now.`
82
82
  : 'No client is connected right now.' }), _jsx(Button, { size: "small", leadingVisual: PulseIcon, onClick: () => navigate(routes.dashboard), children: "What is going on" })] }), _jsxs(Box, { display: "grid", gap: 2, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2 }, children: "The endpoint" }), _jsx(Copyable, { text: endpoint || 'https://mcp.datalayer.run/mcp' }), _jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(KeyIcon, { size: 14 }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: signedIn
83
83
  ? 'You are signed in, so a client you set up from here authorizes through OAuth without a shared token.'
84
- : 'Sign in to authorize a client through OAuth; without it a client can only use a personal access token.' })] })] }), _jsxs(Box, { display: "grid", gap: 2, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2 }, children: "Set up a client" }), _jsx(Box, { display: "grid", gap: 3, gridTemplateColumns: ['1fr', 'repeat(2, 1fr)', 'repeat(3, 1fr)'], children: MCP_CLIENTS.map(client => (_jsxs(Box, { p: 3, border: "1px solid", borderColor: "border.default", borderRadius: 2, display: "grid", gap: 2, minWidth: 0, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: client.name }), _jsx(Copyable, { text: mcpSetupCommand(client.setup) }), _jsx(Link, { href: `${clientDocsBase}/${client.setup}`, sx: { fontSize: 0, cursor: 'pointer', textAlign: 'left' }, onClick: event => {
84
+ : 'Sign in to authorize a client through OAuth; without it a client can only use a personal access token.' })] })] }), _jsxs(Box, { display: "grid", gap: 2, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2 }, children: "Set up a client" }), _jsx(Box, { display: "grid", gap: 3, gridTemplateColumns: ['1fr', 'repeat(2, 1fr)', 'repeat(3, 1fr)'], children: MCP_CLIENTS.map(client => (_jsxs(Card, { border: true, shadow: "none", p: 3, display: "grid", gap: 2, minWidth: 0, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: client.name }), _jsx(Copyable, { text: mcpSetupCommand(client.setup) }), _jsx(Link, { href: `${clientDocsBase}/${client.setup}`, sx: { fontSize: 0, cursor: 'pointer', textAlign: 'left' }, onClick: event => {
85
85
  // A modified click is the reader asking for a new tab or
86
86
  // window, and `href` is real so it still leads to the
87
87
  // full page — for that, for the status bar and for the
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useState } from 'react';
3
3
  import { Button, Heading, Label, SegmentedControl, Spinner, Text, TextInput, } from '@primer/react';
4
4
  import { Blankslate } from '@primer/react/experimental';
5
- import { Box } from '@datalayer/primer-addons';
5
+ import { Box, Card } from '@datalayer/primer-addons';
6
6
  import { SearchIcon, TelescopeIcon } from '@primer/octicons-react';
7
7
  import { McpErrorBlankslate } from '../../components/mcp/index.js';
8
8
  import { useMcpMetrics, useMcpTrace, useMcpWorkflowsHealth, useRunTrace, useTasks, } from '../../hooks/useMcp.js';
@@ -60,7 +60,7 @@ const SpanRow = ({ node, depth, }) => {
60
60
  }, children: durationLabel(node.span.duration_ms) })] }), node.children.map(child => (_jsx(SpanRow, { node: child, depth: depth + 1 }, child.span.span_id)))] }));
61
61
  };
62
62
  /** A number the reader can act on, or a plain statement that it is not measured. */
63
- const Sli = ({ label, value, note, }) => (_jsxs(Box, { p: 3, border: "1px solid", borderColor: "border.default", borderRadius: 2, minWidth: 0, children: [_jsx(Text, { sx: { display: 'block', fontSize: 3, fontWeight: 'bold' }, children: value }), _jsx(Text, { sx: { display: 'block', fontSize: 0, color: 'fg.muted' }, children: label }), note && (_jsx(Text, { sx: { display: 'block', fontSize: 0, color: 'fg.subtle' }, children: note }))] }));
63
+ const Sli = ({ label, value, note, }) => (_jsxs(Card, { border: true, shadow: "none", display: "block", p: 3, minWidth: 0, children: [_jsx(Text, { sx: { display: 'block', fontSize: 3, fontWeight: 'bold' }, children: value }), _jsx(Text, { sx: { display: 'block', fontSize: 0, color: 'fg.muted' }, children: label }), note && (_jsx(Text, { sx: { display: 'block', fontSize: 0, color: 'fg.subtle' }, children: note }))] }));
64
64
  /**
65
65
  * What the durable engine's own report amounts to, in one line.
66
66
  *
@@ -131,10 +131,10 @@ export const McpObservability = ({ errorState, routes, pane, onPaneChange, taskU
131
131
  onSelect(/^[0-9a-f]{32}$/i.test(value)
132
132
  ? { trace: value }
133
133
  : { task: value });
134
- }, children: "Show the run" })] }), !taskUid && !traceId ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(TelescopeIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "Pick a run" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Open a call from the audit log or the dashboard, or paste its task uid or trace id here, and its spans across the gateway, the policy check and the worker appear with the time each took." }) }), _jsx(Button, { size: "small", onClick: () => navigate(routes.audit), children: "Open the audit log" })] })) : run.isError ? (_jsx(McpErrorBlankslate, { state: errorState(run.error, 'This run'), onRetry: () => run.refetch() })) : run.isPending ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : (run.data?.spans.length ?? 0) === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(TelescopeIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No span for this call" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Spans reach the collector a few seconds after the call and are kept for a short time. A call older than the retention window has an audit row but no trace." }) })] })) : (_jsxs(Box, { display: "grid", gap: 2, children: [_jsxs(Box, { display: "flex", gap: 3, alignItems: "center", flexWrap: "wrap", children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', fontFamily: 'mono' }, children: run.data?.traceId }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [run.data?.spans.length, " spans"] }), _jsx(Button, { size: "small", onClick: () => navigate(`${routes.audit}?trace=${encodeURIComponent(run.data?.traceId ?? '')}`), children: "The audit row" })] }), _jsx(TraceTimeline, { tree: run.data?.tree ?? [] }), _jsx(Box, { border: "1px solid", borderColor: "border.default", borderRadius: 2, overflowX: "auto", children: (run.data?.tree ?? []).map(node => (_jsx(SpanRow, { node: node, depth: 0 }, node.span.span_id))) })] }))] })), pane === 'live' && (_jsxs(Box, { display: "grid", gap: 3, children: [(() => {
134
+ }, children: "Show the run" })] }), !taskUid && !traceId ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(TelescopeIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "Pick a run" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Open a call from the audit log or the dashboard, or paste its task uid or trace id here, and its spans across the gateway, the policy check and the worker appear with the time each took." }) }), _jsx(Button, { size: "small", onClick: () => navigate(routes.audit), children: "Open the audit log" })] })) : run.isError ? (_jsx(McpErrorBlankslate, { state: errorState(run.error, 'This run'), onRetry: () => run.refetch() })) : run.isPending ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : (run.data?.spans.length ?? 0) === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(TelescopeIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No span for this call" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Spans reach the collector a few seconds after the call and are kept for a short time. A call older than the retention window has an audit row but no trace." }) })] })) : (_jsxs(Box, { display: "grid", gap: 2, children: [_jsxs(Box, { display: "flex", gap: 3, alignItems: "center", flexWrap: "wrap", children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', fontFamily: 'mono' }, children: run.data?.traceId }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: [run.data?.spans.length, " spans"] }), _jsx(Button, { size: "small", onClick: () => navigate(`${routes.audit}?trace=${encodeURIComponent(run.data?.traceId ?? '')}`), children: "The audit row" })] }), _jsx(TraceTimeline, { tree: run.data?.tree ?? [] }), _jsx(Card, { border: true, shadow: "none", display: "block", overflowX: "auto", children: (run.data?.tree ?? []).map(node => (_jsx(SpanRow, { node: node, depth: 0 }, node.span.span_id))) })] }))] })), pane === 'live' && (_jsxs(Box, { display: "grid", gap: 3, children: [(() => {
135
135
  const look = engineLook(engine.data, engine.isError);
136
136
  const queues = engine.data?.queues ?? [];
137
- return (_jsxs(Box, { border: "1px solid", borderColor: "border.default", borderRadius: 2, p: 3, display: "grid", gap: 2, children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "The durable engine" }), _jsx(Label, { size: "small", variant: look.variant, children: look.label }), engine.data?.engine && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: engine.data.engine }))] }), look.note && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: look.note })), queues.length > 0 && (_jsx(Box, { display: "grid", gap: 1, children: queues.map(queue => (_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", fontSize: 0, children: [_jsx(Text, { sx: { fontFamily: 'mono' }, children: queue.name }), _jsxs(Text, { sx: { color: 'fg.muted' }, children: [queue.backlog, " waiting"] }), typeof queue.oldestWaitSeconds === 'number' && (_jsxs(Text, { sx: { color: 'fg.muted' }, children: ["oldest", ' ', durationLabel(queue.oldestWaitSeconds * 1000)] }))] }, queue.name))) }))] }));
137
+ return (_jsxs(Card, { border: true, shadow: "none", p: 3, display: "grid", gap: 2, children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "The durable engine" }), _jsx(Label, { size: "small", variant: look.variant, children: look.label }), engine.data?.engine && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: engine.data.engine }))] }), look.note && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: look.note })), queues.length > 0 && (_jsx(Box, { display: "grid", gap: 1, children: queues.map(queue => (_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", fontSize: 0, children: [_jsx(Text, { sx: { fontFamily: 'mono' }, children: queue.name }), _jsxs(Text, { sx: { color: 'fg.muted' }, children: [queue.backlog, " waiting"] }), typeof queue.oldestWaitSeconds === 'number' && (_jsxs(Text, { sx: { color: 'fg.muted' }, children: ["oldest", ' ', durationLabel(queue.oldestWaitSeconds * 1000)] }))] }, queue.name))) }))] }));
138
138
  })(), _jsxs(Box, { display: "grid", gap: 2, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "Running now" }), live.isError ? (_jsx(McpErrorBlankslate, { state: errorState(live.error, 'The running calls'), onRetry: () => live.refetch() })) : live.isPending ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 4, children: _jsx(Spinner, {}) })) : (live.data?.items.length ?? 0) === 0 ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Nothing of yours is running. A call that finishes inside its own request never appears here \u2014 it is over before this pane could draw it \u2014 and is found by its trace in Runs." })) : ((live.data?.items ?? []).map(task => (_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", py: 1, borderBottom: "1px solid", borderColor: "border.muted", children: [_jsx(Label, { size: "small", variant: "success", children: "Working" }), _jsx(Text, { sx: { fontSize: 0 }, children: task.tool || 'Run' }), _jsx(Text, { sx: {
139
139
  fontSize: 0,
140
140
  fontFamily: 'mono',
@@ -151,7 +151,7 @@ export const McpObservability = ({ errorState, routes, pane, onPaneChange, taskU
151
151
  ? 'Not measured'
152
152
  : Object.entries(metrics.data?.slis.p95SandboxLaunchSeconds ?? {})
153
153
  .map(([provider, seconds]) => `${provider} ${seconds.toFixed(1)}s`)
154
- .join(' · '), note: `${metrics.data?.slis.samples.launches ?? 0} launches` })] }), _jsx(Box, { border: "1px solid", borderColor: "border.default", borderRadius: 2, overflowX: "auto", children: MCP_METRIC_CATALOG.map(name => {
154
+ .join(' · '), note: `${metrics.data?.slis.samples.launches ?? 0} launches` })] }), _jsx(Card, { border: true, shadow: "none", display: "block", overflowX: "auto", children: MCP_METRIC_CATALOG.map(name => {
155
155
  const reporting = metrics.data?.reporting.includes(name) ?? false;
156
156
  return (_jsxs(Box, { display: "flex", alignItems: "center", gap: 3, py: 1, px: 2, borderBottom: "1px solid", borderColor: "border.muted", children: [_jsx(Text, { sx: { fontSize: 0, fontFamily: 'mono', flex: 1 }, children: name }), _jsx(Text, { sx: {
157
157
  fontSize: 0,
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Heading, Label, Link, RelativeTime, Spinner, Text, } from '@primer/react';
3
- import { Box } from '@datalayer/primer-addons';
3
+ import { Box, Card } from '@datalayer/primer-addons';
4
4
  import { useNotebookTasks } from '../../hooks/useMcp.js';
5
5
  import { RUN_STATUS_LOOK, isRunOver } from './RunDetail.js';
6
6
  /**
@@ -29,7 +29,7 @@ export const NotebookRuns = ({ notebookUid, routes, limit = 20, }) => {
29
29
  }
30
30
  return (_jsxs(Box, { display: "grid", gap: 2, minWidth: 0, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "Runs" }), tasks.length === 0 ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Nothing has run on this notebook yet. A tool call that outlives its request appears here while it runs." })) : (tasks.map(task => {
31
31
  const look = RUN_STATUS_LOOK[task.status];
32
- return (_jsxs(Box, { display: "grid", gap: 1, p: 2, borderRadius: 2, border: "1px solid", borderColor: task.status === 'input_required'
32
+ return (_jsxs(Card, { border: true, shadow: "none", display: "grid", gap: 1, p: 2, borderColor: task.status === 'input_required'
33
33
  ? 'attention.emphasis'
34
34
  : 'border.default', children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", children: [_jsx(Label, { size: "small", variant: look.variant, children: look.label }), _jsx(Text, { sx: { fontSize: 0 }, children: task.tool || 'Run' })] }), _jsxs(Box, { display: "flex", gap: 2, alignItems: "center", children: [_jsxs(Link, { href: `${routes.runs}/${encodeURIComponent(task.uid)}`, sx: { fontFamily: 'mono', fontSize: 0 }, children: [task.uid.slice(0, 16), "\u2026"] }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: _jsx(RelativeTime, { datetime: task.lastUpdatedAt }) })] })] }, task.uid));
35
35
  }))] }));
@@ -2,7 +2,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
2
2
  import { useMemo } from 'react';
3
3
  import { Heading, Label, ProgressBar, Spinner, Text } from '@primer/react';
4
4
  import { Blankslate, DataTable, Table } from '@primer/react/experimental';
5
- import { Box } from '@datalayer/primer-addons';
5
+ import { Box, Card } from '@datalayer/primer-addons';
6
6
  import { GraphIcon } from '@primer/octicons-react';
7
7
  import { ClientBadge, McpErrorBlankslate } from '../../components/mcp/index.js';
8
8
  import { useOrgMcpUsage } from '../../hooks/useMcp.js';
@@ -69,7 +69,7 @@ const QuotaCard = ({ label, hint, quota, }) => {
69
69
  const limit = quota?.limit;
70
70
  const used = quota?.used;
71
71
  const fraction = quota?.fraction;
72
- return (_jsxs(Box, { border: "1px solid", borderColor: "border.default", borderRadius: 2, p: 3, flex: "1 1 220px", minWidth: 0, children: [_jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: label }), _jsx(Box, { mt: 2, display: "flex", alignItems: "baseline", gap: 2, children: quota?.unknown ? (_jsx(Text, { sx: { fontSize: 2, color: 'fg.muted' }, children: "Not available" })) : (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 4, fontWeight: 'bold' }, children: typeof used === 'number' ? amount(used) : '—' }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: typeof limit === 'number'
72
+ return (_jsxs(Card, { border: true, shadow: "none", display: "block", p: 3, flex: "1 1 220px", minWidth: 0, children: [_jsx(Text, { sx: { fontWeight: 'bold', fontSize: 1 }, children: label }), _jsx(Box, { mt: 2, display: "flex", alignItems: "baseline", gap: 2, children: quota?.unknown ? (_jsx(Text, { sx: { fontSize: 2, color: 'fg.muted' }, children: "Not available" })) : (_jsxs(_Fragment, { children: [_jsx(Text, { sx: { fontSize: 4, fontWeight: 'bold' }, children: typeof used === 'number' ? amount(used) : '—' }), _jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: typeof limit === 'number'
73
73
  ? `of ${amount(limit)}`
74
74
  : 'no limit set' })] })) }), typeof fraction === 'number' && (_jsx(Box, { mt: 2, children: _jsx(ProgressBar, { progress: Math.min(100, fraction * 100), barSize: "small", bg: `${quotaTone(fraction)}.emphasis`, "aria-label": `${label}: ${Math.round(fraction * 100)}% of the limit` }) })), _jsx(Text, { as: "p", sx: { mt: 2, mb: 0, fontSize: 0, color: 'fg.muted' }, children: quota?.unknown ? quota.unknown : hint })] }));
75
75
  };
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useMemo, useState } from 'react';
3
3
  import { Heading, Label, Link, Select, Spinner, Text } from '@primer/react';
4
4
  import { Blankslate, Table } from '@primer/react/experimental';
5
- import { Box } from '@datalayer/primer-addons';
5
+ import { Box, Card } from '@datalayer/primer-addons';
6
6
  import { ShieldCheckIcon } from '@primer/octicons-react';
7
7
  import { McpErrorBlankslate } from '../../components/mcp/index.js';
8
8
  import { useConnectedAgents, useEffectivePolicy } from '../../hooks/useMcp.js';
@@ -164,6 +164,6 @@ export const Policies = ({ errorState, routes, organizationName, showTitle = tru
164
164
  color: 'fg.muted',
165
165
  display: 'block',
166
166
  mt: 1,
167
- }, children: row.rule.reason }))] })] }, row.name))) })] })] }), _jsxs(Box, { display: "grid", gap: 3, children: [_jsx(ToolGroup, { title: "Read-only tools", description: "Tools that only look: listing, reading a cell, reading a source.", tools: readOnlyTools, organizationName: organizationName }), _jsx(ToolGroup, { title: "Tools that change things", description: "Tools that write to a notebook, a document or a source.", tools: writeTools, organizationName: organizationName }), _jsx(ToolGroup, { title: "Tools that launch or spend", description: "Tools that execute code, launch a sandbox or reserve compute.", tools: executeTools, organizationName: organizationName })] }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Your token carries ", policy.data?.scopes.length ?? 0, " scopes, which is the ceiling over every rule above:", ' ', (policy.data?.scopes ?? []).join(', ') || 'none', "."] })] })), _jsxs(Box, { p: 3, border: "1px solid", borderColor: "border.default", borderRadius: 2, bg: "canvas.subtle", display: "grid", gap: 1, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: "Your own rules" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Narrowing the defaults for your own agents \u2014 approval by tool, a daily credits cap, a denylist, the environments they may use \u2014 is edited here once the policy layers ship. When your agents act inside an organization, that organization's policy applies instead of yours." }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold', mt: 2 }, children: "Organizations you own" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "The policy form for each organization you own, with its history and a preview of what one agent would get, is the same form the organization's MCP tab carries. It joins this page with the layers." })] })] }));
167
+ }, children: row.rule.reason }))] })] }, row.name))) })] })] }), _jsxs(Box, { display: "grid", gap: 3, children: [_jsx(ToolGroup, { title: "Read-only tools", description: "Tools that only look: listing, reading a cell, reading a source.", tools: readOnlyTools, organizationName: organizationName }), _jsx(ToolGroup, { title: "Tools that change things", description: "Tools that write to a notebook, a document or a source.", tools: writeTools, organizationName: organizationName }), _jsx(ToolGroup, { title: "Tools that launch or spend", description: "Tools that execute code, launch a sandbox or reserve compute.", tools: executeTools, organizationName: organizationName })] }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Your token carries ", policy.data?.scopes.length ?? 0, " scopes, which is the ceiling over every rule above:", ' ', (policy.data?.scopes ?? []).join(', ') || 'none', "."] })] })), _jsxs(Card, { border: true, shadow: "none", variant: "subtle", p: 3, display: "grid", gap: 1, children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: "Your own rules" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Narrowing the defaults for your own agents \u2014 approval by tool, a daily credits cap, a denylist, the environments they may use \u2014 is edited here once the policy layers ship. When your agents act inside an organization, that organization's policy applies instead of yours." }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold', mt: 2 }, children: "Organizations you own" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "The policy form for each organization you own, with its history and a preview of what one agent would get, is the same form the organization's MCP tab carries. It joins this page with the layers." })] })] }));
168
168
  };
169
169
  export default Policies;
@@ -26,7 +26,7 @@
26
26
  * @module views/mcp/RunDetail
27
27
  */
28
28
  import type { JSX } from 'react';
29
- import type { McpTask, McpTaskStatus } from '../../models/McpTask';
29
+ import { type McpTask, type McpTaskStatus } from '../../models/McpTask';
30
30
  import type { McpSpanNode } from '../../api/mcp/observability';
31
31
  import { type McpErrorStateFn, type McpRoutes } from './types';
32
32
  /** How a run's status is drawn. Shared with the runs list. */
@@ -6,6 +6,7 @@ import { useNavigate } from 'react-router-dom';
6
6
  import { McpErrorBlankslate } from '../../components/mcp/index.js';
7
7
  import { useAnswerTask, useCancelTask, useRunTrace, useTask, useTaskEvents, } from '../../hooks/useMcp.js';
8
8
  import { TraceTimelineSection } from './TraceTimeline.js';
9
+ import { taskFailureOf, } from '../../models/McpTask.js';
9
10
  /** How a run's status is drawn. Shared with the runs list. */
10
11
  export const RUN_STATUS_LOOK = {
11
12
  working: { label: 'Working', variant: 'success' },
@@ -151,6 +152,8 @@ export const RunDetail = ({ taskUid, errorState, routes, mock = false, }) => {
151
152
  return (_jsx(Box, { display: "flex", justifyContent: "center", p: 4, children: _jsx(Spinner, {}) }));
152
153
  }
153
154
  const task = mock ? SAMPLE_RUN : run.data;
155
+ // An empty object is no failure: the server sends `{}` while nothing failed.
156
+ const failure = taskFailureOf(task.error);
154
157
  const look = RUN_STATUS_LOOK[task.status];
155
158
  const over = isRunOver(task.status);
156
159
  const output = outputTextOf(task);
@@ -159,6 +162,6 @@ export const RunDetail = ({ taskUid, errorState, routes, mock = false, }) => {
159
162
  navigate(routes.runs);
160
163
  }, sx: { fontSize: 0 }, children: "All runs" }), _jsx(Heading, { as: "h2", sx: { fontSize: 3, mt: 1, mb: 1 }, children: task.tool || 'Run' }), _jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(Label, { size: "small", variant: look.variant, children: look.label }), _jsx(Text, { sx: { fontFamily: 'mono', fontSize: 0, color: 'fg.muted' }, children: task.uid }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["updated ", _jsx(RelativeTime, { datetime: task.lastUpdatedAt })] })] }), task.statusMessage && (_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', mt: 2 }, children: task.statusMessage }))] }), task.status === 'input_required' && (_jsxs(Box, { borderWidth: 1, borderStyle: "solid", borderColor: "attention.emphasis", borderRadius: 2, p: 3, display: "grid", gap: 2, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: "This run is waiting on you" }), _jsx(Textarea, { "aria-label": "Your answer", value: reply, onChange: event => setReply(event.target.value), placeholder: "Your answer", rows: 3 }), _jsx(Box, { children: _jsx(Button, { variant: "primary", disabled: !reply.trim() || answer.isPending, onClick: () => answer.mutate({ taskUid: task.uid, input: { answer: reply } }, { onSuccess: () => setReply('') }), children: answer.isPending ? 'Answering…' : 'Answer' }) })] })), _jsxs(Box, { children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1, mb: 2 }, children: "Output" }), output ? (_jsx(Box, { as: "pre", fontFamily: "mono", fontSize: 0, whiteSpace: "pre-wrap", overflowX: "auto", bg: "canvas.subtle", borderRadius: 2, p: 3, m: 0, children: output })) : (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: over
161
164
  ? 'This run printed nothing.'
162
- : 'Nothing printed yet. Output appears here as it arrives.' }))] }), task.error && (_jsxs(Box, { children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1, mb: 2 }, children: "Why it failed" }), _jsx(Text, { sx: { fontFamily: 'mono', fontSize: 0, color: 'danger.fg' }, children: task.error })] })), _jsx(TraceTimelineSection, { tree: mock ? SAMPLE_TRACE : (trace.data?.tree ?? []), traceId: mock ? SAMPLE_TRACE[0].span.trace_id : trace.data?.traceId, live: !over }), !over && (_jsxs(Box, { children: [_jsx(Button, { variant: "danger", disabled: cancel.isPending, onClick: () => cancel.mutate(task.uid), children: cancel.isPending ? 'Cancelling…' : 'Cancel this run' }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 2 }, children: "Cancelling interrupts the work itself, so the sandbox stops being billed for it. What it has already printed is kept." })] }))] }));
165
+ : 'Nothing printed yet. Output appears here as it arrives.' }))] }), failure && (_jsxs(Box, { children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1, mb: 2 }, children: "Why it failed" }), _jsx(Text, { sx: { fontFamily: 'mono', fontSize: 0, color: 'danger.fg' }, children: failure })] })), _jsx(TraceTimelineSection, { tree: mock ? SAMPLE_TRACE : (trace.data?.tree ?? []), traceId: mock ? SAMPLE_TRACE[0].span.trace_id : trace.data?.traceId, live: !over }), !over && (_jsxs(Box, { children: [_jsx(Button, { variant: "danger", disabled: cancel.isPending, onClick: () => cancel.mutate(task.uid), children: cancel.isPending ? 'Cancelling…' : 'Cancel this run' }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 2 }, children: "Cancelling interrupts the work itself, so the sandbox stops being billed for it. What it has already printed is kept." })] }))] }));
163
166
  };
164
167
  export default RunDetail;
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useMemo, useRef, useState } from 'react';
3
3
  import { ActionList, ActionMenu, Button, Flash, FormControl, Heading, IconButton, Label, Spinner, Text, TextInput, } from '@primer/react';
4
4
  import { Blankslate, DataTable, Dialog, Table, } from '@primer/react/experimental';
5
- import { Box } from '@datalayer/primer-addons';
5
+ import { Box, Card } from '@datalayer/primer-addons';
6
6
  import { KebabHorizontalIcon, PeopleIcon } from '@primer/octicons-react';
7
7
  import { McpErrorBlankslate } from '../../components/mcp/index.js';
8
8
  import { useCoreStore } from '../../state/index.js';
@@ -142,7 +142,7 @@ export const ScimProvisioning = ({ errorState, orgUid, readOnly = false, showTit
142
142
  return (_jsx(McpErrorBlankslate, { state: errorState(tokens.error, 'SCIM provisioning'), onRetry: () => tokens.refetch() }));
143
143
  }
144
144
  const shown = SCIM_STATUS_MESSAGES[status.state];
145
- return (_jsxs(Box, { display: "grid", gap: 3, minWidth: 0, children: [showTitle && (_jsxs(Box, { display: "flex", alignItems: "start", justifyContent: "space-between", gap: 3, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Directory provisioning" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "Over SCIM. Sign-in can only act on somebody who turns up; this is what removes the person who does not." })] }), !readOnly && (_jsx(Button, { variant: "primary", ref: returnFocusRef, onClick: openCreate, children: "New SCIM token" }))] })), tokens.isPending && !tokens.data ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : (_jsxs(_Fragment, { children: [_jsxs(Flash, { variant: shown.variant, children: [_jsx(Text, { as: "p", sx: { fontWeight: 'semibold', m: 0 }, children: shown.heading }), _jsx(Text, { as: "p", sx: { fontSize: 1, mt: 1, mb: 0 }, children: shown.body }), status.lastUsedAt && (_jsxs(Text, { as: "p", sx: { fontSize: 1, mt: 1, mb: 0, color: 'fg.muted' }, children: ["Last provisioning call ", timeAgo(status.lastUsedAt), "."] }))] }), rows.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h3", id: "scim-tokens", children: "SCIM tokens" }), _jsx(Table.Subtitle, { as: "p", id: "scim-tokens-subtitle", children: "A revoked token is kept rather than deleted, so the provisioning it did stays attributable." }), _jsx(DataTable, { "aria-labelledby": "scim-tokens", "aria-describedby": "scim-tokens-subtitle", data: rows, columns: columns })] }), _jsxs(Box, { border: "1px solid", borderColor: "border.default", borderRadius: 2, p: 3, display: "grid", gap: 2, children: [_jsx(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: "What to give the directory" }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "SCIM base URL" }), _jsx(TextInput, { block: true, readOnly: true, value: scimBaseUrl(iamUrl), "aria-describedby": "scim-base-url-note" }), _jsxs(FormControl.Caption, { id: "scim-base-url-note", children: ["Okta and Entra append ", _jsx("code", { children: "/Users" }), " themselves. Use the token as a bearer credential; the token is what says which organization is being provisioned, so nothing else names this one."] })] }), _jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', m: 0 }, children: ["Groups are not provisioned over SCIM \u2014 this server answers them ", _jsx("code", { children: "501" }), " saying so. Roles come from the sign-in token\u2019s groups claim and the provider\u2019s role mappings, above; a second source of the same fact would eventually disagree with the first."] })] })] })) : (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(PeopleIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No SCIM token" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Issue one to let this organization\u2019s directory add people when they join and \u2014 the part sign-in cannot do \u2014 remove them when they leave." }) }), !readOnly && (_jsx(Button, { size: "small", onClick: openCreate, children: "New SCIM token" }))] }))] })), creating && (_jsx(Dialog, { title: "New SCIM token", onClose: () => setCreating(false), returnFocusRef: returnFocusRef, footerButtons: [
145
+ return (_jsxs(Box, { display: "grid", gap: 3, minWidth: 0, children: [showTitle && (_jsxs(Box, { display: "flex", alignItems: "start", justifyContent: "space-between", gap: 3, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Directory provisioning" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "Over SCIM. Sign-in can only act on somebody who turns up; this is what removes the person who does not." })] }), !readOnly && (_jsx(Button, { variant: "primary", ref: returnFocusRef, onClick: openCreate, children: "New SCIM token" }))] })), tokens.isPending && !tokens.data ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : (_jsxs(_Fragment, { children: [_jsxs(Flash, { variant: shown.variant, children: [_jsx(Text, { as: "p", sx: { fontWeight: 'semibold', m: 0 }, children: shown.heading }), _jsx(Text, { as: "p", sx: { fontSize: 1, mt: 1, mb: 0 }, children: shown.body }), status.lastUsedAt && (_jsxs(Text, { as: "p", sx: { fontSize: 1, mt: 1, mb: 0, color: 'fg.muted' }, children: ["Last provisioning call ", timeAgo(status.lastUsedAt), "."] }))] }), rows.length > 0 ? (_jsxs(_Fragment, { children: [_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h3", id: "scim-tokens", children: "SCIM tokens" }), _jsx(Table.Subtitle, { as: "p", id: "scim-tokens-subtitle", children: "A revoked token is kept rather than deleted, so the provisioning it did stays attributable." }), _jsx(DataTable, { "aria-labelledby": "scim-tokens", "aria-describedby": "scim-tokens-subtitle", data: rows, columns: columns })] }), _jsxs(Card, { border: true, shadow: "none", p: 3, display: "grid", gap: 2, children: [_jsx(Text, { sx: { fontWeight: 'semibold', fontSize: 1 }, children: "What to give the directory" }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "SCIM base URL" }), _jsx(TextInput, { block: true, readOnly: true, value: scimBaseUrl(iamUrl), "aria-describedby": "scim-base-url-note" }), _jsxs(FormControl.Caption, { id: "scim-base-url-note", children: ["Okta and Entra append ", _jsx("code", { children: "/Users" }), " themselves. Use the token as a bearer credential; the token is what says which organization is being provisioned, so nothing else names this one."] })] }), _jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', m: 0 }, children: ["Groups are not provisioned over SCIM \u2014 this server answers them ", _jsx("code", { children: "501" }), " saying so. Roles come from the sign-in token\u2019s groups claim and the provider\u2019s role mappings, above; a second source of the same fact would eventually disagree with the first."] })] })] })) : (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(PeopleIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No SCIM token" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Issue one to let this organization\u2019s directory add people when they join and \u2014 the part sign-in cannot do \u2014 remove them when they leave." }) }), !readOnly && (_jsx(Button, { size: "small", onClick: openCreate, children: "New SCIM token" }))] }))] })), creating && (_jsx(Dialog, { title: "New SCIM token", onClose: () => setCreating(false), returnFocusRef: returnFocusRef, footerButtons: [
146
146
  {
147
147
  buttonType: 'default',
148
148
  content: 'Cancel',
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from 'react';
3
3
  import { Button, Heading, Label, Spinner, Text, Truncate } from '@primer/react';
4
- import { Box } from '@datalayer/primer-addons';
4
+ import { Box, Card } from '@datalayer/primer-addons';
5
5
  import { McpErrorBlankslate } from '../../components/mcp/index.js';
6
6
  import { useContentSources, useMcpSessions, useMcpTools, useRevokeMcpSession, } from '../../hooks/useContents.js';
7
7
  /**
@@ -67,7 +67,7 @@ const SourceCard = ({ source, permissions, errorState, }) => {
67
67
  const [revoking, setRevoking] = useState('');
68
68
  const look = config ? APPROVAL_POLICY_LOOK[config.approvalPolicy] : undefined;
69
69
  const offered = manifest.data?.tools?.length ?? 0;
70
- return (_jsxs(Box, { border: "1px solid", borderColor: "border.default", borderRadius: 2, p: 3, display: "grid", gap: 2, minWidth: 0, children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: source.name }), look && (_jsx(Label, { size: "small", variant: look.variant, children: look.label })), config?.transport && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: config.transport }))] }), look && _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: look.note }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: sourceTools.length === 0
70
+ return (_jsxs(Card, { border: true, shadow: "none", p: 3, display: "grid", gap: 2, minWidth: 0, children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(Heading, { as: "h3", sx: { fontSize: 1 }, children: source.name }), look && (_jsx(Label, { size: "small", variant: look.variant, children: look.label })), config?.transport && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: config.transport }))] }), look && _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: look.note }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: sourceTools.length === 0
71
71
  ? 'No tool is allowed on this source, so an agent can call none of it.'
72
72
  : `${sourceTools.length} of ${offered || sourceTools.length} tools allowed to agents.` }), sourceTools.length > 0 && (_jsx(Box, { display: "flex", gap: 1, flexWrap: "wrap", children: [...sourceTools].sort().map(tool => (_jsx(Label, { size: "small", variant: "accent", children: tool }, tool))) })), _jsxs(Box, { children: [_jsx(Heading, { as: "h4", sx: { fontSize: 0, color: 'fg.muted', mb: 1 }, children: "Open sessions" }), sessions.isError ? (_jsx(McpErrorBlankslate, { state: errorState(sessions.error, 'The sessions'), onRetry: () => sessions.refetch() })) : sessions.isPending ? (_jsx(Spinner, { size: "small" })) : (sessions.data?.items.length ?? 0) === 0 ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "No agent has opened this source." })) : ((sessions.data?.items ?? []).map(session => (_jsx(SessionRow, { session: session, sourceTools: sourceTools,
73
73
  // Revoking a session withdraws an agent's access to this
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datalayer/core",
3
- "version": "1.2.19",
3
+ "version": "1.2.20",
4
4
  "type": "module",
5
5
  "workspaces": [
6
6
  ".",