@datalayer/core 1.2.18 → 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.
- 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.d.ts +10 -11
- package/lib/components/avatars/UserAvatar.js +23 -52
- package/lib/components/avatars/UserProfileAvatar.js +1 -1
- package/lib/components/avatars/avatarChoice.d.ts +42 -0
- package/lib/components/avatars/avatarChoice.js +65 -0
- package/lib/components/avatars/index.d.ts +1 -0
- package/lib/components/avatars/index.js +1 -0
- package/lib/components/billing/BillingEntitySelect.js +6 -48
- package/lib/components/checkout/StripeCheckout.js +33 -217
- package/lib/components/collaboration/LiveEditorCollaborators.d.ts +3 -4
- package/lib/components/collaboration/LiveEditorCollaborators.js +7 -5
- 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/emoji/faceEmojis.js +48 -0
- package/lib/components/emoji/fluent/loaders.js +46 -0
- package/lib/components/emoji/fluent/svg/1f30a.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f30a.js +5 -0
- package/lib/components/emoji/fluent/svg/1f310.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f310.js +5 -0
- package/lib/components/emoji/fluent/svg/1f324.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f324.js +5 -0
- package/lib/components/emoji/fluent/svg/1f326.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f326.js +5 -0
- package/lib/components/emoji/fluent/svg/1f327.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f327.js +5 -0
- package/lib/components/emoji/fluent/svg/1f33e.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f33e.js +5 -0
- package/lib/components/emoji/fluent/svg/1f372.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f372.js +5 -0
- package/lib/components/emoji/fluent/svg/1f373.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f373.js +5 -0
- package/lib/components/emoji/fluent/svg/1f39b.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f39b.js +5 -0
- package/lib/components/emoji/fluent/svg/1f3ab.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f3ab.js +5 -0
- package/lib/components/emoji/fluent/svg/1f41b.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f41b.js +5 -0
- package/lib/components/emoji/fluent/svg/1f441.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f441.js +5 -0
- package/lib/components/emoji/fluent/svg/1f465.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f465.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4b9.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4b9.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4be.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4be.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4c1.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4c1.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4c2.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4c2.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4c4.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4c4.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4d3.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4d3.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4d6.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4d6.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4dc.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4dc.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4e1.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4e1.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4e2.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4e2.js +5 -0
- package/lib/components/emoji/fluent/svg/1f4e7.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f4e7.js +5 -0
- package/lib/components/emoji/fluent/svg/1f500.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f500.js +5 -0
- package/lib/components/emoji/fluent/svg/1f501.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f501.js +5 -0
- package/lib/components/emoji/fluent/svg/1f504.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f504.js +5 -0
- package/lib/components/emoji/fluent/svg/1f52d.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f52d.js +5 -0
- package/lib/components/emoji/fluent/svg/1f552.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f552.js +5 -0
- package/lib/components/emoji/fluent/svg/1f58b.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f58b.js +5 -0
- package/lib/components/emoji/fluent/svg/1f5b2.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f5b2.js +5 -0
- package/lib/components/emoji/fluent/svg/1f5c3.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f5c3.js +5 -0
- package/lib/components/emoji/fluent/svg/1f5d1.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f5d1.js +5 -0
- package/lib/components/emoji/fluent/svg/1f5dc.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f5dc.js +5 -0
- package/lib/components/emoji/fluent/svg/1f604.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f604.js +5 -0
- package/lib/components/emoji/fluent/svg/1f917.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f917.js +5 -0
- package/lib/components/emoji/fluent/svg/1f9d1-200d-2696.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1f9d1-200d-2696.js +5 -0
- package/lib/components/emoji/fluent/svg/1fa79.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1fa79.js +5 -0
- package/lib/components/emoji/fluent/svg/1fa9d.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1fa9d.js +5 -0
- package/lib/components/emoji/fluent/svg/1fa9f.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/1fa9f.js +5 -0
- package/lib/components/emoji/fluent/svg/23f3.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/23f3.js +5 -0
- package/lib/components/emoji/fluent/svg/2611.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/2611.js +5 -0
- package/lib/components/emoji/fluent/svg/2702.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/2702.js +5 -0
- package/lib/components/emoji/fluent/svg/270f.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/270f.js +5 -0
- package/lib/components/emoji/fluent/svg/2728.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/2728.js +5 -0
- package/lib/components/emoji/fluent/svg/2b1c.d.ts +2 -0
- package/lib/components/emoji/fluent/svg/2b1c.js +5 -0
- 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.d.ts +24 -1
- package/lib/components/principal/PrincipalAppearance.js +107 -80
- package/lib/components/principal/PrincipalAvatar.d.ts +5 -7
- package/lib/components/principal/PrincipalAvatar.js +12 -38
- package/lib/components/principal/PrincipalBadge.js +3 -13
- package/lib/components/principal/PrincipalBanner.js +4 -32
- package/lib/components/principal/PrincipalDetailsOverlay.d.ts +4 -7
- package/lib/components/principal/PrincipalDetailsOverlay.js +8 -24
- 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/unlinkIAMProvider.d.ts +22 -0
- package/lib/hooks/unlinkIAMProvider.js +24 -0
- package/lib/hooks/useAuthorization.js +6 -1
- package/lib/hooks/useCache.d.ts +8 -1
- package/lib/hooks/useCache.js +35 -4
- package/lib/hooks/useNavigate.js +8 -2
- 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/IAMProviderLinked.d.ts +9 -0
- package/lib/models/IAMProviderLinked.js +34 -5
- package/lib/models/McpTask.d.ts +18 -1
- package/lib/models/McpTask.js +15 -0
- package/lib/models/Person.d.ts +9 -0
- package/lib/models/Person.js +23 -0
- package/lib/models/Profile.d.ts +2 -2
- package/lib/models/User.js +5 -12
- package/lib/models/UserOnboarding.d.ts +9 -0
- package/lib/models/UserOnboarding.js +33 -0
- package/lib/otel/views/OtelLive.js +4 -62
- package/lib/otel/views/OtelLiveSpans.js +4 -29
- 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.js +9 -79
- 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 +12 -76
- package/lib/portable/index.d.ts +9 -0
- package/lib/portable/index.js +14 -0
- package/lib/portable/states.d.ts +39 -0
- package/lib/portable/states.js +71 -0
- package/lib/state/substates/NavigationState.d.ts +10 -6
- package/lib/state/substates/NavigationState.js +18 -8
- 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 +3 -11
- package/lib/views/mcp/AlertRules.js +4 -9
- package/lib/views/mcp/ApprovalQueue.js +5 -22
- package/lib/views/mcp/AuditLog.js +7 -44
- package/lib/views/mcp/ConnectedAgents.js +1 -6
- package/lib/views/mcp/EnterpriseConsole.js +11 -24
- package/lib/views/mcp/IdentityProviders.js +7 -31
- package/lib/views/mcp/McpDashboard.js +15 -31
- package/lib/views/mcp/McpHome.js +8 -55
- package/lib/views/mcp/McpObservability.js +14 -86
- package/lib/views/mcp/NotebookRuns.js +6 -13
- package/lib/views/mcp/OrganizationPolicy.js +3 -9
- package/lib/views/mcp/OrganizationUsage.js +5 -12
- package/lib/views/mcp/PersonalPolicy.js +3 -3
- package/lib/views/mcp/Policies.js +6 -47
- package/lib/views/mcp/PolicyForm.js +1 -9
- package/lib/views/mcp/PolicyHistory.js +2 -8
- package/lib/views/mcp/RunDetail.d.ts +1 -1
- package/lib/views/mcp/RunDetail.js +7 -26
- package/lib/views/mcp/ScimProvisioning.js +4 -16
- package/lib/views/mcp/ServiceAgents.js +4 -17
- package/lib/views/mcp/TeamPolicies.js +7 -19
- package/lib/views/mcp/ToolAccess.js +16 -23
- 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
|
@@ -15,7 +15,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
15
15
|
import { useState, useCallback, useRef, useMemo, useEffect, } from 'react';
|
|
16
16
|
import { PageConfig, URLExt } from '@jupyterlab/coreutils';
|
|
17
17
|
import { createGlobalStyle } from 'styled-components';
|
|
18
|
-
import { Box
|
|
18
|
+
import { Box } from '@datalayer/primer-addons';
|
|
19
|
+
import { Button, FormControl, Heading, Link, Spinner, Text, Textarea, TextInput, } from '@primer/react';
|
|
19
20
|
import { EyeIcon, EyeClosedIcon, KeyIcon, MailIcon, SignInIcon, TelescopeIcon, } from '@primer/octicons-react';
|
|
20
21
|
import { GithubMarkIcon, GoogleIcon, LinkedInGreyIcon, } from '@datalayer/icons-react';
|
|
21
22
|
import { useToast } from '../../hooks/index.js';
|
|
@@ -318,30 +319,12 @@ export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp,
|
|
|
318
319
|
}
|
|
319
320
|
}, [mfaUserUid, submit, submitMfa]);
|
|
320
321
|
const socialDisabled = socialLoading || loading || asDoc;
|
|
321
|
-
return (_jsxs(Box, { className: "signin-input-theme-scope", sx: {
|
|
322
|
-
display: 'flex',
|
|
323
|
-
alignItems: hideHero || compactDocMode || !fillHeight ? 'flex-start' : 'center',
|
|
324
|
-
justifyContent: 'center',
|
|
325
|
-
minHeight: hideHero || compactDocMode || !fillHeight ? 'auto' : '100vh',
|
|
326
|
-
bg: hideHero ? 'transparent' : 'canvas.default',
|
|
327
|
-
color: 'fg.default',
|
|
328
|
-
py: hideHero ? 0 : compactDocMode ? 2 : 4,
|
|
329
|
-
}, children: [_jsx(SignInInputGlobalStyle, {}), _jsxs(Box, { sx: {
|
|
330
|
-
width: '100%',
|
|
331
|
-
maxWidth: 440,
|
|
332
|
-
p: 0,
|
|
333
|
-
}, children: [!hideHero && (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
|
|
334
|
-
display: 'flex',
|
|
335
|
-
alignItems: 'center',
|
|
336
|
-
gap: 2,
|
|
337
|
-
mb: compactDocMode ? 2 : 3,
|
|
338
|
-
justifyContent: 'center',
|
|
339
|
-
}, children: [headingIcon, _jsx(Heading, { sx: { fontSize: 3 }, children: headingText })] }), _jsx(Text, { as: "p", sx: {
|
|
322
|
+
return (_jsxs(Box, { className: "signin-input-theme-scope", display: "flex", alignItems: hideHero || compactDocMode || !fillHeight ? 'flex-start' : 'center', justifyContent: "center", minHeight: hideHero || compactDocMode || !fillHeight ? 'auto' : '100vh', bg: hideHero ? 'transparent' : 'canvas.default', color: "fg.default", py: hideHero ? 0 : compactDocMode ? 2 : 4, children: [_jsx(SignInInputGlobalStyle, {}), _jsxs(Box, { width: "100%", maxWidth: 440, p: 0, children: [!hideHero && (_jsxs(_Fragment, { children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, mb: compactDocMode ? 2 : 3, justifyContent: "center", children: [headingIcon, _jsx(Heading, { sx: { fontSize: 3 }, children: headingText })] }), _jsx(Text, { as: "p", sx: {
|
|
340
323
|
fontSize: 1,
|
|
341
324
|
color: 'fg.muted',
|
|
342
325
|
mb: compactDocMode ? 2 : 3,
|
|
343
326
|
textAlign: 'center',
|
|
344
|
-
}, children: description })] })), (calloutTitle || calloutDescription) && (_jsxs(Box, {
|
|
327
|
+
}, children: description })] })), (calloutTitle || calloutDescription) && (_jsxs(Box, { mb: 3, textAlign: "center", children: [calloutTitle && (_jsx(Heading, { as: "h3", sx: { fontSize: 2, mb: 1 }, children: calloutTitle })), calloutDescription && (_jsx(Text, { sx: { color: 'fg.muted', fontSize: 1 }, children: calloutDescription }))] })), !mfaUserUid && (github || google || linkedin) && (_jsxs(_Fragment, { children: [github && (_jsx(Button, { block: true, size: "large", leadingVisual: pendingSocialProvider === 'github'
|
|
345
328
|
? () => _jsx(Spinner, { size: "small" })
|
|
346
329
|
: GithubMarkIcon, disabled: socialDisabled, onClick: () => startOAuthSignIn(OAUTH2_PROVIDERS.github), sx: {
|
|
347
330
|
mt: socialButtonMarginTop,
|
|
@@ -359,12 +342,7 @@ export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp,
|
|
|
359
342
|
mt: socialButtonMarginTop,
|
|
360
343
|
maxWidth: actionButtonMaxWidth,
|
|
361
344
|
mx: 'auto',
|
|
362
|
-
}, children: "Sign in with LinkedIn" }))] })), !mfaUserUid && !showPasswordForm && (_jsx(Box, {
|
|
363
|
-
display: 'flex',
|
|
364
|
-
alignItems: 'center',
|
|
365
|
-
justifyContent: 'space-between',
|
|
366
|
-
mt: 3,
|
|
367
|
-
}, children: [_jsx(Button, { variant: "primary", disabled: loading || asDoc || !handle || !password, onClick: submit, children: loading ? 'Signing in…' : 'Sign In' }), showForgotPassword && (_jsx(Link, { as: "button", sx: {
|
|
345
|
+
}, children: "Sign in with LinkedIn" }))] })), !mfaUserUid && !showPasswordForm && (_jsx(Box, { mt: 3, display: "flex", justifyContent: "center", children: _jsx(Button, { leadingVisual: KeyIcon, size: "large", block: true, disabled: asDoc || loading || socialLoading, onClick: () => setShowPasswordForm(true), sx: { maxWidth: actionButtonMaxWidth, mx: 'auto' }, children: passwordToggleLabel }) })), !mfaUserUid && showPasswordForm && (_jsxs(Box, { mt: 4, children: [_jsxs(FormControl, { required: true, sx: { mb: 3 }, children: [_jsx(FormControl.Label, { children: "Username" }), _jsx(TextInput, { autoFocus: true, block: true, placeholder: "Your username", value: handle, disabled: loading || asDoc, onChange: e => setHandle(e.target.value), onKeyDown: handleKeyDown })] }), _jsxs(FormControl, { required: true, sx: { mb: 3 }, children: [_jsx(FormControl.Label, { children: "Password" }), _jsx(TextInput, { block: true, placeholder: "Your password", type: showPassword ? 'text' : 'password', value: password, disabled: loading || asDoc, onChange: e => setPassword(e.target.value), onKeyDown: handleKeyDown, trailingAction: _jsx(TextInput.Action, { onClick: () => setShowPassword(!showPassword), disabled: loading || asDoc, icon: showPassword ? EyeClosedIcon : EyeIcon, "aria-label": showPassword ? 'Hide password' : 'Show password', sx: { color: 'var(--fgColor-muted)' } }) })] }), _jsxs(Box, { display: "flex", alignItems: "center", justifyContent: "space-between", mt: 3, children: [_jsx(Button, { variant: "primary", disabled: loading || asDoc || !handle || !password, onClick: submit, children: loading ? 'Signing in…' : 'Sign In' }), showForgotPassword && (_jsx(Link, { as: "button", sx: {
|
|
368
346
|
fontSize: 1,
|
|
369
347
|
cursor: asDoc ? 'not-allowed' : 'pointer',
|
|
370
348
|
background: 'none',
|
|
@@ -375,47 +353,13 @@ export const SignInSimple = ({ onSignIn, onApiKeySignIn, loginUrl: loginUrlProp,
|
|
|
375
353
|
return;
|
|
376
354
|
}
|
|
377
355
|
handleForgotPassword();
|
|
378
|
-
}, children: forgotPasswordLabel }))] })] })), mfaUserUid && (_jsxs(_Fragment, { children: [_jsxs(FormControl, { required: true, sx: { mb: 3, mt: 2 }, children: [_jsx(FormControl.Label, { children: "MFA Code" }), _jsx(TextInput, { autoFocus: true, block: true, placeholder: "Your MFA code", value: mfaCode, disabled: loading || asDoc, onChange: e => setMfaCode(e.target.value), onKeyDown: handleKeyDown })] }), _jsx(Button, { variant: "primary", block: true, disabled: loading || asDoc || !mfaCode.trim(), onClick: submitMfa, sx: { maxWidth: actionButtonMaxWidth, mx: 'auto' }, children: loading ? 'Validating…' : 'Validate MFA Code' })] })), error && (_jsx(Text, { sx: { color: 'danger.fg', fontSize: 1, mt: 3, display: 'block' }, children: error })), signUp && (_jsxs(Box, { sx: {
|
|
379
|
-
mt: 4,
|
|
380
|
-
pt: 4,
|
|
381
|
-
textAlign: 'center',
|
|
382
|
-
borderTop: '1px solid',
|
|
383
|
-
borderColor: 'border.muted',
|
|
384
|
-
}, children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2, mb: 2 }, children: signUpTitle }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, mb: 3 }, children: signUpDescription }), _jsx(Box, { sx: { display: 'flex', justifyContent: 'center' }, children: _jsx(Button, { variant: "primary", size: "large", leadingVisual: MailIcon, disabled: asDoc || loading, onClick: handleSignUp, children: signUpLabel }) })] })), apiKey && onApiKeySignIn && (_jsxs(_Fragment, { children: [_jsxs(Box, { sx: {
|
|
385
|
-
display: 'flex',
|
|
386
|
-
alignItems: 'center',
|
|
387
|
-
gap: 2,
|
|
388
|
-
my: 3,
|
|
389
|
-
}, children: [_jsx(Box, { sx: { flex: 1, height: '1px', bg: 'border.default' } }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "or" }), _jsx(Box, { sx: { flex: 1, height: '1px', bg: 'border.default' } })] }), _jsx(Button, { block: true, leadingVisual: KeyIcon, disabled: asDoc || loading || socialLoading, onClick: () => setShowApiKeyDialog(true), sx: { maxWidth: actionButtonMaxWidth, mx: 'auto' }, children: "Sign in with an API Key" }), showApiKeyDialog && (_jsx(Box, { role: "dialog", "aria-modal": "true", "aria-labelledby": "signin-api-key-title", onKeyDown: event => {
|
|
356
|
+
}, children: forgotPasswordLabel }))] })] })), mfaUserUid && (_jsxs(_Fragment, { children: [_jsxs(FormControl, { required: true, sx: { mb: 3, mt: 2 }, children: [_jsx(FormControl.Label, { children: "MFA Code" }), _jsx(TextInput, { autoFocus: true, block: true, placeholder: "Your MFA code", value: mfaCode, disabled: loading || asDoc, onChange: e => setMfaCode(e.target.value), onKeyDown: handleKeyDown })] }), _jsx(Button, { variant: "primary", block: true, disabled: loading || asDoc || !mfaCode.trim(), onClick: submitMfa, sx: { maxWidth: actionButtonMaxWidth, mx: 'auto' }, children: loading ? 'Validating…' : 'Validate MFA Code' })] })), error && (_jsx(Text, { sx: { color: 'danger.fg', fontSize: 1, mt: 3, display: 'block' }, children: error })), signUp && (_jsxs(Box, { mt: 4, pt: 4, textAlign: "center", borderTop: "1px solid", borderColor: "border.muted", children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2, mb: 2 }, children: signUpTitle }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, mb: 3 }, children: signUpDescription }), _jsx(Box, { display: "flex", justifyContent: "center", children: _jsx(Button, { variant: "primary", size: "large", leadingVisual: MailIcon, disabled: asDoc || loading, onClick: handleSignUp, children: signUpLabel }) })] })), apiKey && onApiKeySignIn && (_jsxs(_Fragment, { children: [_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, my: 3, children: [_jsx(Box, { flex: 1, height: "1px", bg: "border.default" }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "or" }), _jsx(Box, { flex: 1, height: "1px", bg: "border.default" })] }), _jsx(Button, { block: true, leadingVisual: KeyIcon, disabled: asDoc || loading || socialLoading, onClick: () => setShowApiKeyDialog(true), sx: { maxWidth: actionButtonMaxWidth, mx: 'auto' }, children: "Sign in with an API Key" }), showApiKeyDialog && (_jsx(Box, { role: "dialog", "aria-modal": "true", "aria-labelledby": "signin-api-key-title", onKeyDown: event => {
|
|
390
357
|
if (event.key === 'Escape') {
|
|
391
358
|
closeApiKeyDialog();
|
|
392
359
|
}
|
|
393
|
-
}, onClick: closeApiKeyDialog,
|
|
394
|
-
position: 'fixed',
|
|
395
|
-
inset: 0,
|
|
396
|
-
zIndex: 200,
|
|
397
|
-
p: 3,
|
|
398
|
-
bg: 'canvas.backdrop',
|
|
399
|
-
display: 'flex',
|
|
400
|
-
alignItems: 'center',
|
|
401
|
-
justifyContent: 'center',
|
|
402
|
-
}, children: _jsxs(Box, { as: "form", onClick: event => event.stopPropagation(), onSubmit: event => {
|
|
360
|
+
}, onClick: closeApiKeyDialog, position: "fixed", inset: 0, zIndex: 200, p: 3, bg: "canvas.backdrop", display: "flex", alignItems: "center", justifyContent: "center", children: _jsxs(Box, { as: "form", onClick: event => event.stopPropagation(), onSubmit: event => {
|
|
403
361
|
event.preventDefault();
|
|
404
362
|
handleApiKeyAuthenticate();
|
|
405
|
-
}, sx: {
|
|
406
|
-
width: 'min(560px, 100%)',
|
|
407
|
-
p: 3,
|
|
408
|
-
borderRadius: 2,
|
|
409
|
-
border: '1px solid',
|
|
410
|
-
borderColor: 'border.default',
|
|
411
|
-
bg: 'canvas.overlay',
|
|
412
|
-
color: 'fg.default',
|
|
413
|
-
boxShadow: 'shadow.large',
|
|
414
|
-
}, children: [_jsx(Heading, { id: "signin-api-key-title", sx: { fontSize: 2, mb: 2 }, children: "Enter your API Key" }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "API Key" }), _jsx(Textarea, { block: true, required: true, autoFocus: true, placeholder: "Paste your API key here", value: apiKeyValue, onInput: e => setApiKeyValue(e.currentTarget.value), ref: apiKeyRef })] }), _jsxs(Box, { sx: {
|
|
415
|
-
mt: 3,
|
|
416
|
-
display: 'flex',
|
|
417
|
-
justifyContent: 'flex-end',
|
|
418
|
-
gap: 2,
|
|
419
|
-
}, children: [_jsx(Button, { type: "button", onClick: closeApiKeyDialog, children: "Cancel" }), _jsx(Button, { type: "submit", variant: "primary", disabled: !apiKeyValue.trim(), children: "Authenticate" })] })] }) }))] }))] })] }));
|
|
363
|
+
}, width: "min(560px, 100%)", p: 3, borderRadius: 2, border: "1px solid", borderColor: "border.default", bg: "canvas.overlay", color: "fg.default", boxShadow: "shadow.large", children: [_jsx(Heading, { id: "signin-api-key-title", sx: { fontSize: 2, mb: 2 }, children: "Enter your API Key" }), _jsxs(FormControl, { required: true, children: [_jsx(FormControl.Label, { children: "API Key" }), _jsx(Textarea, { block: true, required: true, autoFocus: true, placeholder: "Paste your API key here", value: apiKeyValue, onInput: e => setApiKeyValue(e.currentTarget.value), ref: apiKeyRef })] }), _jsxs(Box, { mt: 3, display: "flex", justifyContent: "flex-end", gap: 2, children: [_jsx(Button, { type: "button", onClick: closeApiKeyDialog, children: "Cancel" }), _jsx(Button, { type: "submit", variant: "primary", disabled: !apiKeyValue.trim(), children: "Authenticate" })] })] }) }))] }))] })] }));
|
|
420
364
|
};
|
|
421
365
|
export default SignInSimple;
|
|
@@ -8,20 +8,7 @@ const Row = ({ client }) => {
|
|
|
8
8
|
const unusable = client.kind === 'unusable';
|
|
9
9
|
const icon = unusable ? (_jsx(QuestionIcon, {})) : unreadable ? (_jsx(AlertIcon, {})) : client.kind === 'hostname' ? (_jsx(GlobeIcon, {})) : (_jsx(CheckCircleIcon, {}));
|
|
10
10
|
const tone = unusable || unreadable ? 'danger.fg' : 'fg.muted';
|
|
11
|
-
return (_jsxs(Box, { sx: {
|
|
12
|
-
display: 'grid',
|
|
13
|
-
gridTemplateColumns: 'auto 1fr',
|
|
14
|
-
gap: 2,
|
|
15
|
-
alignItems: 'start',
|
|
16
|
-
py: 2,
|
|
17
|
-
borderTop: '1px solid',
|
|
18
|
-
borderColor: 'border.muted',
|
|
19
|
-
}, children: [_jsx(Box, { sx: { color: tone, pt: '2px' }, children: icon }), _jsxs(Box, { sx: { display: 'grid', gap: 1, minWidth: 0 }, children: [_jsxs(Box, { sx: {
|
|
20
|
-
display: 'flex',
|
|
21
|
-
gap: 2,
|
|
22
|
-
alignItems: 'center',
|
|
23
|
-
flexWrap: 'wrap',
|
|
24
|
-
}, children: [client.clientName && (_jsx(Text, { sx: { fontWeight: 'semibold' }, children: client.clientName })), client.kind === 'hostname' && (_jsx(Label, { variant: "accent", size: "small", children: "Whole host" })), client.localhostOnly && (
|
|
11
|
+
return (_jsxs(Box, { display: "grid", gridTemplateColumns: "auto 1fr", gap: 2, alignItems: "start", py: 2, borderTop: "1px solid", borderColor: "border.muted", children: [_jsx(Box, { color: tone, pt: "2px", children: icon }), _jsxs(Box, { display: "grid", gap: 1, minWidth: 0, children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [client.clientName && (_jsx(Text, { sx: { fontWeight: 'semibold' }, children: client.clientName })), client.kind === 'hostname' && (_jsx(Label, { variant: "accent", size: "small", children: "Whole host" })), client.localhostOnly && (
|
|
25
12
|
// Worth a label of its own: every redirect goes to the reader's
|
|
26
13
|
// own machine, and a document cannot prove which local program
|
|
27
14
|
// is listening on the port.
|
|
@@ -35,7 +22,7 @@ const Row = ({ client }) => {
|
|
|
35
22
|
export const AdmittedClients = ({ scope, subjectUid, edited = false, }) => {
|
|
36
23
|
const described = useAdmittedClients(scope, subjectUid);
|
|
37
24
|
if (described.isPending && !described.data) {
|
|
38
|
-
return (_jsx(Box, {
|
|
25
|
+
return (_jsx(Box, { display: "flex", justifyContent: "center", py: 3, children: _jsx(Spinner, { size: "small" }) }));
|
|
39
26
|
}
|
|
40
27
|
// An error here is not worth a blankslate: the field above still works and
|
|
41
28
|
// the policy is unaffected. Saying nothing would be worse than saying it
|
|
@@ -54,6 +41,6 @@ export const AdmittedClients = ({ scope, subjectUid, edited = false, }) => {
|
|
|
54
41
|
return (_jsx(Text, { as: "p", sx: { fontSize: 0, color: 'fg.muted', m: 0 }, children: answer.detail ??
|
|
55
42
|
'This layer names no client allowlist, so every client is admitted by it.' }));
|
|
56
43
|
}
|
|
57
|
-
return (_jsxs(Box, {
|
|
44
|
+
return (_jsxs(Box, { display: "grid", gap: 1, children: [edited && (_jsxs(Text, { as: "p", sx: { fontSize: 0, color: 'attention.fg', m: 0 }, children: ["Describing the ", _jsx("strong", { children: "saved" }), " list. Save to check what you have just typed."] })), answer.clients.map(client => (_jsx(Row, { client: client }, client.entry)))] }));
|
|
58
45
|
};
|
|
59
46
|
export default AdmittedClients;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useMemo, useState } from 'react';
|
|
3
3
|
import { Button, Flash, FormControl, Heading, Spinner, Text, TextInput, } 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 { useAuditSettings, useSetAuditSettings } from '../../hooks/useMcp.js';
|
|
7
7
|
import { useToast } from '../../hooks/index.js';
|
|
@@ -60,16 +60,8 @@ export const AlertDestinations = ({ errorState, orgUid, readOnly = false, }) =>
|
|
|
60
60
|
return (_jsx(McpErrorBlankslate, { state: errorState(settings.error, 'Alert destinations'), onRetry: () => settings.refetch() }));
|
|
61
61
|
}
|
|
62
62
|
if (settings.isPending && settings.data === undefined) {
|
|
63
|
-
return (_jsx(Box, {
|
|
63
|
+
return (_jsx(Box, { display: "flex", justifyContent: "center", py: 4, children: _jsx(Spinner, {}) }));
|
|
64
64
|
}
|
|
65
|
-
return (_jsxs(Box, { sx: {
|
|
66
|
-
display: 'grid',
|
|
67
|
-
gap: 3,
|
|
68
|
-
maxWidth: '42rem',
|
|
69
|
-
p: 3,
|
|
70
|
-
border: '1px solid',
|
|
71
|
-
borderColor: 'border.default',
|
|
72
|
-
borderRadius: 2,
|
|
73
|
-
}, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2, mb: 1 }, children: "Where alerts go" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "Set once for the organization, not per rule \u2014 a URL repeated on twenty rules is nineteen places to forget when it rotates. Every firing also appears in the app, and that copy is sent first so it is not lost when one of these is down." })] }), refusal && (_jsx(Flash, { variant: "danger", children: _jsx(Text, { sx: { fontSize: 1 }, children: refusal }) })), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Email" }), _jsx(TextInput, { block: true, disabled: readOnly, value: draft.alertEmails, onChange: event => set('alertEmails', event.target.value), placeholder: "ops@example.co, oncall@example.co" }), _jsx(FormControl.Caption, { children: "Comma-separated, up to twenty. An alert list is the people who want to know, not a mailing list \u2014 a firing that emails two hundred people is a firing that gets the rule switched off." })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Slack" }), _jsx(TextInput, { block: true, disabled: readOnly, value: draft.alertSlackWebhookUrl, onChange: event => set('alertSlackWebhookUrl', event.target.value), placeholder: "https://hooks.slack.com/services/\u2026" }), _jsx(FormControl.Caption, { children: "A Slack incoming webhook, and only Slack\u2019s \u2014 anything else belongs in the field below. Through this one Slack gets a coloured attachment with the reading, the severity and the scope as separate fields; through the generic webhook it shows one grey line." })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Webhook" }), _jsx(TextInput, { block: true, disabled: readOnly, value: draft.alertWebhookUrl, onChange: event => set('alertWebhookUrl', event.target.value), placeholder: "https://events.pagerduty.com/\u2026" }), _jsxs(FormControl.Caption, { children: ["Anything that takes a JSON POST: PagerDuty, a chat relay, your own endpoint. ", _jsx("strong", { children: "https only" }), " \u2014 an alert names your organization and what its agents did. It carries no credential."] })] }), !readOnly && (_jsxs(Box, { sx: { display: 'flex', gap: 2 }, children: [_jsx(Button, { variant: "primary", onClick: apply, disabled: !changed || save.isPending, children: "Save destinations" }), changed && (_jsx(Button, { variant: "invisible", onClick: () => setDraft(stored), children: "Discard changes" }))] })), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: ["Each copy is attempted on its own: if the webhook is down you still get the email. A copy that fails is recorded and", ' ', _jsx("strong", { children: "not retried" }), " \u2014 retrying a notice against an endpoint that is down turns its outage into a loop against it, and the alert is already in the app."] })] }));
|
|
65
|
+
return (_jsxs(Card, { border: true, shadow: "none", display: "grid", gap: 3, maxWidth: "42rem", p: 3, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2, mb: 1 }, children: "Where alerts go" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "Set once for the organization, not per rule \u2014 a URL repeated on twenty rules is nineteen places to forget when it rotates. Every firing also appears in the app, and that copy is sent first so it is not lost when one of these is down." })] }), refusal && (_jsx(Flash, { variant: "danger", children: _jsx(Text, { sx: { fontSize: 1 }, children: refusal }) })), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Email" }), _jsx(TextInput, { block: true, disabled: readOnly, value: draft.alertEmails, onChange: event => set('alertEmails', event.target.value), placeholder: "ops@example.co, oncall@example.co" }), _jsx(FormControl.Caption, { children: "Comma-separated, up to twenty. An alert list is the people who want to know, not a mailing list \u2014 a firing that emails two hundred people is a firing that gets the rule switched off." })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Slack" }), _jsx(TextInput, { block: true, disabled: readOnly, value: draft.alertSlackWebhookUrl, onChange: event => set('alertSlackWebhookUrl', event.target.value), placeholder: "https://hooks.slack.com/services/\u2026" }), _jsx(FormControl.Caption, { children: "A Slack incoming webhook, and only Slack\u2019s \u2014 anything else belongs in the field below. Through this one Slack gets a coloured attachment with the reading, the severity and the scope as separate fields; through the generic webhook it shows one grey line." })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Webhook" }), _jsx(TextInput, { block: true, disabled: readOnly, value: draft.alertWebhookUrl, onChange: event => set('alertWebhookUrl', event.target.value), placeholder: "https://events.pagerduty.com/\u2026" }), _jsxs(FormControl.Caption, { children: ["Anything that takes a JSON POST: PagerDuty, a chat relay, your own endpoint. ", _jsx("strong", { children: "https only" }), " \u2014 an alert names your organization and what its agents did. It carries no credential."] })] }), !readOnly && (_jsxs(Box, { display: "flex", gap: 2, children: [_jsx(Button, { variant: "primary", onClick: apply, disabled: !changed || save.isPending, children: "Save destinations" }), changed && (_jsx(Button, { variant: "invisible", onClick: () => setDraft(stored), children: "Discard changes" }))] })), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: ["Each copy is attempted on its own: if the webhook is down you still get the email. A copy that fails is recorded and", ' ', _jsx("strong", { children: "not retried" }), " \u2014 retrying a notice against an endpoint that is down turns its outage into a loop against it, and the alert is already in the app."] })] }));
|
|
74
66
|
};
|
|
75
67
|
export default AlertDestinations;
|
|
@@ -166,7 +166,7 @@ export const AlertRules = ({ errorState, orgUid, readOnly = false, showTitle = t
|
|
|
166
166
|
id: 'condition',
|
|
167
167
|
rowHeader: true,
|
|
168
168
|
width: 'growCollapse',
|
|
169
|
-
renderCell: row => (_jsxs(Box, {
|
|
169
|
+
renderCell: row => (_jsxs(Box, { display: "grid", children: [_jsxs(Text, { sx: { fontSize: 1 }, children: [labelOf(row.condition), " ", operatorOf(row.operator), " ", row.threshold] }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["over ", windowOf(row.windowSeconds), row.scopeKind !== 'organization' && ` · this ${row.scopeKind}`] })] })),
|
|
170
170
|
},
|
|
171
171
|
{
|
|
172
172
|
header: 'Severity',
|
|
@@ -201,12 +201,7 @@ export const AlertRules = ({ errorState, orgUid, readOnly = false, showTitle = t
|
|
|
201
201
|
return (_jsx(McpErrorBlankslate, { state: errorState(rules.error, 'Alert rules'), onRetry: () => rules.refetch() }));
|
|
202
202
|
}
|
|
203
203
|
const chosen = ALERT_CONDITIONS.find(entry => entry.name === draft.condition);
|
|
204
|
-
return (_jsxs(Box, {
|
|
205
|
-
display: 'flex',
|
|
206
|
-
alignItems: 'start',
|
|
207
|
-
justifyContent: 'space-between',
|
|
208
|
-
gap: 3,
|
|
209
|
-
}, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Alerts" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "What this organization asked to be told about. Each rule is checked once a minute and fires at most once per window." })] }), !readOnly && (_jsx(Button, { variant: "primary", onClick: openCreate, children: "New rule" }))] })), rules.isPending && !rules.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: "alert-rules", children: "Rules" }), _jsx(Table.Subtitle, { as: "p", id: "alert-rules-subtitle", children: "A rule switched off stays here and stops being evaluated." }), _jsx(DataTable, { "aria-labelledby": "alert-rules", "aria-describedby": "alert-rules-subtitle", data: rows, columns: columns })] })) : (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(BellIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "Nothing is watched" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Runs are recorded either way. A rule is what turns a number somebody would have to go and look at into something that reaches you." }) }), !readOnly && (_jsx(Button, { size: "small", onClick: openCreate, children: "New rule" }))] })), _jsx(AlertDestinations, { errorState: errorState, orgUid: orgUid, readOnly: readOnly }), (creating || editing) && (_jsx(Dialog, { title: editing ? 'Edit rule' : 'New alert rule', onClose: close, returnFocusRef: returnFocusRef, footerButtons: [
|
|
204
|
+
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: "Alerts" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "What this organization asked to be told about. Each rule is checked once a minute and fires at most once per window." })] }), !readOnly && (_jsx(Button, { variant: "primary", onClick: openCreate, children: "New rule" }))] })), rules.isPending && !rules.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: "alert-rules", children: "Rules" }), _jsx(Table.Subtitle, { as: "p", id: "alert-rules-subtitle", children: "A rule switched off stays here and stops being evaluated." }), _jsx(DataTable, { "aria-labelledby": "alert-rules", "aria-describedby": "alert-rules-subtitle", data: rows, columns: columns })] })) : (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(BellIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "Nothing is watched" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Runs are recorded either way. A rule is what turns a number somebody would have to go and look at into something that reaches you." }) }), !readOnly && (_jsx(Button, { size: "small", onClick: openCreate, children: "New rule" }))] })), _jsx(AlertDestinations, { errorState: errorState, orgUid: orgUid, readOnly: readOnly }), (creating || editing) && (_jsx(Dialog, { title: editing ? 'Edit rule' : 'New alert rule', onClose: close, returnFocusRef: returnFocusRef, footerButtons: [
|
|
210
205
|
{ buttonType: 'default', content: 'Cancel', onClick: close },
|
|
211
206
|
{
|
|
212
207
|
buttonType: 'default',
|
|
@@ -220,7 +215,7 @@ export const AlertRules = ({ errorState, orgUid, readOnly = false, showTitle = t
|
|
|
220
215
|
onClick: apply,
|
|
221
216
|
disabled: create.isPending || update.isPending,
|
|
222
217
|
},
|
|
223
|
-
], children: _jsxs(Box, {
|
|
218
|
+
], children: _jsxs(Box, { display: "grid", gap: 3, children: [refusal && (_jsx(Flash, { variant: "danger", children: _jsx(Text, { sx: { fontSize: 1 }, children: refusal }) })), trial && (_jsxs(Flash, { variant: trial.readable ? 'default' : 'warning', children: [_jsx(Text, { sx: { fontSize: 1 }, children: trial.readable
|
|
224
219
|
? `Right now it reads ${trial.value}, so this rule ${trial.wouldFire ? 'would fire' : 'would not fire'}.`
|
|
225
220
|
: 'This cannot be read at the moment, so the rule would ' +
|
|
226
221
|
'not fire — and a rule that never fires looks exactly ' +
|
|
@@ -228,7 +223,7 @@ export const AlertRules = ({ errorState, orgUid, readOnly = false, showTitle = t
|
|
|
228
223
|
// A condition nothing reads would be stored, evaluated
|
|
229
224
|
// every minute and never fire. Offering it as though it
|
|
230
225
|
// worked is the silence rules exist to break.
|
|
231
|
-
disabled: !condition.measurable, children: [condition.label, condition.measurable ? '' : ' — not measurable yet'] }, condition.name))) }), chosen && (_jsx(FormControl.Caption, { children: chosen.help }))] }), _jsxs(Box, {
|
|
226
|
+
disabled: !condition.measurable, children: [condition.label, condition.measurable ? '' : ' — not measurable yet'] }, condition.name))) }), chosen && (_jsx(FormControl.Caption, { children: chosen.help }))] }), _jsxs(Box, { display: "grid", gap: 2, gridTemplateColumns: "1fr 1fr", children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Comparison" }), _jsx(Select, { value: draft.operator, onChange: event => set('operator', event.target.value), children: ALERT_OPERATORS.map(operator => (_jsx(Select.Option, { value: operator.name, children: operator.label }, operator.name))) })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Threshold" }), _jsx(TextInput, { block: true, type: "number", value: String(draft.threshold), onChange: event => set('threshold', Number(event.target.value)) })] })] }), _jsxs(Box, { display: "grid", gap: 2, gridTemplateColumns: "1fr 1fr", children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Over" }), _jsx(Select, { value: String(draft.windowSeconds), onChange: event => set('windowSeconds', Number(event.target.value)), children: WINDOWS.map(window => (_jsx(Select.Option, { value: String(window.seconds), children: window.label }, window.seconds))) }), _jsx(FormControl.Caption, { children: "It fires once per window, not once per check." })] }), _jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Severity" }), _jsx(Select, { value: draft.severity, onChange: event => set('severity', event.target.value), children: ALERT_SEVERITIES.map(severity => (_jsx(Select.Option, { value: severity, children: severity }, severity))) }), _jsx(FormControl.Caption, { children: "Sets the colour in Slack and the wording of the notice." })] })] }), _jsxs(Box, { display: "grid", gap: 2, gridTemplateColumns: "1fr 1fr", children: [_jsxs(FormControl, { children: [_jsx(FormControl.Label, { children: "Measured over" }), _jsxs(Select, { value: draft.scopeKind, onChange: event => set('scopeKind', event.target.value), children: [_jsx(Select.Option, { value: "organization", children: "The whole organization" }), _jsx(Select.Option, { value: "team", children: "One team" }), _jsx(Select.Option, { value: "user", children: "One person" }), _jsx(Select.Option, { value: "agent", children: "One agent" })] })] }), draft.scopeKind !== 'organization' && (_jsxs(FormControl, { required: true, children: [_jsxs(FormControl.Label, { children: ["Which ", draft.scopeKind] }), _jsx(TextInput, { block: true, value: draft.scopeUid, onChange: event => set('scopeUid', event.target.value), placeholder: "uid" }), _jsx(FormControl.Caption, { children: "Without one the rule would be measured over the whole organization under a name saying otherwise." })] }))] })] }) })), removing && (_jsx(Dialog, { title: "Remove this rule?", onClose: () => setRemoving(null), returnFocusRef: returnFocusRef, footerButtons: [
|
|
232
227
|
{
|
|
233
228
|
buttonType: 'default',
|
|
234
229
|
content: 'Keep it',
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState } from 'react';
|
|
3
3
|
import { Button, Heading, Label, RelativeTime, SegmentedControl, Spinner, Text, Textarea, } 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
|
-
import { useDecideMcpApproval, useMcpApprovals
|
|
6
|
+
import { useDecideMcpApproval, useMcpApprovals } from '../../hooks/useContents.js';
|
|
7
7
|
/** How each state of an approval is drawn. */
|
|
8
8
|
export const APPROVAL_LOOK = {
|
|
9
9
|
pending: { label: 'Waiting on you', variant: 'attention' },
|
|
@@ -54,32 +54,15 @@ export const ApprovalQueue = ({ errorState, sourceUid, }) => {
|
|
|
54
54
|
const approvals = useMcpApprovals(status, sourceUid ? { sourceUid } : {});
|
|
55
55
|
const decide = useDecideMcpApproval();
|
|
56
56
|
const items = approvals.data?.items ?? [];
|
|
57
|
-
return (_jsxs(Box, {
|
|
57
|
+
return (_jsxs(Box, { display: "grid", gap: 3, minWidth: 0, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h3", sx: { fontSize: 2, mb: 1 }, children: "Approvals" }), _jsx(Text, { as: "p", sx: { fontSize: 1, color: 'fg.muted', m: 0 }, children: "A source set to require approval stops each call until you allow it. An approval covers the exact arguments below and nothing else, so a second call with different arguments asks again." })] }), _jsx(SegmentedControl, { "aria-label": "Which approvals", size: "small", children: APPROVAL_FILTERS.map(state => (_jsx(SegmentedControl.Button, { selected: status === state, onClick: () => setStatus(state), children: APPROVAL_LOOK[state].label }, state))) }), approvals.isError ? (_jsx(McpErrorBlankslate, { state: errorState(approvals.error, 'The approvals'), onRetry: () => approvals.refetch() })) : approvals.isPending ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 5, children: _jsx(Spinner, {}) })) : items.length === 0 ? (_jsx(Text, { sx: { fontSize: 1, color: 'fg.muted' }, children: status === 'pending'
|
|
58
58
|
? 'Nothing is waiting on you.'
|
|
59
59
|
: `No ${APPROVAL_LOOK[status].label.toLowerCase()} approvals.` })) : (items.map(approval => {
|
|
60
60
|
const look = approvalLook(approval);
|
|
61
61
|
const decidable = isDecidable(approval);
|
|
62
|
-
return (_jsxs(Box, { sx: {
|
|
63
|
-
border: '1px solid',
|
|
64
|
-
borderColor: decidable ? 'attention.emphasis' : 'border.default',
|
|
65
|
-
borderRadius: 2,
|
|
66
|
-
p: 3,
|
|
67
|
-
display: 'grid',
|
|
68
|
-
gap: 2,
|
|
69
|
-
minWidth: 0,
|
|
70
|
-
}, children: [_jsxs(Box, { sx: { display: 'flex', gap: 2, alignItems: 'center', flexWrap: 'wrap' }, children: [_jsx(Label, { size: "small", variant: look.variant, children: look.label }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: approval.tool }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', fontFamily: 'mono' }, children: approval.actorUid }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["asked ", _jsx(RelativeTime, { datetime: approval.createdAt })] }), decidable && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["expires ", _jsx(RelativeTime, { datetime: approval.expiresAt })] }))] }), _jsx(Box, { as: "pre", sx: {
|
|
71
|
-
fontFamily: 'mono',
|
|
72
|
-
fontSize: 0,
|
|
73
|
-
whiteSpace: 'pre-wrap',
|
|
74
|
-
overflowX: 'auto',
|
|
75
|
-
bg: 'canvas.subtle',
|
|
76
|
-
borderRadius: 2,
|
|
77
|
-
p: 2,
|
|
78
|
-
m: 0,
|
|
79
|
-
}, children: JSON.stringify(approval.argumentsRedacted, null, 2) }), approval.destinationUri && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Writes to", ' ', _jsx(Text, { as: "span", sx: { fontFamily: 'mono' }, children: approval.destinationUri })] })), decidable ? (_jsxs(_Fragment, { children: [_jsx(Textarea, { "aria-label": `Why, for ${approval.tool}`, rows: 2, placeholder: "Why (optional; kept with the decision)", value: noteFor[approval.uid] ?? '', onChange: event => setNoteFor(current => ({
|
|
62
|
+
return (_jsxs(Card, { border: true, shadow: "none", borderColor: decidable ? 'attention.emphasis' : 'border.default', p: 3, display: "grid", gap: 2, minWidth: 0, children: [_jsxs(Box, { display: "flex", gap: 2, alignItems: "center", flexWrap: "wrap", children: [_jsx(Label, { size: "small", variant: look.variant, children: look.label }), _jsx(Text, { sx: { fontSize: 1, fontWeight: 'semibold' }, children: approval.tool }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', fontFamily: 'mono' }, children: approval.actorUid }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["asked ", _jsx(RelativeTime, { datetime: approval.createdAt })] }), decidable && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["expires ", _jsx(RelativeTime, { datetime: approval.expiresAt })] }))] }), _jsx(Box, { as: "pre", fontFamily: "mono", fontSize: 0, whiteSpace: "pre-wrap", overflowX: "auto", bg: "canvas.subtle", borderRadius: 2, p: 2, m: 0, children: JSON.stringify(approval.argumentsRedacted, null, 2) }), approval.destinationUri && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["Writes to", ' ', _jsx(Text, { as: "span", sx: { fontFamily: 'mono' }, children: approval.destinationUri })] })), decidable ? (_jsxs(_Fragment, { children: [_jsx(Textarea, { "aria-label": `Why, for ${approval.tool}`, rows: 2, placeholder: "Why (optional; kept with the decision)", value: noteFor[approval.uid] ?? '', onChange: event => setNoteFor(current => ({
|
|
80
63
|
...current,
|
|
81
64
|
[approval.uid]: event.target.value,
|
|
82
|
-
})) }), _jsxs(Box, {
|
|
65
|
+
})) }), _jsxs(Box, { display: "flex", gap: 2, children: [_jsx(Button, { variant: "primary", disabled: decide.isPending, onClick: () => decide.mutate({
|
|
83
66
|
approvalUid: approval.uid,
|
|
84
67
|
decision: 'approve',
|
|
85
68
|
note: noteFor[approval.uid] || undefined,
|
|
@@ -81,64 +81,27 @@ export const AuditLog = ({ errorState, routes, filters, onFiltersChange, retenti
|
|
|
81
81
|
if (page.isError) {
|
|
82
82
|
return (_jsx(McpErrorBlankslate, { state: errorState(page.error, 'Audit'), onRetry: () => page.refetch() }));
|
|
83
83
|
}
|
|
84
|
-
return (_jsxs(Box, {
|
|
85
|
-
display: 'grid',
|
|
86
|
-
gap: 2,
|
|
87
|
-
gridTemplateColumns: ['1fr', 'repeat(2, 1fr)', 'repeat(5, 1fr)'],
|
|
88
|
-
alignItems: 'end',
|
|
89
|
-
}, children: [_jsx(TextInput, { size: "small", "aria-label": "Agent", placeholder: "Agent", value: filters.agent ?? '', onChange: event => set({ agent: event.currentTarget.value || undefined }) }), _jsx(TextInput, { size: "small", "aria-label": "Tool", placeholder: "Tool", value: filters.tool ?? '', onChange: event => set({ tool: event.currentTarget.value || undefined }) }), _jsxs(Select, { size: "small", "aria-label": "Decision", value: filters.decision ?? '', onChange: event => set({
|
|
84
|
+
return (_jsxs(Box, { display: "grid", gap: 3, minWidth: 0, children: [showTitle && (_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Audit" }), _jsxs(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: ["Every call ", subject, " made through MCP, what was decided, and why."] })] })), forwarding.data?.configured && forwarding.data.state && (_jsx(Flash, { variant: forwarding.data.state.healthy ? 'default' : 'danger', children: _jsx(Text, { sx: { fontSize: 1 }, children: forwarding.data.state.healthy ? (_jsxs(_Fragment, { children: ["Forwarded to your own system of record \u2014", ' ', forwarding.data.state.delivered, " batches", forwarding.data.state.lastDeliveredAt && (_jsxs(_Fragment, { children: [", last", ' ', _jsx(RelativeTime, { datetime: forwarding.data.state.lastDeliveredAt })] })), "."] })) : (_jsxs(_Fragment, { children: [_jsx("strong", { children: "Forwarding is failing." }), " These rows are kept here and are not reaching your own system of record:", ' ', forwarding.data.state.lastError, forwarding.data.state.lastErrorAt && (_jsxs(_Fragment, { children: [' ', "(", _jsx(RelativeTime, { datetime: forwarding.data.state.lastErrorAt }), ")"] })), ". ", forwarding.data.state.failed, " batches have failed."] })) }) })), _jsxs(Box, { display: "grid", gap: 2, gridTemplateColumns: ['1fr', 'repeat(2, 1fr)', 'repeat(5, 1fr)'], alignItems: "end", children: [_jsx(TextInput, { size: "small", "aria-label": "Agent", placeholder: "Agent", value: filters.agent ?? '', onChange: event => set({ agent: event.currentTarget.value || undefined }) }), _jsx(TextInput, { size: "small", "aria-label": "Tool", placeholder: "Tool", value: filters.tool ?? '', onChange: event => set({ tool: event.currentTarget.value || undefined }) }), _jsxs(Select, { size: "small", "aria-label": "Decision", value: filters.decision ?? '', onChange: event => set({
|
|
90
85
|
decision: (event.currentTarget.value ||
|
|
91
86
|
undefined),
|
|
92
87
|
}), children: [_jsx(Select.Option, { value: "", children: "Every decision" }), _jsx(Select.Option, { value: "allowed", children: "Allowed" }), _jsx(Select.Option, { value: "refused", children: "Refused" })] }), _jsxs(Select, { size: "small", "aria-label": "Outcome", value: filters.outcome ?? '', onChange: event => set({
|
|
93
88
|
outcome: (event.currentTarget.value ||
|
|
94
89
|
undefined),
|
|
95
|
-
}), 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: "is_error", children: "Tool error" })] }), _jsx(Box, {
|
|
90
|
+
}), 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: "is_error", children: "Tool error" })] }), _jsx(Box, { display: "flex", gap: 2, justifyContent: "flex-end", children: _jsxs(ActionMenu, { children: [_jsx(ActionMenu.Button, { size: "small", leadingVisual: DownloadIcon, disabled: exporting.isPending, children: "Export" }), _jsx(ActionMenu.Overlay, { align: "end", children: _jsxs(ActionList, { children: [_jsxs(ActionList.Item, { onSelect: () => exportAs('jsonl'), children: ["JSONL", _jsx(ActionList.Description, { variant: "block", children: "One row per line, as a SIEM reads it." })] }), _jsxs(ActionList.Item, { onSelect: () => exportAs('csv'), children: ["CSV", _jsx(ActionList.Description, { variant: "block", children: "The same rows for a spreadsheet." })] })] }) })] }) })] }), _jsxs(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: ["Audit rows are written once and never changed or deleted by anyone, here or elsewhere. Arguments are redacted before they are written.", ' ', retention] }), page.isPending && !page.data ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 6, children: _jsx(Spinner, {}) })) : rows.length === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(HistoryIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "Nothing to audit yet" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Every call an agent makes is written down here with its decision and its outcome. Connect a client and ask it to list your notebooks." }) }), _jsx(Button, { size: "small", onClick: () => navigate(routes.access), children: "Connect an agent" })] })) : (
|
|
96
91
|
/* The rail of the activity view: each mark on a tinted disc, the discs
|
|
97
92
|
linked by a line, so the rows carry no border of their own. */
|
|
98
|
-
_jsx(Box, {
|
|
93
|
+
_jsx(Box, { display: "grid", children: rows.map((event, index) => {
|
|
99
94
|
const look = decisionLook(event);
|
|
100
95
|
const isLast = index === rows.length - 1;
|
|
101
|
-
return (_jsxs(Box, {
|
|
102
|
-
display: 'flex',
|
|
103
|
-
flexDirection: 'column',
|
|
104
|
-
alignItems: 'center',
|
|
105
|
-
}, children: [_jsx(Box, { sx: {
|
|
106
|
-
width: 26,
|
|
107
|
-
height: 26,
|
|
108
|
-
borderRadius: '50%',
|
|
109
|
-
display: 'inline-flex',
|
|
110
|
-
alignItems: 'center',
|
|
111
|
-
justifyContent: 'center',
|
|
112
|
-
color: look.fg,
|
|
113
|
-
bg: look.bg,
|
|
114
|
-
flexShrink: 0,
|
|
115
|
-
}, children: _jsx(look.Icon, { size: 13 }) }), !isLast && (_jsx(Box, { sx: { width: '2px', flex: 1, bg: 'border.muted', my: 1 } }))] }), _jsxs(Box, { sx: {
|
|
116
|
-
flexGrow: 1,
|
|
117
|
-
minWidth: 0,
|
|
118
|
-
pb: isLast ? 0 : 3,
|
|
119
|
-
pt: '3px',
|
|
120
|
-
}, children: [_jsx(Link, { as: "button", sx: {
|
|
96
|
+
return (_jsxs(Box, { display: "flex", gap: 3, children: [_jsxs(Box, { display: "flex", flexDirection: "column", alignItems: "center", children: [_jsx(Box, { width: 26, height: 26, borderRadius: "50%", display: "inline-flex", alignItems: "center", justifyContent: "center", color: look.fg, bg: look.bg, flexShrink: 0, children: _jsx(look.Icon, { size: 13 }) }), !isLast && (_jsx(Box, { width: "2px", flex: 1, bg: "border.muted", my: 1 }))] }), _jsxs(Box, { flexGrow: 1, minWidth: 0, pb: isLast ? 0 : 3, pt: "3px", children: [_jsx(Link, { as: "button", sx: {
|
|
121
97
|
fontSize: 1,
|
|
122
98
|
display: 'block',
|
|
123
99
|
textAlign: 'left',
|
|
124
100
|
cursor: 'pointer',
|
|
125
|
-
}, onClick: () => setOpen(event), children: event.tool || event.method }), _jsxs(Box, { sx: {
|
|
126
|
-
display: 'flex',
|
|
127
|
-
gap: 2,
|
|
128
|
-
alignItems: 'center',
|
|
129
|
-
mt: 1,
|
|
130
|
-
flexWrap: 'wrap',
|
|
131
|
-
}, children: [_jsx(Label, { size: "small", variant: event.decision === 'refused' ? 'danger' : 'success', children: event.decision }), event.clientId && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: event.clientId })), event.itemUid && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["on ", event.itemUid] })), event.durationMs !== null &&
|
|
101
|
+
}, onClick: () => setOpen(event), children: event.tool || event.method }), _jsxs(Box, { display: "flex", gap: 2, alignItems: "center", mt: 1, flexWrap: "wrap", children: [_jsx(Label, { size: "small", variant: event.decision === 'refused' ? 'danger' : 'success', children: event.decision }), event.clientId && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: event.clientId })), event.itemUid && (_jsxs(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: ["on ", event.itemUid] })), event.durationMs !== null &&
|
|
132
102
|
event.durationMs !== undefined && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: durationLabel(event.durationMs) })), event.refusalReason && (_jsx(Text, { sx: { fontSize: 0, color: 'danger.fg' }, children: event.refusalReason }))] })] }), _jsx(Text, { sx: { fontSize: 0, color: 'fg.muted', flexShrink: 0 }, children: _jsx(RelativeTime, { datetime: event.at }) })] }, event.uid));
|
|
133
|
-
}) })), (walked.length > 0 || nextCursor) && (_jsxs(Box, {
|
|
103
|
+
}) })), (walked.length > 0 || nextCursor) && (_jsxs(Box, { display: "flex", gap: 2, justifyContent: "center", children: [_jsx(Button, { size: "small", leadingVisual: ChevronLeftIcon, disabled: walked.length === 0, onClick: newer, children: "Newer" }), _jsx(Button, { size: "small", trailingVisual: ChevronRightIcon, disabled: !nextCursor, onClick: older, children: "Older" })] })), open && (_jsx(Dialog, { title: open.tool || open.method, subtitle: `${open.decision} · ${open.outcome ?? 'no outcome recorded'}`, onClose: () => setOpen(null), returnFocusRef: returnFocusRef, width: "large", children: _jsxs(Box, { display: "grid", gap: 3, children: [_jsxs(Box, { display: "grid", gap: 1, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "When" }), _jsxs(Text, { sx: { fontSize: 1 }, children: [_jsx(RelativeTime, { datetime: open.at }), " \u2014 ", open.at] })] }), _jsxs(Box, { display: "grid", gap: 1, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Who" }), _jsxs(Text, { sx: { fontSize: 1 }, children: [open.clientId || 'unknown client', open.act &&
|
|
134
104
|
open.act.length > 0 &&
|
|
135
|
-
` acting for ${open.act.join(' → ')}`] })] }), open.refusalReason && (_jsxs(Box, {
|
|
136
|
-
m: 0,
|
|
137
|
-
p: 2,
|
|
138
|
-
fontSize: 0,
|
|
139
|
-
bg: 'canvas.inset',
|
|
140
|
-
borderRadius: 2,
|
|
141
|
-
overflowX: 'auto',
|
|
142
|
-
}, children: JSON.stringify(open.redactedArguments ?? {}, null, 2) }), open.argumentsHash && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle', fontFamily: 'mono' }, children: open.argumentsHash }))] }), _jsxs(Box, { sx: { display: 'flex', gap: 2, flexWrap: 'wrap' }, children: [open.taskId && (_jsx(Button, { size: "small", onClick: () => navigate(`${routes.runs}/${encodeURIComponent(open.taskId)}`), children: "The run" })), open.traceId && (_jsx(Button, { size: "small", onClick: () => navigate(`${routes.observability}?trace=${encodeURIComponent(open.traceId)}`), children: "The trace" }))] })] }) }))] }));
|
|
105
|
+
` acting for ${open.act.join(' → ')}`] })] }), open.refusalReason && (_jsxs(Box, { display: "grid", gap: 1, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Why it was refused" }), _jsx(Text, { sx: { fontSize: 1, color: 'danger.fg' }, children: open.refusalReason })] })), _jsxs(Box, { display: "grid", gap: 1, children: [_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Arguments, redacted before they were written" }), _jsx(Box, { as: "pre", m: 0, p: 2, fontSize: 0, bg: "canvas.inset", borderRadius: 2, overflowX: "auto", children: JSON.stringify(open.redactedArguments ?? {}, null, 2) }), open.argumentsHash && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle', fontFamily: 'mono' }, children: open.argumentsHash }))] }), _jsxs(Box, { display: "flex", gap: 2, flexWrap: "wrap", children: [open.taskId && (_jsx(Button, { size: "small", onClick: () => navigate(`${routes.runs}/${encodeURIComponent(open.taskId)}`), children: "The run" })), open.traceId && (_jsx(Button, { size: "small", onClick: () => navigate(`${routes.observability}?trace=${encodeURIComponent(open.traceId)}`), children: "The trace" }))] })] }) }))] }));
|
|
143
106
|
};
|
|
144
107
|
export default AuditLog;
|
|
@@ -101,12 +101,7 @@ export const ConnectedAgents = ({ errorState, routes, showTitle = true, readOnly
|
|
|
101
101
|
if (agents.isError) {
|
|
102
102
|
return (_jsx(McpErrorBlankslate, { state: errorState(agents.error, 'Connected agents'), onRetry: () => agents.refetch() }));
|
|
103
103
|
}
|
|
104
|
-
return (_jsxs(Box, {
|
|
105
|
-
display: 'flex',
|
|
106
|
-
alignItems: 'start',
|
|
107
|
-
justifyContent: 'space-between',
|
|
108
|
-
gap: 3,
|
|
109
|
-
}, children: [_jsxs(Box, { children: [_jsx(Heading, { as: "h2", sx: { fontSize: 3, mb: 1 }, children: "Connected Agents" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "Every agent you have authorized, what it may do, and when it last did it." })] }), !readOnly && rows.length > 0 && (_jsx(Button, { variant: "danger", onClick: () => setDisconnectingEvery(true), disabled: disconnectEvery.isPending, children: "Disconnect all" }))] })), agents.isPending && !agents.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: "connected-agents", children: "Agents" }), _jsx(Table.Subtitle, { as: "p", id: "connected-agents-subtitle", children: "An agent acts with exactly the access of the person who authorized it, and no more." }), _jsx(DataTable, { "aria-labelledby": "connected-agents", "aria-describedby": "connected-agents-subtitle", data: rows, columns: columns })] })) : (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(PlugIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No agent connected" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Connect an MCP client and approve the scopes it asks for; the grant appears here and can be revoked from here." }) }), _jsx(Button, { size: "small", onClick: () => navigate(routes.access), children: "Connect an agent" })] })), _jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: "Narrowing a grant to fewer scopes without disconnecting arrives with the organization policy." }), disconnecting && (_jsx(Dialog, { title: "Disconnect this agent?", onClose: () => setDisconnecting(null), returnFocusRef: returnFocusRef, footerButtons: [
|
|
104
|
+
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: "Connected Agents" }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "Every agent you have authorized, what it may do, and when it last did it." })] }), !readOnly && rows.length > 0 && (_jsx(Button, { variant: "danger", onClick: () => setDisconnectingEvery(true), disabled: disconnectEvery.isPending, children: "Disconnect all" }))] })), agents.isPending && !agents.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: "connected-agents", children: "Agents" }), _jsx(Table.Subtitle, { as: "p", id: "connected-agents-subtitle", children: "An agent acts with exactly the access of the person who authorized it, and no more." }), _jsx(DataTable, { "aria-labelledby": "connected-agents", "aria-describedby": "connected-agents-subtitle", data: rows, columns: columns })] })) : (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(PlugIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No agent connected" }), _jsx(Blankslate.Description, { children: _jsx(Text, { sx: { textAlign: 'center' }, children: "Connect an MCP client and approve the scopes it asks for; the grant appears here and can be revoked from here." }) }), _jsx(Button, { size: "small", onClick: () => navigate(routes.access), children: "Connect an agent" })] })), _jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: "Narrowing a grant to fewer scopes without disconnecting arrives with the organization policy." }), disconnecting && (_jsx(Dialog, { title: "Disconnect this agent?", onClose: () => setDisconnecting(null), returnFocusRef: returnFocusRef, footerButtons: [
|
|
110
105
|
{
|
|
111
106
|
buttonType: 'default',
|
|
112
107
|
content: 'Keep it',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Button, Heading, Label, SegmentedControl, Spinner, Text, } from '@primer/react';
|
|
3
3
|
import { Blankslate, DataTable, Table } from '@primer/react/experimental';
|
|
4
|
-
import { Box } from '@datalayer/primer-addons';
|
|
4
|
+
import { Box, Card } from '@datalayer/primer-addons';
|
|
5
5
|
import { AlertIcon, CheckCircleIcon, LockIcon, PlugIcon, } from '@primer/octicons-react';
|
|
6
6
|
import { ClientBadge, McpErrorBlankslate, ScopeList, } from '../../components/mcp/index.js';
|
|
7
7
|
import { useDisconnectAgent, useMcpActivity, useOrgMcpOverview, } from '../../hooks/useMcp.js';
|
|
@@ -90,13 +90,7 @@ export const pagesForRoles = (roles) => {
|
|
|
90
90
|
}
|
|
91
91
|
return [];
|
|
92
92
|
};
|
|
93
|
-
const Metric = ({ label, value, note, tone = 'neutral', }) => (_jsxs(
|
|
94
|
-
p: 3,
|
|
95
|
-
border: '1px solid',
|
|
96
|
-
borderColor: 'border.default',
|
|
97
|
-
borderRadius: 2,
|
|
98
|
-
minWidth: 0,
|
|
99
|
-
}, children: [_jsx(Text, { sx: {
|
|
93
|
+
const Metric = ({ label, value, note, tone = 'neutral', }) => (_jsxs(Card, { border: true, shadow: "none", display: "block", p: 3, minWidth: 0, children: [_jsx(Text, { sx: {
|
|
100
94
|
display: 'block',
|
|
101
95
|
fontSize: 4,
|
|
102
96
|
fontWeight: 'bold',
|
|
@@ -161,7 +155,7 @@ export const EnterpriseConsole = ({ errorState, routes, organization, roles, pag
|
|
|
161
155
|
id: 'actions',
|
|
162
156
|
width: '200px',
|
|
163
157
|
align: 'end',
|
|
164
|
-
renderCell: row => (_jsxs(Box, {
|
|
158
|
+
renderCell: row => (_jsxs(Box, { display: "flex", gap: 2, justifyContent: "flex-end", children: [_jsx(Button, { size: "small", onClick: () => navigate(`${routes.audit}?org=${encodeURIComponent(organization.uid)}&agent=${encodeURIComponent(row.clientId)}`), children: "Audit" }), _jsx(Button, { size: "small", variant: "danger", disabled: !row.grantUid, onClick: () => row.grantUid &&
|
|
165
159
|
disconnect.mutate(row.grantUid, {
|
|
166
160
|
onSuccess: () => enqueueToast(`${row.clientName || row.clientId} is disconnected.`, {
|
|
167
161
|
variant: 'success',
|
|
@@ -170,26 +164,19 @@ export const EnterpriseConsole = ({ errorState, routes, organization, roles, pag
|
|
|
170
164
|
}), children: "Revoke" })] })),
|
|
171
165
|
},
|
|
172
166
|
];
|
|
173
|
-
return (_jsxs(Box, {
|
|
174
|
-
(overview.isError ? (_jsx(McpErrorBlankslate, { state: errorState(overview.error, 'The overview'), onRetry: () => overview.refetch() })) : overview.isPending && !overview.data ? (_jsx(Box, {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
'repeat(3, 1fr)',
|
|
180
|
-
'repeat(5, 1fr)',
|
|
181
|
-
],
|
|
182
|
-
}, children: [_jsx(Metric, { label: "Agents active today", value: overview.data?.agents.activeToday ?? 0, note: `${overview.data?.agents.delegated ?? 0} delegated · ${overview.data?.agents.service ?? 0} service` }), _jsx(Metric, { label: "Runs today", value: overview.data?.runs.today ?? 0 }), _jsx(Metric, { label: "Success rate", value: overview.data?.runs.successRate === null ||
|
|
167
|
+
return (_jsxs(Box, { display: "grid", gap: 4, minWidth: 0, children: [_jsxs(Box, { children: [_jsxs(Heading, { as: "h3", sx: { fontSize: 2, mb: 1 }, children: ["MCP \u2014 ", organization.name || organization.handle] }), _jsx(Text, { as: "p", sx: { color: 'fg.muted', fontSize: 1, m: 0 }, children: "What the agents of this organization are doing, what they were allowed to do, and how it ran." })] }), _jsx(SegmentedControl, { "aria-label": "MCP console pages", size: "small", children: ENTERPRISE_CONSOLE_PAGES.filter(entry => allowed.includes(entry.id)).map(entry => (_jsx(SegmentedControl.Button, { selected: current === entry.id, onClick: () => onPageChange(entry.id), children: entry.label }, entry.id))) }), current === 'overview' &&
|
|
168
|
+
(overview.isError ? (_jsx(McpErrorBlankslate, { state: errorState(overview.error, 'The overview'), onRetry: () => overview.refetch() })) : overview.isPending && !overview.data ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 6, children: _jsx(Spinner, {}) })) : (_jsxs(Box, { display: "grid", gap: 4, children: [_jsxs(Box, { display: "grid", gap: 3, gridTemplateColumns: [
|
|
169
|
+
'repeat(2, 1fr)',
|
|
170
|
+
'repeat(3, 1fr)',
|
|
171
|
+
'repeat(5, 1fr)',
|
|
172
|
+
], children: [_jsx(Metric, { label: "Agents active today", value: overview.data?.agents.activeToday ?? 0, note: `${overview.data?.agents.delegated ?? 0} delegated · ${overview.data?.agents.service ?? 0} service` }), _jsx(Metric, { label: "Runs today", value: overview.data?.runs.today ?? 0 }), _jsx(Metric, { label: "Success rate", value: overview.data?.runs.successRate === null ||
|
|
183
173
|
overview.data?.runs.successRate === undefined
|
|
184
174
|
? '—'
|
|
185
175
|
: `${(overview.data.runs.successRate * 100).toFixed(0)}%`, note: `${overview.data?.runs.failed ?? 0} failed` }), _jsx(Metric, { label: "Credits today", value: overview.data?.spend?.creditsToday ?? '—', note: overview.data?.spend?.quotaMonth
|
|
186
176
|
? `${overview.data.spend.creditsMonth} of ${overview.data.spend.quotaMonth} this month`
|
|
187
177
|
: 'Quotas arrive with the organization policy' }), _jsx(Metric, { label: "Refusals today", value: (overview.data?.refusals ?? []).reduce((sum, row) => sum + row.count, 0), tone: (overview.data?.refusals ?? []).length > 0
|
|
188
178
|
? 'danger'
|
|
189
|
-
: 'neutral' })] }), (overview.data?.refusals ?? []).length > 0 && (_jsxs(Box, {
|
|
190
|
-
|
|
191
|
-
display: 'flex',
|
|
192
|
-
}, children: check.ok ? (_jsx(CheckCircleIcon, { size: 14 })) : (_jsx(AlertIcon, { size: 14 })) }), _jsx(Text, { sx: { fontSize: 1 }, children: check.name }), !check.ok && check.detail && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: check.detail }))] }, check.name))) }))] }), _jsxs(Box, { sx: { display: 'flex', gap: 3, flexWrap: 'wrap' }, children: [_jsx(Metric, { label: "Approvals waiting", value: overview.data?.approvalsWaiting ?? '—', note: "The queue arrives with durable execution" }), _jsx(Metric, { label: "Alerts firing", value: overview.data?.alertsFiring ?? '—', note: "Alert rules arrive with quotas" })] })] }))), current === 'usage' && (_jsx(OrganizationUsage, { errorState: errorState, orgUid: organization.uid, showTitle: false })), current === 'teams' && (_jsx(TeamPolicies, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') })), current === 'identity-providers' && (_jsxs(Box, { sx: { display: 'grid', gap: 5, minWidth: 0 }, children: [_jsx(IdentityProviders, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') }), _jsx(ScimProvisioning, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') })] })), current === 'alerts' && (_jsx(AlertRules, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') })), current === 'approvals' && _jsx(ApprovalQueue, { errorState: errorState }), current === 'policy' && (_jsx(OrganizationPolicy, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') })), current === 'service-agents' && (_jsx(ServiceAgents, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') })), current === 'agents' &&
|
|
193
|
-
(activity.isError ? (_jsx(McpErrorBlankslate, { state: errorState(activity.error, "The organization's agents"), onRetry: () => activity.refetch() })) : activity.isPending && !activity.data ? (_jsx(Box, { sx: { display: 'flex', justifyContent: 'center', py: 6 }, children: _jsx(Spinner, {}) })) : agentRows.length === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(PlugIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No agent acts for this organization" }), _jsx(Blankslate.Description, { children: _jsxs(Text, { sx: { textAlign: 'center' }, children: ["A member who authorizes a client while acting for", ' ', organization.name || organization.handle, " appears here with the scopes the grant carries and what it last did."] }) })] })) : (_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h4", id: "org-agents", children: "Agents" }), _jsxs(Table.Subtitle, { as: "p", id: "org-agents-subtitle", children: [plural(agentRows.length, 'principal'), " acting through MCP for this organization. A member's own grant is revoked by that member; revoking on their behalf arrives with the organization's agent directory."] }), _jsx(DataTable, { "aria-labelledby": "org-agents", "aria-describedby": "org-agents-subtitle", data: agentRows, columns: agentColumns })] }))), current === 'audit' && (_jsx(AuditLog, { errorState: errorState, routes: routes, showTitle: false, subject: organization.name || organization.handle, filters: { ...auditFilters, org: organization.uid }, onFiltersChange: filters => onAuditFiltersChange({ ...filters, org: undefined }) })), current === 'observability' && (_jsx(McpObservability, { errorState: errorState, routes: routes, showTitle: false, org: organization.uid, pane: observabilityPane, onPaneChange: onObservabilityPaneChange, taskUid: observabilityTask, traceId: observabilityTrace, onSelect: onObservabilitySelect })), _jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: "Teams, Policies, Quotas, Alerts, Approvals and Runs join this console as the layers behind them ship. Identity \u2014 providers, group mapping, SCIM and session controls \u2014 comes last, with enterprise sign-in." })] }));
|
|
179
|
+
: 'neutral' })] }), (overview.data?.refusals ?? []).length > 0 && (_jsxs(Box, { display: "grid", gap: 2, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1 }, children: "Why calls were refused" }), _jsx(Box, { display: "flex", gap: 2, flexWrap: "wrap", children: (overview.data?.refusals ?? []).map(row => (_jsxs(Label, { size: "small", variant: "danger", children: [row.reason, " \u00B7 ", row.count] }, row.reason))) })] })), _jsxs(Box, { display: "grid", gap: 2, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1 }, children: "Compliance" }), (overview.data?.compliance ?? []).length === 0 ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: "Nothing to check yet: the strip fills as the organization's sign-in, admitted clients and audit export are configured." })) : (_jsx(Box, { display: "grid", gap: 1, children: (overview.data?.compliance ?? []).map(check => (_jsxs(Box, { display: "flex", alignItems: "center", gap: 2, children: [_jsx(Box, { color: check.ok ? 'success.fg' : 'attention.fg', display: "flex", children: check.ok ? (_jsx(CheckCircleIcon, { size: 14 })) : (_jsx(AlertIcon, { size: 14 })) }), _jsx(Text, { sx: { fontSize: 1 }, children: check.name }), !check.ok && check.detail && (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: check.detail }))] }, check.name))) }))] }), _jsxs(Box, { display: "flex", gap: 3, flexWrap: "wrap", children: [_jsx(Metric, { label: "Approvals waiting", value: overview.data?.approvalsWaiting ?? '—', note: "The queue arrives with durable execution" }), _jsx(Metric, { label: "Alerts firing", value: overview.data?.alertsFiring ?? '—', note: "Alert rules arrive with quotas" })] })] }))), current === 'usage' && (_jsx(OrganizationUsage, { errorState: errorState, orgUid: organization.uid, showTitle: false })), current === 'teams' && (_jsx(TeamPolicies, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') })), current === 'identity-providers' && (_jsxs(Box, { display: "grid", gap: 5, minWidth: 0, children: [_jsx(IdentityProviders, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') }), _jsx(ScimProvisioning, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') })] })), current === 'alerts' && (_jsx(AlertRules, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') })), current === 'approvals' && _jsx(ApprovalQueue, { errorState: errorState }), current === 'policy' && (_jsx(OrganizationPolicy, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') })), current === 'service-agents' && (_jsx(ServiceAgents, { errorState: errorState, orgUid: organization.uid, readOnly: !roles.includes('organization_owner') })), current === 'agents' &&
|
|
180
|
+
(activity.isError ? (_jsx(McpErrorBlankslate, { state: errorState(activity.error, "The organization's agents"), onRetry: () => activity.refetch() })) : activity.isPending && !activity.data ? (_jsx(Box, { display: "flex", justifyContent: "center", py: 6, children: _jsx(Spinner, {}) })) : agentRows.length === 0 ? (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(PlugIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "No agent acts for this organization" }), _jsx(Blankslate.Description, { children: _jsxs(Text, { sx: { textAlign: 'center' }, children: ["A member who authorizes a client while acting for", ' ', organization.name || organization.handle, " appears here with the scopes the grant carries and what it last did."] }) })] })) : (_jsxs(Table.Container, { children: [_jsx(Table.Title, { as: "h4", id: "org-agents", children: "Agents" }), _jsxs(Table.Subtitle, { as: "p", id: "org-agents-subtitle", children: [plural(agentRows.length, 'principal'), " acting through MCP for this organization. A member's own grant is revoked by that member; revoking on their behalf arrives with the organization's agent directory."] }), _jsx(DataTable, { "aria-labelledby": "org-agents", "aria-describedby": "org-agents-subtitle", data: agentRows, columns: agentColumns })] }))), current === 'audit' && (_jsx(AuditLog, { errorState: errorState, routes: routes, showTitle: false, subject: organization.name || organization.handle, filters: { ...auditFilters, org: organization.uid }, onFiltersChange: filters => onAuditFiltersChange({ ...filters, org: undefined }) })), current === 'observability' && (_jsx(McpObservability, { errorState: errorState, routes: routes, showTitle: false, org: organization.uid, pane: observabilityPane, onPaneChange: onObservabilityPaneChange, taskUid: observabilityTask, traceId: observabilityTrace, onSelect: onObservabilitySelect })), _jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: "Teams, Policies, Quotas, Alerts, Approvals and Runs join this console as the layers behind them ship. Identity \u2014 providers, group mapping, SCIM and session controls \u2014 comes last, with enterprise sign-in." })] }));
|
|
194
181
|
};
|
|
195
182
|
export default EnterpriseConsole;
|