@datalayer/core 1.2.17 → 1.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cli-login.js +5 -51
- package/lib/components/anonymous/AnonymousKeyExpired.js +1 -15
- package/lib/components/anonymous/AnonymousKeyTimer.js +5 -15
- package/lib/components/auth/SignIn.js +2 -2
- package/lib/components/avatars/UserAvatar.js +3 -27
- package/lib/components/billing/BillingEntitySelect.js +6 -48
- package/lib/components/checkout/StripeCheckout.js +33 -217
- package/lib/components/contents/ContentSourceCard.js +2 -11
- package/lib/components/contents/HomeFolderObjectsBrowser.d.ts +1 -1
- package/lib/components/contents/HomeFolderObjectsBrowser.js +11 -35
- package/lib/components/display/CenteredSpinner.js +1 -6
- package/lib/components/display/DatalayerBox.js +2 -14
- package/lib/components/flashes/FlashClosable.js +2 -17
- package/lib/components/mcp/ClientBadge.js +1 -1
- package/lib/components/mcp/McpErrorBlankslate.js +1 -1
- package/lib/components/mcp/ScopeList.js +1 -1
- package/lib/components/notebooks/JupyterNotebook.js +1 -2
- package/lib/components/principal/Principal.js +2 -10
- package/lib/components/principal/PrincipalAppearance.js +19 -63
- package/lib/components/principal/PrincipalAvatar.js +5 -25
- package/lib/components/principal/PrincipalBadge.js +3 -13
- package/lib/components/principal/PrincipalBanner.js +4 -32
- package/lib/components/principal/PrincipalDetailsOverlay.js +7 -23
- package/lib/components/principal/PrincipalHoverCard.js +15 -18
- package/lib/components/principal/PrincipalSwitcherMenu.js +15 -83
- package/lib/components/progress/ConsumptionBar.js +1 -1
- package/lib/components/sharing/ShareAccessComponent.js +21 -229
- package/lib/components/sharing/SharingEditor.js +1 -1
- package/lib/components/spaces/SpaceDetailsOverlay.js +4 -35
- package/lib/components/spaces/SpaceDisplay.js +1 -8
- package/lib/components/storage/ContentsBrowser.js +3 -26
- package/lib/components/storage/ContentsTable.js +4 -23
- package/lib/components/students/StudentResultCircle.js +7 -29
- package/lib/components/timeline/Timeline.js +4 -36
- package/lib/hooks/layouts/LayoutBackdrop.js +2 -1
- package/lib/hooks/layouts/LayoutScreencapture.js +1 -1
- package/lib/hooks/libraryApp.d.ts +6 -1
- package/lib/hooks/libraryApp.js +10 -1
- package/lib/hooks/useAuthorization.js +6 -1
- package/lib/mocks/components/FlashMock.js +3 -8
- package/lib/mocks/views/DashboardMock.js +6 -72
- package/lib/mocks/views/FormMock.js +3 -2
- package/lib/mocks/views/TableMock.js +3 -2
- package/lib/mocks/views/WipMock.js +2 -1
- package/lib/models/Person.d.ts +9 -0
- package/lib/models/Person.js +23 -0
- package/lib/otel/index.d.ts +4 -0
- package/lib/otel/index.js +3 -0
- package/lib/otel/live/filter.d.ts +15 -0
- package/lib/otel/live/filter.js +16 -0
- package/lib/otel/live/index.d.ts +10 -0
- package/lib/otel/live/index.js +14 -0
- package/lib/otel/live/tracer.d.ts +94 -0
- package/lib/otel/live/tracer.js +223 -0
- package/lib/otel/live/useOtelLiveSpans.d.ts +6 -0
- package/lib/otel/live/useOtelLiveSpans.js +22 -0
- package/lib/otel/types.d.ts +17 -0
- package/lib/otel/views/OtelLive.js +4 -62
- package/lib/otel/views/OtelLiveSpans.d.ts +52 -0
- package/lib/otel/views/OtelLiveSpans.js +114 -0
- package/lib/otel/views/OtelLogsList.js +13 -64
- package/lib/otel/views/OtelMetricsChart.js +4 -19
- package/lib/otel/views/OtelMetricsList.js +8 -77
- package/lib/otel/views/OtelSearchBar.js +3 -12
- package/lib/otel/views/OtelSpanDetail.d.ts +6 -0
- package/lib/otel/views/OtelSpanDetail.js +31 -81
- package/lib/otel/views/OtelSpanTree.js +7 -57
- package/lib/otel/views/OtelSqlView.js +5 -99
- package/lib/otel/views/OtelSystemView.js +4 -34
- package/lib/otel/views/OtelTimeline.js +7 -37
- package/lib/otel/views/OtelTimelineRangeSlider.js +7 -140
- package/lib/otel/views/OtelTracesList.js +39 -87
- package/lib/otel/views/index.d.ts +3 -0
- package/lib/otel/views/index.js +2 -0
- package/lib/portable/index.d.ts +8 -0
- package/lib/portable/index.js +12 -0
- package/lib/state/substates/NavigationState.d.ts +6 -4
- package/lib/state/substates/NavigationState.js +6 -5
- package/lib/views/api-keys/APIKeyEdit.js +2 -11
- package/lib/views/api-keys/APIKeyNew.js +3 -19
- package/lib/views/api-keys/APIKeys.js +6 -11
- package/lib/views/api-keys/APIKeysStandalone.js +1 -1
- package/lib/views/datasources/DatasourceDetail.d.ts +1 -1
- package/lib/views/datasources/DatasourceDetail.js +24 -17
- package/lib/views/datasources/DatasourceNew.js +2 -6
- package/lib/views/datasources/Datasources.js +2 -14
- package/lib/views/iam/SignInSimple.js +8 -64
- package/lib/views/mcp/AdmittedClients.js +3 -16
- package/lib/views/mcp/AlertDestinations.js +2 -10
- package/lib/views/mcp/AlertRules.js +4 -9
- package/lib/views/mcp/ApprovalQueue.js +4 -21
- package/lib/views/mcp/AuditLog.js +7 -44
- package/lib/views/mcp/ConnectedAgents.js +1 -6
- package/lib/views/mcp/EnterpriseConsole.js +10 -23
- package/lib/views/mcp/IdentityProviders.js +7 -31
- package/lib/views/mcp/McpDashboard.js +14 -30
- package/lib/views/mcp/McpHome.js +7 -54
- package/lib/views/mcp/McpObservability.js +13 -85
- package/lib/views/mcp/NotebookRuns.js +5 -12
- package/lib/views/mcp/OrganizationPolicy.js +3 -9
- package/lib/views/mcp/OrganizationUsage.js +4 -11
- package/lib/views/mcp/PersonalPolicy.js +3 -3
- package/lib/views/mcp/Policies.js +5 -46
- package/lib/views/mcp/PolicyForm.js +1 -9
- package/lib/views/mcp/PolicyHistory.js +2 -8
- package/lib/views/mcp/RunDetail.js +3 -25
- package/lib/views/mcp/ScimProvisioning.js +3 -15
- package/lib/views/mcp/ServiceAgents.js +4 -17
- package/lib/views/mcp/TeamPolicies.js +7 -19
- package/lib/views/mcp/ToolAccess.js +15 -22
- package/lib/views/mcp/TraceTimeline.js +8 -23
- package/lib/views/otel/DashboardView.js +2 -2
- package/lib/views/otel/LogsView.js +2 -2
- package/lib/views/otel/MetricsView.js +2 -2
- package/lib/views/otel/OtelHeader.js +6 -40
- package/lib/views/otel/SqlView.js +2 -2
- package/lib/views/otel/SystemView.js +2 -2
- package/lib/views/otel/TracesView.js +2 -2
- package/lib/views/profile/UserBadge.js +6 -98
- package/lib/views/secrets/SecretEdit.js +2 -11
- package/lib/views/secrets/SecretNew.js +1 -1
- package/package.json +1 -1
|
@@ -165,13 +165,13 @@ export const IdentityProviders = ({ errorState, orgUid, readOnly = false, showTi
|
|
|
165
165
|
id: 'name',
|
|
166
166
|
rowHeader: true,
|
|
167
167
|
width: 'growCollapse',
|
|
168
|
-
renderCell: row => (_jsxs(Box, {
|
|
168
|
+
renderCell: row => (_jsxs(Box, { display: "grid", children: [_jsx(Text, { sx: { fontSize: 1, fontWeight: 'bold' }, children: row.name }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: row.issuer })] })),
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
header: 'Domains',
|
|
172
172
|
id: 'domains',
|
|
173
173
|
width: 'growCollapse',
|
|
174
|
-
renderCell: row => (_jsxs(Box, {
|
|
174
|
+
renderCell: row => (_jsxs(Box, { display: "flex", flexWrap: "wrap", gap: 1, children: [row.domains.length === 0 && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: "none" })), row.domains.map(domain => (_jsxs(Label, { size: "small", variant: row.verifiedDomains.includes(domain) ? 'success' : 'secondary', children: [domain, row.verifiedDomains.includes(domain)
|
|
175
175
|
? ' · verified'
|
|
176
176
|
: ' · claimed'] }, domain)))] })),
|
|
177
177
|
},
|
|
@@ -192,12 +192,7 @@ export const IdentityProviders = ({ errorState, orgUid, readOnly = false, showTi
|
|
|
192
192
|
if (providers.isError) {
|
|
193
193
|
return (_jsx(McpErrorBlankslate, { state: errorState(providers.error, 'Identity providers'), onRetry: () => providers.refetch() }));
|
|
194
194
|
}
|
|
195
|
-
return (_jsxs(Box, {
|
|
196
|
-
display: 'flex',
|
|
197
|
-
alignItems: 'start',
|
|
198
|
-
justifyContent: 'space-between',
|
|
199
|
-
gap: 3,
|
|
200
|
-
}, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Identity providers" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "The directory this organization signs in through. A domain is claimed the moment it is typed here and routes nothing until it is verified." })] }), !readOnly && (_jsx(Button, { variant: "primary", onClick: openCreate, children: "New provider" }))] })), providers.isPending && !providers.data ? (_jsx(Box, { sx: { display: 'flex', justifyContent: 'center', py: 5 }, children: _jsx(Spinner, {}) })) : rows.length > 0 ? (_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h3", id: "identity-providers", children: "Providers" }), _jsx(Table.Subtitle, { as: "p", id: "identity-providers-subtitle", children: "A provider switched off keeps its configuration and its verified domains; only sign-in through it stops." }), _jsx(DataTable, { "aria-labelledby": "identity-providers", "aria-describedby": "identity-providers-subtitle", data: rows, columns: columns })] })) : (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(KeyIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No directory registered" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "People here sign in the ordinary way. Register a provider to let them sign in through the directory this organization already has." }) }), !readOnly && (_jsx(Button, { size: "small", onClick: openCreate, children: "New provider" }))] })), (creating || editing) && (_jsx(Dialog, { title: editing ? 'Edit identity provider' : 'New identity provider', onClose: close, returnFocusRef: returnFocusRef, footerButtons: [
|
|
195
|
+
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: "Identity providers" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "The directory this organization signs in through. A domain is claimed the moment it is typed here and routes nothing until it is verified." })] }), !readOnly && (_jsx(Button, { variant: "primary", onClick: openCreate, children: "New provider" }))] })), providers.isPending && !providers.data ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : rows.length > 0 ? (_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h3", id: "identity-providers", children: "Providers" }), _jsx(Table.Subtitle, { as: "p", id: "identity-providers-subtitle", children: "A provider switched off keeps its configuration and its verified domains; only sign-in through it stops." }), _jsx(DataTable, { "aria-labelledby": "identity-providers", "aria-describedby": "identity-providers-subtitle", data: rows, columns: columns })] })) : (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(KeyIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No directory registered" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "People here sign in the ordinary way. Register a provider to let them sign in through the directory this organization already has." }) }), !readOnly && (_jsx(Button, { size: "small", onClick: openCreate, children: "New provider" }))] })), (creating || editing) && (_jsx(Dialog, { title: editing ? 'Edit identity provider' : 'New identity provider', onClose: close, returnFocusRef: returnFocusRef, footerButtons: [
|
|
201
196
|
{ buttonType: 'default', content: 'Cancel', onClick: close },
|
|
202
197
|
{
|
|
203
198
|
buttonType: 'primary',
|
|
@@ -205,19 +200,9 @@ export const IdentityProviders = ({ errorState, orgUid, readOnly = false, showTi
|
|
|
205
200
|
onClick: apply,
|
|
206
201
|
disabled: create.isPending || update.isPending,
|
|
207
202
|
},
|
|
208
|
-
], children: _jsxs(Box, {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
justifyContent: 'space-between',
|
|
212
|
-
mb: 2,
|
|
213
|
-
}, children: [_jsx(FormControl.Label, { children: "Group \u2192 role mapping" }), _jsx(Button, { size: "small", onClick: addMapping, children: "Add mapping" })] }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 0, mb: 2 }, children: "Granted the next time somebody in the group signs in, and never taken back by a sign-in that omits it \u2014 a slow directory sync should not read as a demotion. Reaches no further than this organization and its own teams." }), draft.roleMappings.length === 0 && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: "No mapping: everybody who signs in through this provider becomes an organization member and nothing more." })), _jsx(Box, { sx: { display: 'grid', gap: 2 }, children: draft.roleMappings.map((mapping, index) => (_jsxs(Box, { sx: {
|
|
214
|
-
display: 'grid',
|
|
215
|
-
gap: 2,
|
|
216
|
-
gridTemplateColumns: isTeamRole(mapping.role)
|
|
217
|
-
? '1fr 1fr 1fr auto'
|
|
218
|
-
: '1fr 1fr auto',
|
|
219
|
-
alignItems: 'end',
|
|
220
|
-
}, children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Group" }), _jsx(TextInput, { block: true, value: mapping.group, onChange: event => setMapping(index, { group: event.target.value }), placeholder: "admins" })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Grants" }), _jsxs(Select, { value: mapping.role, onChange: event => setMapping(index, {
|
|
203
|
+
], children: _jsxs(Box, { display: "grid", gap: 3, children: [refusal && (_jsx(Flash, { variant: "danger", children: _jsx(Text, { sx: { fontSize: 1 }, children: refusal }) })), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Name" }), _jsx(TextInput, { block: true, value: draft.name, onChange: event => set('name', event.target.value), placeholder: "Acme Okta" }), _jsx(FormControl.Caption, { children: "What an administrator sees in this list." })] }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Issuer" }), _jsx(TextInput, { block: true, value: draft.issuer, onChange: event => set('issuer', event.target.value), placeholder: "https://acme.okta.com" }), _jsx(FormControl.Caption, { children: "Must be https \u2014 discovery, the signing keys and the sign-in redirect all travel over it." })] }), _jsxs(Box, { display: "grid", gap: 2, gridTemplateColumns: "1fr 1fr", children: [_jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Client ID" }), _jsx(TextInput, { block: true, value: draft.clientId, onChange: event => set('clientId', event.target.value) })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Client secret" }), _jsx(TextInput, { block: true, value: draft.clientSecretRef, onChange: event => set('clientSecretRef', event.target.value), placeholder: "the secret's name, not the secret" }), _jsx(FormControl.Caption, { children: "The name of a secret already in this organization\u2019s store \u2014 never the secret itself." })] })] }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Email domains" }), _jsx(TextInput, { block: true, value: domainsText, onChange: event => setDomainsText(event.target.value), placeholder: "acme.com, acme.io" }), _jsx(FormControl.Caption, { children: "Comma-separated. Claiming a domain is free and routes nothing \u2014 verify it below once it is registered before anybody can sign in through it." })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Group claim" }), _jsx(TextInput, { block: true, value: draft.groupClaim, onChange: event => set('groupClaim', event.target.value), placeholder: "groups" }), _jsx(FormControl.Caption, { children: "Which claim in the token carries the groups the mapping below reads." })] }), _jsxs(FormControl, { children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(ToggleSwitch, { size: "small", checked: draft.allowEmailLinking, "aria-labelledby": "allow-email-linking-label", onClick: () => set('allowEmailLinking', !draft.allowEmailLinking) }), _jsx(FormControl.Label, { id: "allow-email-linking-label", children: "Adopt an existing account on a verified address" })] }), _jsx(FormControl.Caption, { children: "Off by default: a sign-in whose address already has a Datalayer account is refused rather than signed in as that account, and the person is told to connect the two from a session they already hold. Turn this on only if the smoother rollout is worth it \u2014 the address still has to be on a verified domain, and the provider still has to say it verified it itself." })] }), _jsxs(Box, { children: [_jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", mb: 2, children: [_jsx(FormControl.Label, { children: "Group \u2192 role mapping" }), _jsx(Button, { size: "small", onClick: addMapping, children: "Add mapping" })] }), _jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', mt: 0, mb: 2 }, children: "Granted the next time somebody in the group signs in, and never taken back by a sign-in that omits it \u2014 a slow directory sync should not read as a demotion. Reaches no further than this organization and its own teams." }), draft.roleMappings.length === 0 && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: "No mapping: everybody who signs in through this provider becomes an organization member and nothing more." })), _jsx(Box, { display: "grid", gap: 2, children: draft.roleMappings.map((mapping, index) => (_jsxs(Box, { display: "grid", gap: 2, gridTemplateColumns: isTeamRole(mapping.role)
|
|
204
|
+
? '1fr 1fr 1fr auto'
|
|
205
|
+
: '1fr 1fr auto', alignItems: "end", children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Group" }), _jsx(TextInput, { block: true, value: mapping.group, onChange: event => setMapping(index, { group: event.target.value }), placeholder: "admins" })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Grants" }), _jsxs(Select, { value: mapping.role, onChange: event => setMapping(index, {
|
|
221
206
|
role: event.target.value,
|
|
222
207
|
}), children: [ORGANIZATION_ROLES.map(role => (_jsx(Select.Option, { value: role, children: roleLabel(role) }, role))), TEAM_ROLES.map(role => (_jsx(Select.Option, { value: role, children: roleLabel(role) }, role)))] })] }), isTeamRole(mapping.role) && (_jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "Team" }), _jsx(TextInput, { block: true, value: mapping.teamUid, onChange: event => setMapping(index, { teamUid: event.target.value }), placeholder: "team uid" })] })), _jsx(IconButton, { icon: TrashIcon, variant: "danger", size: "small", "aria-label": "Remove this mapping", onClick: () => removeMapping(index) })] }, index))) })] })] }) })), managingDomains && (_jsx(DomainVerificationDialog, { provider: managingDomains, orgUid: orgUid, onClose: () => setManagingDomains(null), fetchVerification: domainVerification, verify: verifyDomain })), removing && (_jsx(Dialog, { title: "Remove this identity provider?", onClose: () => setRemoving(null), returnFocusRef: returnFocusRef, footerButtons: [
|
|
223
208
|
{
|
|
@@ -285,15 +270,6 @@ const DomainVerificationDialog = ({ provider, onClose, fetchVerification, verify
|
|
|
285
270
|
};
|
|
286
271
|
return (_jsx(Dialog, { title: `Verify a domain for ${provider.name}`, onClose: onClose, returnFocusRef: returnFocusRef, footerButtons: [
|
|
287
272
|
{ buttonType: 'default', content: 'Close', onClick: onClose },
|
|
288
|
-
], children: _jsxs(Box, {
|
|
289
|
-
display: 'grid',
|
|
290
|
-
gap: 1,
|
|
291
|
-
p: 2,
|
|
292
|
-
border: '1px solid',
|
|
293
|
-
borderColor: 'border.default',
|
|
294
|
-
borderRadius: 2,
|
|
295
|
-
fontFamily: 'mono',
|
|
296
|
-
fontSize: 0,
|
|
297
|
-
}, children: [_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Type: ", record.type] }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Host: ", record.host] }), _jsxs(Text, { sx: { fontSize: 0, wordBreak: 'break-all' }, children: ["Value: ", record.value] })] })) : (_jsx(Button, { size: "small", onClick: () => load(selected), children: "Show what to publish" })), _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Label, { variant: verified ? 'success' : 'secondary', children: verified ? 'Verified — routes sign-in' : 'Not yet verified' }), !verified && (_jsx(Button, { variant: "primary", size: "small", onClick: runVerify, disabled: verify.isPending || !selected, children: verify.isPending ? 'Checking…' : 'Check DNS now' }))] })] }) }));
|
|
273
|
+
], children: _jsxs(Box, { display: "grid", gap: 3, children: [_jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0 }, children: "Publish the record below at your DNS provider, then check it here. Until it checks out, this domain routes no sign-in \u2014 a claim is not proof." }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Domain" }), _jsx(Select, { value: selected, onChange: event => load(event.target.value), children: provider.domains.map(domain => (_jsxs(Select.Option, { value: domain, children: [domain, provider.verifiedDomains.includes(domain) ? ' — verified' : ''] }, domain))) })] }), refusal && (_jsx(Flash, { variant: "danger", children: _jsx(Text, { sx: { fontSize: 1 }, children: refusal }) })), fetchVerification.isPending ? (_jsx(Spinner, { size: "small" })) : record ? (_jsxs(Box, { display: "grid", gap: 1, p: 2, border: "1px solid", borderColor: "border.default", borderRadius: 2, fontFamily: "mono", fontSize: 0, children: [_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Type: ", record.type] }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Host: ", record.host] }), _jsxs(Text, { sx: { fontSize: 0, wordBreak: 'break-all' }, children: ["Value: ", record.value] })] })) : (_jsx(Button, { size: "small", onClick: () => load(selected), children: "Show what to publish" })), _jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(Label, { variant: verified ? 'success' : 'secondary', children: verified ? 'Verified — routes sign-in' : 'Not yet verified' }), !verified && (_jsx(Button, { variant: "primary", size: "small", onClick: runVerify, disabled: verify.isPending || !selected, children: verify.isPending ? 'Checking…' : 'Check DNS now' }))] })] }) }));
|
|
298
274
|
};
|
|
299
275
|
export default IdentityProviders;
|
|
@@ -54,14 +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, { sx: {
|
|
58
|
-
p: 3,
|
|
59
|
-
border: '1px solid',
|
|
60
|
-
borderColor: 'border.default',
|
|
61
|
-
borderRadius: 2,
|
|
62
|
-
bg: 'canvas.default',
|
|
63
|
-
minWidth: 0,
|
|
64
|
-
}, children: [_jsx(Text, { sx: {
|
|
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: {
|
|
65
58
|
display: 'block',
|
|
66
59
|
fontSize: 4,
|
|
67
60
|
fontWeight: 'bold',
|
|
@@ -230,7 +223,7 @@ export const McpDashboard = ({ errorState, routes, org, showTitle = true, sectio
|
|
|
230
223
|
{
|
|
231
224
|
header: 'Last tool',
|
|
232
225
|
id: 'last-tool',
|
|
233
|
-
renderCell: row => row.lastCall ? (_jsxs(Box, {
|
|
226
|
+
renderCell: row => row.lastCall ? (_jsxs(Box, { display: "grid", gap: "2px", minWidth: 0, children: [_jsx(Text, { sx: { fontSize: 0 }, children: row.lastCall.tool || row.lastCall.method }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: timeAgo(row.lastCall.at) })] })) : (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Nothing yet" })),
|
|
234
227
|
},
|
|
235
228
|
{
|
|
236
229
|
header: 'Status',
|
|
@@ -298,7 +291,7 @@ export const McpDashboard = ({ errorState, routes, org, showTitle = true, sectio
|
|
|
298
291
|
header: 'Capabilities',
|
|
299
292
|
id: 'capabilities',
|
|
300
293
|
width: 'growCollapse',
|
|
301
|
-
renderCell: row => (_jsxs(Box, {
|
|
294
|
+
renderCell: row => (_jsxs(Box, { display: "flex", gap: 1, flexWrap: "wrap", children: [(row.capabilities ?? []).map(capability => (_jsx(Label, { size: "small", variant: "secondary", children: capability }, capability))), (row.capabilities ?? []).length === 0 && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "\u2014" }))] })),
|
|
302
295
|
},
|
|
303
296
|
{
|
|
304
297
|
header: 'Last used',
|
|
@@ -320,7 +313,7 @@ export const McpDashboard = ({ errorState, routes, org, showTitle = true, sectio
|
|
|
320
313
|
id: 'actions',
|
|
321
314
|
width: '190px',
|
|
322
315
|
align: 'end',
|
|
323
|
-
renderCell: row => (_jsxs(Box, {
|
|
316
|
+
renderCell: row => (_jsxs(Box, { display: "flex", gap: 2, justifyContent: "flex-end", children: [sandboxSharingUrl(runtimesUrl, row.runtimeName) && (_jsx(Button, { size: "small", disabled: row.state === 'closed', onClick: () => setSharing(row), children: "Share" })), _jsx(Button, { size: "small", variant: "danger", disabled: row.state === 'closed', onClick: () => setTerminating(row), children: "Terminate" })] })),
|
|
324
317
|
},
|
|
325
318
|
];
|
|
326
319
|
const callColumns = [
|
|
@@ -328,7 +321,7 @@ export const McpDashboard = ({ errorState, routes, org, showTitle = true, sectio
|
|
|
328
321
|
header: 'Tool',
|
|
329
322
|
field: 'tool',
|
|
330
323
|
rowHeader: true,
|
|
331
|
-
renderCell: row => (_jsxs(Box, {
|
|
324
|
+
renderCell: row => (_jsxs(Box, { display: "grid", gap: "2px", minWidth: 0, children: [_jsx(Text, { sx: { fontSize: 1 }, children: row.tool || row.method }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: timeAgo(row.at) })] })),
|
|
332
325
|
},
|
|
333
326
|
{
|
|
334
327
|
header: 'Client',
|
|
@@ -369,24 +362,20 @@ export const McpDashboard = ({ errorState, routes, org, showTitle = true, sectio
|
|
|
369
362
|
align: 'end',
|
|
370
363
|
renderCell: row => {
|
|
371
364
|
const trace = traceFor(row);
|
|
372
|
-
return (_jsxs(Box, {
|
|
365
|
+
return (_jsxs(Box, { display: "flex", gap: 2, justifyContent: "flex-end", children: [_jsx(Link, { as: "button", sx: { fontSize: 0, cursor: 'pointer' }, onClick: () => navigate(auditFor(row)), children: "Audit" }), trace && (_jsx(Link, { as: "button", sx: { fontSize: 0, cursor: 'pointer' }, onClick: () => navigate(trace), children: "Trace" }))] }));
|
|
373
366
|
},
|
|
374
367
|
},
|
|
375
368
|
];
|
|
376
369
|
if (activity.isError) {
|
|
377
|
-
return (_jsx(Box, {
|
|
370
|
+
return (_jsx(Box, { display: "grid", gap: 3, children: _jsx(McpErrorBlankslate, { state: errorState(activity.error, 'MCP activity'), onRetry: () => activity.refetch() }) }));
|
|
378
371
|
}
|
|
379
372
|
const loading = activity.isPending && !data;
|
|
380
|
-
return (_jsxs(Box, {
|
|
381
|
-
(loading ? (_jsx(Box, {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
'repeat(3, 1fr)',
|
|
387
|
-
'repeat(6, 1fr)',
|
|
388
|
-
],
|
|
389
|
-
}, children: [_jsx(Count, { label: "Clients connected", value: clients.length, to: routes.agents, onOpen: navigate }), _jsx(Count, { label: "Sandboxes bound", to: routes.sandboxes, onOpen: navigate, value: sandboxes.filter(binding => (binding.state ?? 'active') === 'active').length }), _jsx(Count, { label: "Tasks running", value: data?.tasks.length ?? 0, to: routes.runs, onOpen: navigate }), _jsx(Count, { label: "Calls today", value: data?.today.calls ?? 0, to: routes.calls, onOpen: navigate }), _jsx(Count, { label: "Refusals today", value: data?.today.refusals ?? 0, to: routes.audit, onOpen: navigate, tone: (data?.today.refusals ?? 0) > 0 ? 'danger' : 'neutral' }), _jsx(Count, { label: "Credits by agents", value: data?.today.credits ?? 0, note: "today",
|
|
373
|
+
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: "What the agents connected to your workspace are doing right now." })] })), draws('overview') &&
|
|
374
|
+
(loading ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : (_jsxs(Box, { display: "grid", gap: 3, gridTemplateColumns: [
|
|
375
|
+
'repeat(2, 1fr)',
|
|
376
|
+
'repeat(3, 1fr)',
|
|
377
|
+
'repeat(6, 1fr)',
|
|
378
|
+
], children: [_jsx(Count, { label: "Clients connected", value: clients.length, to: routes.agents, onOpen: navigate }), _jsx(Count, { label: "Sandboxes bound", to: routes.sandboxes, onOpen: navigate, value: sandboxes.filter(binding => (binding.state ?? 'active') === 'active').length }), _jsx(Count, { label: "Tasks running", value: data?.tasks.length ?? 0, to: routes.runs, onOpen: navigate }), _jsx(Count, { label: "Calls today", value: data?.today.calls ?? 0, to: routes.calls, onOpen: navigate }), _jsx(Count, { label: "Refusals today", value: data?.today.refusals ?? 0, to: routes.audit, onOpen: navigate, tone: (data?.today.refusals ?? 0) > 0 ? 'danger' : 'neutral' }), _jsx(Count, { label: "Credits by agents", value: data?.today.credits ?? 0, note: "today",
|
|
390
379
|
// Credits are summed from the day's calls, which the Calls tab
|
|
391
380
|
// lists.
|
|
392
381
|
to: routes.calls, onOpen: navigate })] }))), draws('agents') &&
|
|
@@ -398,12 +387,7 @@ export const McpDashboard = ({ errorState, routes, org, showTitle = true, sectio
|
|
|
398
387
|
!loading &&
|
|
399
388
|
(sandboxes.length > 0 ? (_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h3", id: "mcp-sandboxes", children: "Sandboxes bound" }), _jsx(Table.Subtitle, { as: "p", id: "mcp-sandboxes-subtitle", children: "The sessions your agents execute in. Terminating one ends its open work." }), _jsx(DataTable, { "aria-labelledby": "mcp-sandboxes", "aria-describedby": "mcp-sandboxes-subtitle", data: sandboxes, columns: sandboxColumns })] })) : (_jsx(PanelEmpty, { icon: StackIcon, heading: "No sandbox bound", description: "An agent that launches a sandbox keeps it for the session; it appears here with its provider, its capabilities and what it is doing." }))), draws('calls') &&
|
|
400
389
|
!loading &&
|
|
401
|
-
(calls.length > 0 ? (_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h3", id: "mcp-calls", children: "Recent calls" }), _jsx(Table.Subtitle, { as: "p", id: "mcp-calls-subtitle", children: "The last calls as they landed. Every one of them has an audit row that outlives this page." }), _jsx(Table.Actions, { children: _jsxs(Box, {
|
|
402
|
-
p: 4,
|
|
403
|
-
textAlign: 'center',
|
|
404
|
-
color: 'fg.muted',
|
|
405
|
-
fontSize: 1,
|
|
406
|
-
}, children: "No call matches these filters." }))] })) : (_jsx(PanelEmpty, { icon: ChecklistIcon, heading: "No call yet", description: "Ask your agent to list your notebooks. The call, its decision and its outcome land here and in the audit log.", action: {
|
|
390
|
+
(calls.length > 0 ? (_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h3", id: "mcp-calls", children: "Recent calls" }), _jsx(Table.Subtitle, { as: "p", id: "mcp-calls-subtitle", children: "The last calls as they landed. Every one of them has an audit row that outlives this page." }), _jsx(Table.Actions, { children: _jsxs(Box, { display: "flex", gap: 2, alignItems: "center", children: [_jsxs(Select, { size: "small", "aria-label": "Filter by client", value: callClient, onChange: event => setCallClient(event.currentTarget.value), children: [_jsx(Select.Option, { value: "", children: "Every client" }), clients.map(client => (_jsx(Select.Option, { value: client.clientId, children: client.clientName || client.clientId }, client.clientId)))] }), _jsxs(Select, { size: "small", "aria-label": "Filter by tool", value: callTool, onChange: event => setCallTool(event.currentTarget.value), children: [_jsx(Select.Option, { value: "", children: "Every tool" }), callTools.map(tool => (_jsx(Select.Option, { value: tool, children: tool }, tool)))] }), _jsxs(Select, { size: "small", "aria-label": "Filter by outcome", value: callOutcome, onChange: event => setCallOutcome(event.currentTarget.value), children: [_jsx(Select.Option, { value: "", children: "Every outcome" }), _jsx(Select.Option, { value: "ok", children: "Succeeded" }), _jsx(Select.Option, { value: "error", children: "Failed" }), _jsx(Select.Option, { value: "refused", children: "Refused" })] })] }) }), filteredCalls.length > 0 ? (_jsx(DataTable, { "aria-labelledby": "mcp-calls", "aria-describedby": "mcp-calls-subtitle", data: filteredCalls, columns: callColumns })) : (_jsx(Box, { p: 4, textAlign: "center", color: "fg.muted", fontSize: 1, children: "No call matches these filters." }))] })) : (_jsx(PanelEmpty, { icon: ChecklistIcon, heading: "No call yet", description: "Ask your agent to list your notebooks. The call, its decision and its outcome land here and in the audit log.", action: {
|
|
407
391
|
label: 'Open the audit log',
|
|
408
392
|
onClick: () => navigate(routes.audit),
|
|
409
393
|
} }))), disconnecting && (_jsx(Dialog, { title: "Disconnect this client?", onClose: () => setDisconnecting(null), returnFocusRef: returnFocusRef, footerButtons: [
|
package/lib/views/mcp/McpHome.js
CHANGED
|
@@ -41,15 +41,7 @@ export const MCP_CLIENTS = [
|
|
|
41
41
|
*/
|
|
42
42
|
export const Copyable = ({ text }) => {
|
|
43
43
|
const [copied, setCopied] = useState(false);
|
|
44
|
-
return (_jsxs(Box, { sx: {
|
|
45
|
-
display: 'flex',
|
|
46
|
-
alignItems: 'center',
|
|
47
|
-
gap: 2,
|
|
48
|
-
p: 2,
|
|
49
|
-
bg: 'canvas.inset',
|
|
50
|
-
borderRadius: 2,
|
|
51
|
-
minWidth: 0,
|
|
52
|
-
}, children: [_jsx(Text, { sx: {
|
|
44
|
+
return (_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, p: 2, bg: "canvas.inset", borderRadius: 2, minWidth: 0, children: [_jsx(Text, { sx: {
|
|
53
45
|
fontFamily: 'mono',
|
|
54
46
|
fontSize: 0,
|
|
55
47
|
flex: 1,
|
|
@@ -64,23 +56,14 @@ export const Copyable = ({ text }) => {
|
|
|
64
56
|
} })] }));
|
|
65
57
|
};
|
|
66
58
|
/** One of the five summaries: a heading, what it holds, and the way in. */
|
|
67
|
-
const Summary = ({ icon: Icon, title, children, action, to, onOpen, }) => (_jsxs(Box, {
|
|
68
|
-
p: 3,
|
|
69
|
-
border: '1px solid',
|
|
70
|
-
borderColor: 'border.default',
|
|
71
|
-
borderRadius: 2,
|
|
72
|
-
display: 'grid',
|
|
73
|
-
gap: 2,
|
|
74
|
-
alignContent: 'start',
|
|
75
|
-
minWidth: 0,
|
|
76
|
-
}, children: [_jsxs(Box, { sx: { 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(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 => {
|
|
77
60
|
// A modified click asks for a new tab; `href` is real, so let it.
|
|
78
61
|
if (event.metaKey || event.ctrlKey || event.shiftKey) {
|
|
79
62
|
return;
|
|
80
63
|
}
|
|
81
64
|
event.preventDefault();
|
|
82
65
|
onOpen?.(to);
|
|
83
|
-
}, sx: { fontSize: 1, fontWeight: 'semibold' }, children: title })) : (_jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: title }))] }), _jsx(Box, {
|
|
66
|
+
}, sx: { fontSize: 1, fontWeight: 'semibold' }, children: title })) : (_jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: title }))] }), _jsx(Box, { fontSize: 0, color: "fg.muted", display: "grid", gap: 1, children: children }), action && (_jsx(Box, { children: _jsx(Link, { as: "button", sx: { fontSize: 0, cursor: 'pointer' }, onClick: action.onClick, children: action.label }) }))] }));
|
|
84
67
|
export const McpHome = ({ routes, clientDocsBase = '/docs/mcp-clients', showTitle = true, showSummaries = true, showSetup = true, onOpenDocs, }) => {
|
|
85
68
|
const navigate = useNavigate();
|
|
86
69
|
const endpoint = useCoreStore(state => state.configuration.datalayerMcpServerUrl);
|
|
@@ -94,37 +77,11 @@ export const McpHome = ({ routes, clientDocsBase = '/docs/mcp-clients', showTitl
|
|
|
94
77
|
const connected = agents.data ?? [];
|
|
95
78
|
const runs = tasks.data?.items ?? [];
|
|
96
79
|
const live = activity.data?.clients.length ?? 0;
|
|
97
|
-
return (_jsxs(Box, {
|
|
98
|
-
display: 'flex',
|
|
99
|
-
alignItems: 'center',
|
|
100
|
-
gap: 3,
|
|
101
|
-
flexWrap: 'wrap',
|
|
102
|
-
p: 3,
|
|
103
|
-
borderRadius: 2,
|
|
104
|
-
bg: 'canvas.subtle',
|
|
105
|
-
border: '1px solid',
|
|
106
|
-
borderColor: 'border.default',
|
|
107
|
-
}, 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(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
|
|
108
81
|
? `${plural(live, 'client')} connected right now.`
|
|
109
|
-
: 'No client is connected right now.' }), _jsx(Button, { size: "small", leadingVisual: PulseIcon, onClick: () => navigate(routes.dashboard), children: "What is going on" })] }), _jsxs(Box, {
|
|
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
|
|
110
83
|
? 'You are signed in, so a client you set up from here authorizes through OAuth without a shared token.'
|
|
111
|
-
: 'Sign in to authorize a client through OAuth; without it a client can only use a personal access token.' })] })] }), _jsxs(Box, {
|
|
112
|
-
display: 'grid',
|
|
113
|
-
gap: 3,
|
|
114
|
-
gridTemplateColumns: [
|
|
115
|
-
'1fr',
|
|
116
|
-
'repeat(2, 1fr)',
|
|
117
|
-
'repeat(3, 1fr)',
|
|
118
|
-
],
|
|
119
|
-
}, children: MCP_CLIENTS.map(client => (_jsxs(Box, { sx: {
|
|
120
|
-
p: 3,
|
|
121
|
-
border: '1px solid',
|
|
122
|
-
borderColor: 'border.default',
|
|
123
|
-
borderRadius: 2,
|
|
124
|
-
display: 'grid',
|
|
125
|
-
gap: 2,
|
|
126
|
-
minWidth: 0,
|
|
127
|
-
}, 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(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 => {
|
|
128
85
|
// A modified click is the reader asking for a new tab or
|
|
129
86
|
// window, and `href` is real so it still leads to the
|
|
130
87
|
// full page — for that, for the status bar and for the
|
|
@@ -134,11 +91,7 @@ export const McpHome = ({ routes, clientDocsBase = '/docs/mcp-clients', showTitl
|
|
|
134
91
|
}
|
|
135
92
|
event.preventDefault();
|
|
136
93
|
onOpenDocs(`${clientDocsBase}/${client.setup}`);
|
|
137
|
-
}, children: "Configuration and authorization" })] }, client.setup))) })] })] })), showSummaries && (_jsxs(Box, {
|
|
138
|
-
display: 'grid',
|
|
139
|
-
gap: 3,
|
|
140
|
-
gridTemplateColumns: ['1fr', 'repeat(2, 1fr)', 'repeat(3, 1fr)'],
|
|
141
|
-
}, children: [_jsx(Summary, { icon: AiAgentIcon, title: "Agents", to: routes.agents, onOpen: navigate, action: {
|
|
94
|
+
}, children: "Configuration and authorization" })] }, client.setup))) })] })] })), showSummaries && (_jsxs(Box, { display: "grid", gap: 3, gridTemplateColumns: ['1fr', 'repeat(2, 1fr)', 'repeat(3, 1fr)'], children: [_jsx(Summary, { icon: AiAgentIcon, title: "Agents", to: routes.agents, onOpen: navigate, action: {
|
|
142
95
|
label: 'Connected agents',
|
|
143
96
|
onClick: () => navigate(routes.agents),
|
|
144
97
|
}, children: connected.length === 0 ? (_jsx(Text, { children: "No agent has been authorized yet. Set up a client above and approve the scopes it asks for." })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { children: [plural(connected.length, 'agent'), " authorized."] }), connected.slice(0, 3).map(agent => (_jsxs(Text, { children: [agent.clientName || agent.clientId, " \u2014", ' ', agent.lastUsedAt
|
|
@@ -43,16 +43,7 @@ export const stageOf = (name) => {
|
|
|
43
43
|
const SpanRow = ({ node, depth, }) => {
|
|
44
44
|
const stage = stageOf(node.span.span_name);
|
|
45
45
|
const failed = (node.span.status_code ?? '').toUpperCase() === 'ERROR';
|
|
46
|
-
return (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
|
|
47
|
-
display: 'flex',
|
|
48
|
-
alignItems: 'center',
|
|
49
|
-
gap: 2,
|
|
50
|
-
py: 1,
|
|
51
|
-
pl: depth * 3,
|
|
52
|
-
borderBottom: '1px solid',
|
|
53
|
-
borderColor: 'border.muted',
|
|
54
|
-
minWidth: 0,
|
|
55
|
-
}, children: [_jsx(Text, { sx: {
|
|
46
|
+
return (_jsxs(_Fragment, { children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, py: 1, pl: depth * 3, borderBottom: "1px solid", borderColor: "border.muted", minWidth: 0, children: [_jsx(Text, { sx: {
|
|
56
47
|
fontSize: 0,
|
|
57
48
|
fontFamily: 'mono',
|
|
58
49
|
flex: 1,
|
|
@@ -69,13 +60,7 @@ const SpanRow = ({ node, depth, }) => {
|
|
|
69
60
|
}, children: durationLabel(node.span.duration_ms) })] }), node.children.map(child => (_jsx(SpanRow, { node: child, depth: depth + 1 }, child.span.span_id)))] }));
|
|
70
61
|
};
|
|
71
62
|
/** A number the reader can act on, or a plain statement that it is not measured. */
|
|
72
|
-
const Sli = ({ label, value, note, }) => (_jsxs(Box, { sx: {
|
|
73
|
-
p: 3,
|
|
74
|
-
border: '1px solid',
|
|
75
|
-
borderColor: 'border.default',
|
|
76
|
-
borderRadius: 2,
|
|
77
|
-
minWidth: 0,
|
|
78
|
-
}, 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(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 }))] }));
|
|
79
64
|
/**
|
|
80
65
|
* What the durable engine's own report amounts to, in one line.
|
|
81
66
|
*
|
|
@@ -135,12 +120,7 @@ export const McpObservability = ({ errorState, routes, pane, onPaneChange, taskU
|
|
|
135
120
|
const engine = useMcpWorkflowsHealth({ enabled: pane === 'live' });
|
|
136
121
|
const live = useTasks({ status: 'working' }, { enabled: pane === 'live' });
|
|
137
122
|
const telemetryNotice = (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: ["This is telemetry: spans and metrics are sampled, kept for a short time and meant for understanding how a call ran. It is not the record of what was allowed \u2014", ' ', _jsx(Text, { as: "span", sx: { color: 'accent.fg', cursor: 'pointer' }, onClick: () => navigate(routes.audit), children: "the audit log" }), ' ', "is, and it is kept per plan and never changed."] }));
|
|
138
|
-
return (_jsxs(Box, {
|
|
139
|
-
display: 'flex',
|
|
140
|
-
gap: 2,
|
|
141
|
-
alignItems: 'center',
|
|
142
|
-
flexWrap: 'wrap',
|
|
143
|
-
}, children: [_jsx(TextInput, { size: "small", leadingVisual: SearchIcon, "aria-label": "Task or trace id", placeholder: "Task uid or trace id", value: find, sx: { minWidth: 320 }, onChange: event => setFind(event.currentTarget.value) }), _jsx(Button, { size: "small", onClick: () => {
|
|
123
|
+
return (_jsxs(Box, { display: "grid", gap: 3, minWidth: 0, children: [showTitle && (_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Observability" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "How the calls of your agents ran: where the time went, and how the service is behaving." })] })), _jsxs(SegmentedControl, { "aria-label": "Observability panes", size: "small", children: [_jsx(SegmentedControl.Button, { selected: pane === 'runs', onClick: () => onPaneChange('runs'), children: "Runs" }), _jsx(SegmentedControl.Button, { selected: pane === 'live', onClick: () => onPaneChange('live'), children: "Live" }), _jsx(SegmentedControl.Button, { selected: pane === 'metrics', onClick: () => onPaneChange('metrics'), children: "Metrics" })] }), telemetryNotice, pane === 'runs' && (_jsxs(Box, { display: "grid", gap: 3, children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(TextInput, { size: "small", leadingVisual: SearchIcon, "aria-label": "Task or trace id", placeholder: "Task uid or trace id", value: find, sx: { minWidth: 320 }, onChange: event => setFind(event.currentTarget.value) }), _jsx(Button, { size: "small", onClick: () => {
|
|
144
124
|
const value = find.trim();
|
|
145
125
|
if (!value) {
|
|
146
126
|
onSelect({});
|
|
@@ -151,81 +131,29 @@ export const McpObservability = ({ errorState, routes, pane, onPaneChange, taskU
|
|
|
151
131
|
onSelect(/^[0-9a-f]{32}$/i.test(value)
|
|
152
132
|
? { trace: value }
|
|
153
133
|
: { task: value });
|
|
154
|
-
}, 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, {
|
|
155
|
-
display: 'flex',
|
|
156
|
-
gap: 3,
|
|
157
|
-
alignItems: 'center',
|
|
158
|
-
flexWrap: 'wrap',
|
|
159
|
-
}, 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, { sx: {
|
|
160
|
-
border: '1px solid',
|
|
161
|
-
borderColor: 'border.default',
|
|
162
|
-
borderRadius: 2,
|
|
163
|
-
overflowX: 'auto',
|
|
164
|
-
}, children: (run.data?.tree ?? []).map(node => (_jsx(SpanRow, { node: node, depth: 0 }, node.span.span_id))) })] }))] })), pane === 'live' && (_jsxs(Box, { sx: { 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(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: [(() => {
|
|
165
135
|
const look = engineLook(engine.data, engine.isError);
|
|
166
136
|
const queues = engine.data?.queues ?? [];
|
|
167
|
-
return (_jsxs(Box, { sx: {
|
|
168
|
-
|
|
169
|
-
borderColor: 'border.default',
|
|
170
|
-
borderRadius: 2,
|
|
171
|
-
p: 3,
|
|
172
|
-
display: 'grid',
|
|
173
|
-
gap: 2,
|
|
174
|
-
}, children: [_jsxs(Box, { sx: {
|
|
175
|
-
display: 'flex',
|
|
176
|
-
gap: 2,
|
|
177
|
-
alignItems: 'center',
|
|
178
|
-
flexWrap: 'wrap',
|
|
179
|
-
}, 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, { sx: { display: 'grid', gap: 1 }, children: queues.map(queue => (_jsxs(Box, { sx: {
|
|
180
|
-
display: 'flex',
|
|
181
|
-
gap: 2,
|
|
182
|
-
alignItems: 'center',
|
|
183
|
-
fontSize: 0,
|
|
184
|
-
}, 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))) }))] }));
|
|
185
|
-
})(), _jsxs(Box, { sx: { 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, { sx: { 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, { sx: {
|
|
186
|
-
display: 'flex',
|
|
187
|
-
gap: 2,
|
|
188
|
-
alignItems: 'center',
|
|
189
|
-
flexWrap: 'wrap',
|
|
190
|
-
py: 1,
|
|
191
|
-
borderBottom: '1px solid',
|
|
192
|
-
borderColor: 'border.muted',
|
|
193
|
-
}, children: [_jsx(Label, { size: "small", variant: "success", children: "Working" }), _jsx(Text, { sx: { fontSize: 0 }, children: task.tool || 'Run' }), _jsx(Text, { sx: {
|
|
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))) }))] }));
|
|
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: {
|
|
194
139
|
fontSize: 0,
|
|
195
140
|
fontFamily: 'mono',
|
|
196
141
|
color: 'accent.fg',
|
|
197
142
|
cursor: 'pointer',
|
|
198
|
-
}, onClick: () => onSelect({ task: task.uid }), children: task.uid }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["started ", timeAgo(task.createdAt)] })] }, task.uid))))] })] })), pane === 'metrics' && (_jsx(Box, {
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
'repeat(2, 1fr)',
|
|
204
|
-
'repeat(4, 1fr)',
|
|
205
|
-
],
|
|
206
|
-
}, children: [_jsx(Sli, { label: "Availability", value: percentLabel(metrics.data?.slis.availability), note: `${metrics.data?.slis.samples.calls ?? 0} calls` }), _jsx(Sli, { label: "Call latency, p95", value: metrics.data?.slis.p95CallDurationMs === null ||
|
|
143
|
+
}, onClick: () => onSelect({ task: task.uid }), children: task.uid }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["started ", timeAgo(task.createdAt)] })] }, task.uid))))] })] })), pane === 'metrics' && (_jsx(Box, { display: "grid", gap: 3, children: metrics.isError ? (_jsx(McpErrorBlankslate, { state: errorState(metrics.error, 'Metrics'), onRetry: () => metrics.refetch() })) : metrics.isPending && !metrics.data ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : (_jsxs(_Fragment, { children: [_jsxs(Box, { display: "grid", gap: 3, gridTemplateColumns: [
|
|
144
|
+
'1fr',
|
|
145
|
+
'repeat(2, 1fr)',
|
|
146
|
+
'repeat(4, 1fr)',
|
|
147
|
+
], children: [_jsx(Sli, { label: "Availability", value: percentLabel(metrics.data?.slis.availability), note: `${metrics.data?.slis.samples.calls ?? 0} calls` }), _jsx(Sli, { label: "Call latency, p95", value: metrics.data?.slis.p95CallDurationMs === null ||
|
|
207
148
|
metrics.data?.slis.p95CallDurationMs === undefined
|
|
208
149
|
? 'Not measured'
|
|
209
150
|
: durationLabel(metrics.data.slis.p95CallDurationMs) }), _jsx(Sli, { label: "Task success", value: percentLabel(metrics.data?.slis.taskSuccessRate), note: `${metrics.data?.slis.samples.tasks ?? 0} tasks` }), _jsx(Sli, { label: "Sandbox launch, p95", value: Object.keys(metrics.data?.slis.p95SandboxLaunchSeconds ?? {}).length === 0
|
|
210
151
|
? 'Not measured'
|
|
211
152
|
: Object.entries(metrics.data?.slis.p95SandboxLaunchSeconds ?? {})
|
|
212
153
|
.map(([provider, seconds]) => `${provider} ${seconds.toFixed(1)}s`)
|
|
213
|
-
.join(' · '), note: `${metrics.data?.slis.samples.launches ?? 0} launches` })] }), _jsx(Box, {
|
|
214
|
-
border: '1px solid',
|
|
215
|
-
borderColor: 'border.default',
|
|
216
|
-
borderRadius: 2,
|
|
217
|
-
overflowX: 'auto',
|
|
218
|
-
}, children: MCP_METRIC_CATALOG.map(name => {
|
|
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 => {
|
|
219
155
|
const reporting = metrics.data?.reporting.includes(name) ?? false;
|
|
220
|
-
return (_jsxs(Box, { sx: {
|
|
221
|
-
display: 'flex',
|
|
222
|
-
alignItems: 'center',
|
|
223
|
-
gap: 3,
|
|
224
|
-
py: 1,
|
|
225
|
-
px: 2,
|
|
226
|
-
borderBottom: '1px solid',
|
|
227
|
-
borderColor: 'border.muted',
|
|
228
|
-
}, children: [_jsx(Text, { sx: { fontSize: 0, fontFamily: 'mono', flex: 1 }, children: name }), _jsx(Text, { sx: {
|
|
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: {
|
|
229
157
|
fontSize: 0,
|
|
230
158
|
color: reporting ? 'success.fg' : 'fg.muted',
|
|
231
159
|
}, children: reporting ? 'reporting' : 'no point' })] }, name));
|
|
@@ -25,20 +25,13 @@ export const NotebookRuns = ({ notebookUid, routes, limit = 20, }) => {
|
|
|
25
25
|
const runs = useNotebookTasks(notebookUid);
|
|
26
26
|
const tasks = orderedRuns(runs.data?.items ?? []).slice(0, limit);
|
|
27
27
|
if (runs.isLoading) {
|
|
28
|
-
return (_jsx(Box, {
|
|
28
|
+
return (_jsx(Box, { display: "flex", justifyContent: "center", p: 3, children: _jsx(Spinner, { size: "small" }) }));
|
|
29
29
|
}
|
|
30
|
-
return (_jsxs(Box, {
|
|
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, {
|
|
33
|
-
|
|
34
|
-
gap:
|
|
35
|
-
p: 2,
|
|
36
|
-
borderRadius: 2,
|
|
37
|
-
border: '1px solid',
|
|
38
|
-
borderColor: task.status === 'input_required'
|
|
39
|
-
? 'attention.emphasis'
|
|
40
|
-
: 'border.default',
|
|
41
|
-
}, children: [_jsxs(Box, { sx: { 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, { sx: { 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));
|
|
32
|
+
return (_jsxs(Box, { display: "grid", gap: 1, p: 2, borderRadius: 2, border: "1px solid", borderColor: task.status === 'input_required'
|
|
33
|
+
? 'attention.emphasis'
|
|
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));
|
|
42
35
|
}))] }));
|
|
43
36
|
};
|
|
44
37
|
export default NotebookRuns;
|
|
@@ -80,18 +80,12 @@ export const OrganizationPolicy = ({ errorState, orgUid, readOnly = false, showT
|
|
|
80
80
|
return (_jsx(McpErrorBlankslate, { state: errorState(layer.error, "The organization's MCP policy"), onRetry: () => layer.refetch() }));
|
|
81
81
|
}
|
|
82
82
|
if (layer.isPending && layer.data === undefined) {
|
|
83
|
-
return (_jsx(Box, {
|
|
83
|
+
return (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) }));
|
|
84
84
|
}
|
|
85
|
-
return (_jsxs(Box, {
|
|
85
|
+
return (_jsxs(Box, { display: "grid", gap: 3, minWidth: 0, maxWidth: "52rem", children: [showTitle && (_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Organization Policy" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "What this organization narrows for every agent acting in it. Each layer only narrows \u2014 a team, or a person, can be stricter than this and never looser." })] })), conflict && (_jsxs(Flash, { variant: "warning", children: [_jsx(Text, { sx: { fontSize: 1 }, children: conflict }), _jsx(Box, { mt: 2, children: _jsx(Button, { size: "small", onClick: () => {
|
|
86
86
|
setConflict('');
|
|
87
87
|
layer.refetch();
|
|
88
|
-
}, children: "Read it again" }) })] })), refusal && (_jsx(Flash, { variant: "danger", children: _jsx(Text, { sx: { fontSize: 1 }, children: refusal }) })), _jsx(PolicyForm, { draft: draft, onChange: set, disabled: readOnly, belowAllowedClients: _jsx(AdmittedClients, { scope: "organization", subjectUid: orgUid, edited: draft.allowedClients !== stored.allowedClients }) }), !readOnly && (_jsxs(Box, {
|
|
89
|
-
borderTop: '1px solid',
|
|
90
|
-
borderColor: 'border.muted',
|
|
91
|
-
pt: 3,
|
|
92
|
-
display: 'grid',
|
|
93
|
-
gap: 2,
|
|
94
|
-
}, children: [_jsx(Text, { as: "h3", sx: { fontSize: 1, fontWeight: 'semibold', m: 0 }, children: "History" }), _jsx(PolicyHistory, { orgUid: orgUid, subjectUid: orgUid })] }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: "Only these rules can be stored. A rule the gateway does not enforce is refused rather than kept, so this page cannot promise something that never happens." }), removing && (_jsx(Dialog, { title: "Remove this policy?", onClose: () => setRemoving(false), footerButtons: [
|
|
88
|
+
}, children: "Read it again" }) })] })), refusal && (_jsx(Flash, { variant: "danger", children: _jsx(Text, { sx: { fontSize: 1 }, children: refusal }) })), _jsx(PolicyForm, { draft: draft, onChange: set, disabled: readOnly, belowAllowedClients: _jsx(AdmittedClients, { scope: "organization", subjectUid: orgUid, edited: draft.allowedClients !== stored.allowedClients }) }), !readOnly && (_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", children: [_jsx(Button, { variant: "primary", onClick: apply, disabled: !changed || save.isPending, children: "Save policy" }), changed && (_jsx(Button, { variant: "invisible", onClick: () => setDraft(stored), children: "Discard changes" })), layer.data && (_jsx(Box, { marginLeft: "auto", children: _jsx(Button, { variant: "danger", onClick: () => setRemoving(true), children: "Remove policy" }) }))] })), _jsxs(Box, { borderTop: "1px solid", borderColor: "border.muted", pt: 3, display: "grid", gap: 2, children: [_jsx(Text, { as: "h3", sx: { fontSize: 1, fontWeight: 'semibold', m: 0 }, children: "History" }), _jsx(PolicyHistory, { orgUid: orgUid, subjectUid: orgUid })] }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: "Only these rules can be stored. A rule the gateway does not enforce is refused rather than kept, so this page cannot promise something that never happens." }), removing && (_jsx(Dialog, { title: "Remove this policy?", onClose: () => setRemoving(false), footerButtons: [
|
|
95
89
|
{
|
|
96
90
|
buttonType: 'default',
|
|
97
91
|
content: 'Keep it',
|