@datalayer/core 1.1.60 → 1.2.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -18
- package/lib/api/DatalayerApi.d.ts +42 -1
- package/lib/api/DatalayerApi.js +90 -3
- package/lib/api/constants.d.ts +19 -1
- package/lib/api/constants.js +19 -1
- package/lib/api/contents/attachments.d.ts +9 -0
- package/lib/api/contents/attachments.js +39 -0
- package/lib/api/contents/bridges.d.ts +22 -0
- package/lib/api/contents/bridges.js +79 -0
- package/lib/api/contents/capabilities.d.ts +11 -0
- package/lib/api/contents/capabilities.js +21 -0
- package/lib/api/contents/cloudStorage.d.ts +31 -0
- package/lib/api/contents/cloudStorage.js +89 -0
- package/lib/api/contents/dataservers.d.ts +37 -0
- package/lib/api/contents/dataservers.js +121 -0
- package/lib/api/contents/datasets.d.ts +63 -0
- package/lib/api/contents/datasets.js +82 -0
- package/lib/api/contents/datasources.d.ts +70 -0
- package/lib/api/contents/datasources.js +149 -0
- package/lib/api/contents/generated.d.ts +1070 -0
- package/lib/api/contents/index.d.ts +16 -0
- package/lib/api/contents/index.js +20 -0
- package/lib/api/contents/mcp.d.ts +46 -0
- package/lib/api/contents/mcp.js +157 -0
- package/lib/api/contents/objects.d.ts +31 -0
- package/lib/api/contents/objects.js +88 -0
- package/lib/api/contents/operations.d.ts +3 -0
- package/lib/api/contents/operations.js +19 -0
- package/lib/api/contents/runtimeMounts.d.ts +40 -0
- package/lib/api/contents/runtimeMounts.js +59 -0
- package/lib/api/contents/sandboxUid.d.ts +21 -0
- package/lib/api/contents/sandboxUid.js +27 -0
- package/lib/api/contents/sources.d.ts +19 -0
- package/lib/api/contents/sources.js +119 -0
- package/lib/api/contents/sync.d.ts +18 -0
- package/lib/api/contents/sync.js +69 -0
- package/lib/api/contents/transfers.d.ts +38 -0
- package/lib/api/contents/transfers.js +123 -0
- package/lib/api/evals/client.d.ts +402 -0
- package/lib/api/evals/client.js +359 -0
- package/lib/api/evals/index.d.ts +10 -0
- package/lib/api/evals/index.js +18 -0
- package/lib/api/evals/request.d.ts +43 -0
- package/lib/api/evals/request.js +67 -0
- package/lib/api/evals/status.d.ts +27 -0
- package/lib/api/evals/status.js +122 -0
- package/lib/api/evals/types.d.ts +1335 -0
- package/lib/api/evals/types.js +5 -0
- package/lib/api/iam/connectedAgents.d.ts +68 -0
- package/lib/api/iam/connectedAgents.js +87 -0
- package/lib/api/iam/identityProviders.d.ts +76 -0
- package/lib/api/iam/identityProviders.js +187 -0
- package/lib/api/iam/index.d.ts +3 -1
- package/lib/api/iam/index.js +3 -1
- package/lib/api/iam/mcpAlertRules.d.ts +51 -0
- package/lib/api/iam/mcpAlertRules.js +198 -0
- package/lib/api/iam/mcpAuditSettings.d.ts +46 -0
- package/lib/api/iam/mcpAuditSettings.js +120 -0
- package/lib/api/iam/mcpPolicy.d.ts +181 -0
- package/lib/api/iam/mcpPolicy.js +168 -0
- package/lib/api/iam/organizationTeams.d.ts +13 -0
- package/lib/api/iam/organizationTeams.js +43 -0
- package/lib/api/iam/profile.d.ts +17 -1
- package/lib/api/iam/profile.js +27 -0
- package/lib/api/iam/scimTokens.d.ts +79 -0
- package/lib/api/iam/scimTokens.js +141 -0
- package/lib/api/iam/secrets.js +9 -21
- package/lib/api/iam/serviceAgents.d.ts +68 -0
- package/lib/api/iam/serviceAgents.js +119 -0
- package/lib/api/iam/trials.d.ts +38 -0
- package/lib/api/iam/trials.js +66 -0
- package/lib/api/index.d.ts +8 -1
- package/lib/api/index.js +7 -1
- package/lib/api/mcp/activity.d.ts +37 -0
- package/lib/api/mcp/activity.js +26 -0
- package/lib/api/mcp/alerts.d.ts +25 -0
- package/lib/api/mcp/alerts.js +51 -0
- package/lib/api/mcp/audit.d.ts +29 -0
- package/lib/api/mcp/audit.js +55 -0
- package/lib/api/mcp/bindings.d.ts +18 -0
- package/lib/api/mcp/bindings.js +42 -0
- package/lib/api/mcp/forwarding.d.ts +25 -0
- package/lib/api/mcp/forwarding.js +46 -0
- package/lib/api/mcp/gateway.d.ts +16 -0
- package/lib/api/mcp/gateway.js +70 -0
- package/lib/api/mcp/generated.d.ts +22 -0
- package/lib/api/mcp/generated.js +213 -0
- package/lib/api/mcp/index.d.ts +17 -0
- package/lib/api/mcp/index.js +25 -0
- package/lib/api/mcp/observability.d.ts +141 -0
- package/lib/api/mcp/observability.js +267 -0
- package/lib/api/mcp/operations.d.ts +83 -0
- package/lib/api/mcp/operations.js +50 -0
- package/lib/api/mcp/organizations.d.ts +102 -0
- package/lib/api/mcp/organizations.js +46 -0
- package/lib/api/mcp/policy.d.ts +9 -0
- package/lib/api/mcp/policy.js +23 -0
- package/lib/api/mcp/tasks.d.ts +49 -0
- package/lib/api/mcp/tasks.js +147 -0
- package/lib/api/orchestration/client.d.ts +53 -0
- package/lib/api/orchestration/client.js +105 -0
- package/lib/api/orchestration/events.d.ts +88 -0
- package/lib/api/orchestration/events.js +245 -0
- package/lib/api/orchestration/generated.d.ts +693 -0
- package/lib/api/orchestration/generated.js +687 -0
- package/lib/api/orchestration/index.d.ts +30 -0
- package/lib/api/orchestration/index.js +34 -0
- package/lib/api/orchestration/lifecycle.d.ts +39 -0
- package/lib/api/orchestration/lifecycle.js +57 -0
- package/lib/api/orchestration/measures.d.ts +55 -0
- package/lib/api/orchestration/measures.js +99 -0
- package/lib/api/otel/dashboards.d.ts +56 -0
- package/lib/api/otel/dashboards.js +50 -0
- package/lib/api/otel/index.d.ts +1 -0
- package/lib/api/otel/index.js +1 -0
- package/lib/api/otel/metrics.d.ts +16 -0
- package/lib/api/otel/metrics.js +15 -0
- package/lib/api/scheduler/client.d.ts +32 -0
- package/lib/api/scheduler/client.js +42 -0
- package/lib/api/scheduler/index.d.ts +8 -0
- package/lib/api/scheduler/index.js +16 -0
- package/lib/api/scheduler/request.d.ts +28 -0
- package/lib/api/scheduler/request.js +50 -0
- package/lib/api/scheduler/types.d.ts +88 -0
- package/lib/api/scheduler/types.js +5 -0
- package/lib/api/spacer/comments.d.ts +97 -0
- package/lib/api/spacer/comments.js +45 -0
- package/lib/api/spacer/index.d.ts +9 -0
- package/lib/api/spacer/index.js +17 -0
- package/lib/api/spacer/notebooks.d.ts +33 -0
- package/lib/api/spacer/notebooks.js +39 -0
- package/lib/api/spacer/request.d.ts +25 -0
- package/lib/api/spacer/request.js +46 -0
- package/lib/api/spacer/spaces.d.ts +68 -0
- package/lib/api/spacer/spaces.js +45 -0
- package/lib/api/utils/validation.d.ts +4 -4
- package/lib/api/utils/validation.js +10 -7
- package/lib/client/auth/index.js +0 -5
- package/lib/client/auth/storage.js +0 -5
- package/lib/client/auth/strategies.js +0 -5
- package/lib/client/base.d.ts +6 -0
- package/lib/client/base.js +8 -0
- package/lib/client/constants.d.ts +1 -0
- package/lib/client/constants.js +1 -0
- package/lib/client/index.d.ts +0 -10
- package/lib/client/index.js +2 -2
- package/lib/client/mixins/ContentsMixin.d.ts +71 -0
- package/lib/client/mixins/ContentsMixin.js +157 -0
- package/lib/client/mixins/IAMMixin.d.ts +0 -31
- package/lib/client/mixins/IAMMixin.js +0 -58
- package/lib/components/animation/AnimatedText.d.ts +2 -44
- package/lib/components/animation/AnimatedText.js +6 -126
- package/lib/components/anonymous/AnonymousKeyExpired.d.ts +56 -0
- package/lib/components/anonymous/AnonymousKeyExpired.js +96 -0
- package/lib/components/anonymous/AnonymousKeyTimer.d.ts +63 -0
- package/lib/components/anonymous/AnonymousKeyTimer.js +140 -0
- package/lib/components/anonymous/index.d.ts +7 -0
- package/lib/components/anonymous/index.js +15 -0
- package/lib/components/auth/SigInAPIKey.d.ts +1 -0
- package/lib/components/auth/SigInAPIKey.js +0 -6
- package/lib/components/auth/SignIn.d.ts +1 -0
- package/lib/components/auth/SignIn.js +0 -4
- package/lib/components/auth/SignIn.stories.d.ts +2 -2
- package/lib/components/avatars/BoringAvatar.d.ts +1 -1
- package/lib/components/avatars/BoringAvatar.stories.d.ts +1 -1
- package/lib/components/avatars/DLAvatar.d.ts +1 -1
- package/lib/components/avatars/DLAvatar.js +0 -4
- package/lib/components/avatars/UserAvatar.d.ts +16 -1
- package/lib/components/avatars/UserAvatar.js +15 -13
- package/lib/components/avatars/UserProfileAvatar.d.ts +1 -1
- package/lib/components/banners/NoAutomationBanner.d.ts +1 -1
- package/lib/components/billing/BillingEntitySelect.d.ts +16 -0
- package/lib/components/billing/BillingEntitySelect.js +49 -27
- package/lib/components/billing/eligibility.d.ts +22 -0
- package/lib/components/billing/eligibility.js +27 -0
- package/lib/components/billing/index.d.ts +1 -0
- package/lib/components/billing/index.js +1 -4
- package/lib/components/buttons/DownloadCSVButton.d.ts +1 -1
- package/lib/components/buttons/DownloadJsonButton.d.ts +1 -1
- package/lib/components/buttons/LongActionButton.d.ts +1 -0
- package/lib/components/buttons/LongActionButton.js +0 -4
- package/lib/components/buttons/UploadButton.d.ts +1 -0
- package/lib/components/buttons/UploadButton.js +0 -4
- package/lib/components/checkout/StripeCheckout.d.ts +1 -1
- package/lib/components/collaboration/LiveEditorCollaborators.d.ts +36 -0
- package/lib/components/collaboration/LiveEditorCollaborators.js +88 -53
- package/lib/components/collaboration/index.js +0 -4
- package/lib/components/confetti/ConfettiSuccess.d.ts +1 -1
- package/lib/components/contents/ContentSourceCard.d.ts +8 -0
- package/lib/components/contents/ContentSourceCard.js +23 -0
- package/lib/components/contents/HomeFolderObjectsBrowser.d.ts +10 -0
- package/lib/components/contents/HomeFolderObjectsBrowser.js +148 -0
- package/lib/components/contents/index.d.ts +2 -0
- package/lib/components/contents/index.js +6 -0
- package/lib/components/context/OrganizationSelect.d.ts +1 -1
- package/lib/components/display/AvatarSkeleton.d.ts +1 -1
- package/lib/components/display/BusyDots.d.ts +1 -1
- package/lib/components/display/CenteredSpinner.d.ts +1 -1
- package/lib/components/display/CodePreview.d.ts +1 -1
- package/lib/components/display/DatalayerBox.d.ts +7 -3
- package/lib/components/display/DatalayerBox.js +7 -7
- package/lib/components/display/HorizontalCenter.d.ts +1 -1
- package/lib/components/display/JupyterDialog.d.ts +1 -0
- package/lib/components/display/JupyterDialog.js +1 -7
- package/lib/components/display/Markdown.d.ts +1 -0
- package/lib/components/display/NavLink.js +3 -2
- package/lib/components/display/NotebookSkeleton.d.ts +1 -1
- package/lib/components/display/Placeholder.d.ts +1 -1
- package/lib/components/display/ToTopBranded.d.ts +1 -1
- package/lib/components/echarts/EChartsReact.d.ts +1 -1
- package/lib/components/flashes/FlashClosable.d.ts +1 -0
- package/lib/components/flashes/FlashClosable.js +0 -4
- package/lib/components/flashes/FlashGuest.d.ts +1 -1
- package/lib/components/flashes/FlashSurveys.d.ts +1 -1
- package/lib/components/flashes/FlashUnauthorized.d.ts +1 -0
- package/lib/components/flashes/FlashUnauthorized.js +0 -6
- package/lib/components/flashes/surveys/Survey2025_1.d.ts +1 -1
- package/lib/components/iam/ExternalTokenSilentLogin.d.ts +1 -1
- package/lib/components/index.d.ts +2 -0
- package/lib/components/index.js +2 -0
- package/lib/components/labels/StatusLabels.d.ts +2 -9
- package/lib/components/labels/StatusLabels.js +2 -26
- package/lib/components/labels/VisibilityLabel.d.ts +1 -1
- package/lib/components/landings/StepBlock.d.ts +1 -1
- package/lib/components/mcp/ClientBadge.d.ts +41 -0
- package/lib/components/mcp/ClientBadge.js +33 -0
- package/lib/components/mcp/McpErrorBlankslate.d.ts +21 -0
- package/lib/components/mcp/McpErrorBlankslate.js +17 -0
- package/lib/components/mcp/ScopeList.d.ts +28 -0
- package/lib/components/mcp/ScopeList.js +14 -0
- package/lib/components/mcp/index.d.ts +10 -0
- package/lib/components/mcp/index.js +18 -0
- package/lib/components/navbar/NavigationVisbilityObserver.d.ts +2 -1
- package/lib/components/navbar/SubdomainNavBar.d.ts +10 -5
- package/lib/components/navbar/SubdomainNavBar.js +2 -1
- package/lib/components/notebooks/JupyterNotebook.d.ts +1 -1
- package/lib/components/notebooks/JupyterNotebookToolbar.d.ts +1 -1
- package/lib/components/principal/PrincipalAppearance.d.ts +22 -42
- package/lib/components/principal/PrincipalAppearance.js +232 -182
- package/lib/components/principal/PrincipalAvatar.d.ts +9 -1
- package/lib/components/principal/PrincipalAvatar.js +18 -10
- package/lib/components/principal/PrincipalBadge.d.ts +1 -1
- package/lib/components/principal/PrincipalBanner.d.ts +1 -1
- package/lib/components/principal/PrincipalDetailsOverlay.d.ts +38 -1
- package/lib/components/principal/PrincipalDetailsOverlay.js +64 -33
- package/lib/components/principal/PrincipalHoverCard.d.ts +31 -0
- package/lib/components/principal/PrincipalHoverCard.js +52 -0
- package/lib/components/principal/PrincipalSwitcherMenu.d.ts +1 -0
- package/lib/components/principal/PrincipalSwitcherMenu.js +5 -14
- package/lib/components/principal/index.d.ts +2 -1
- package/lib/components/principal/index.js +2 -1
- package/lib/components/progress/ConsumptionBar.d.ts +1 -0
- package/lib/components/progress/ConsumptionBar.js +0 -4
- package/lib/components/progress/ProgressRing.d.ts +1 -0
- package/lib/components/progress/SpinnerBar.d.ts +1 -1
- package/lib/components/progress/Timer.d.ts +1 -0
- package/lib/components/progress/Timer.js +0 -4
- package/lib/components/screencapture/Screencapture.js +46 -3
- package/lib/components/screencapture/ScreencaptureButton.d.ts +1 -1
- package/lib/components/sharing/ShareAccessComponent.d.ts +58 -3
- package/lib/components/sharing/ShareAccessComponent.js +143 -98
- package/lib/components/sharing/SharingEditor.d.ts +21 -0
- package/lib/components/sharing/SharingEditor.js +9 -28
- package/lib/components/sharing/index.d.ts +1 -0
- package/lib/components/sharing/index.js +1 -0
- package/lib/components/sharing/sandboxSharing.d.ts +26 -0
- package/lib/components/sharing/sandboxSharing.js +41 -0
- package/lib/components/spaces/SpaceDetailsOverlay.d.ts +39 -0
- package/lib/components/spaces/SpaceDetailsOverlay.js +80 -0
- package/lib/components/spaces/SpaceDisplay.d.ts +38 -0
- package/lib/components/spaces/SpaceDisplay.js +92 -0
- package/lib/components/spaces/index.d.ts +4 -0
- package/lib/components/spaces/index.js +7 -0
- package/lib/components/spaces/spaceDisplayModel.d.ts +93 -0
- package/lib/components/spaces/spaceDisplayModel.js +170 -0
- package/lib/components/sparklines/Sparklines.js +3 -4
- package/lib/components/sparklines/index.js +0 -4
- package/lib/components/storage/ContentsBrowser.d.ts +25 -1
- package/lib/components/storage/ContentsBrowser.js +145 -52
- package/lib/components/storage/ContentsBrowserMock.d.ts +3 -0
- package/lib/components/storage/ContentsBrowserMock.js +75 -0
- package/lib/components/storage/ContentsItems.d.ts +2 -1
- package/lib/components/storage/ContentsItems.js +0 -4
- package/lib/components/storage/ContentsTable.d.ts +50 -0
- package/lib/components/storage/ContentsTable.js +134 -0
- package/lib/components/storage/HomeFolderDrive.d.ts +71 -0
- package/lib/components/storage/HomeFolderDrive.js +248 -0
- package/lib/components/storage/index.d.ts +2 -0
- package/lib/components/storage/index.js +2 -0
- package/lib/components/students/StudentItemStatus.d.ts +1 -1
- package/lib/components/students/StudentResultCircle.d.ts +1 -1
- package/lib/components/subnav/SubNav.d.ts +5 -5
- package/lib/components/subnav/SubNav.js +11 -9
- package/lib/components/tables/DataTable.d.ts +1 -1
- package/lib/components/text-reveal/TextRevealAnimation.d.ts +2 -2
- package/lib/components/text-reveal/useTextRevealAnimationLines.d.ts +1 -1
- package/lib/components/time/LiveRelativeTime.d.ts +1 -0
- package/lib/components/time/LiveRelativeTime.js +0 -8
- package/lib/components/time/index.js +0 -4
- package/lib/components/timeline/Timeline.d.ts +1 -1
- package/lib/components/timeline/index.js +0 -4
- package/lib/components/users/PeerIndicator.d.ts +1 -0
- package/lib/components/users/PeerIndicator.js +0 -4
- package/lib/config/Configuration.d.ts +15 -17
- package/lib/config/Configuration.js +7 -0
- package/lib/hooks/cacheConverters.d.ts +0 -7
- package/lib/hooks/cacheConverters.js +0 -25
- package/lib/hooks/index.d.ts +3 -0
- package/lib/hooks/index.js +3 -0
- package/lib/hooks/layouts/LayoutBackdrop.d.ts +1 -1
- package/lib/hooks/layouts/LayoutScreencapture.d.ts +1 -1
- package/lib/hooks/useBackdrop.d.ts +1 -1
- package/lib/hooks/useBackdropJupyterLab.d.ts +3 -2
- package/lib/hooks/useBackdropJupyterLab.js +0 -4
- package/lib/hooks/useBillingEntityStore.js +3 -0
- package/lib/hooks/useCache.d.ts +478 -130
- package/lib/hooks/useCache.js +1580 -676
- package/lib/hooks/useContainsFocus.d.ts +1 -1
- package/lib/hooks/useContents.d.ts +334 -0
- package/lib/hooks/useContents.js +1033 -0
- package/lib/hooks/useFocusTrap.d.ts +4 -4
- package/lib/hooks/useFocusTrap.js +1 -1
- package/lib/hooks/useMcp.d.ts +315 -0
- package/lib/hooks/useMcp.js +891 -0
- package/lib/hooks/useMobile.js +0 -5
- package/lib/hooks/useNavigate.d.ts +41 -3
- package/lib/hooks/useNavigate.js +106 -52
- package/lib/hooks/usePrincipalCacheStore.js +3 -0
- package/lib/hooks/usePrincipalStore.js +3 -0
- package/lib/hooks/useProjectStore.d.ts +3 -3
- package/lib/hooks/useProjectStore.js +4 -4
- package/lib/hooks/useRef.d.ts +1 -1
- package/lib/hooks/useRef.js +3 -0
- package/lib/hooks/useScreencapture.d.ts +2 -1
- package/lib/hooks/useScreencapture.js +0 -4
- package/lib/hooks/useSpaceCacheStore.d.ts +50 -0
- package/lib/hooks/useSpaceCacheStore.js +85 -0
- package/lib/hooks/useToast.js +0 -4
- package/lib/hooks/useVisibilityObserver.d.ts +1 -1
- package/lib/index.d.ts +4 -1
- package/lib/index.js +3 -1
- package/lib/mocks/components/FlashMock.d.ts +1 -1
- package/lib/mocks/views/ActionMenuMock.d.ts +1 -1
- package/lib/mocks/views/ChartMock.d.ts +1 -1
- package/lib/mocks/views/DashboardMock.d.ts +1 -1
- package/lib/mocks/views/FormMock.d.ts +1 -1
- package/lib/mocks/views/TableMock.d.ts +1 -1
- package/lib/mocks/views/WipMock.d.ts +1 -1
- package/lib/models/Credits.d.ts +16 -0
- package/lib/models/Credits.js +22 -0
- package/lib/models/CreditsDTO.d.ts +6 -5
- package/lib/models/CreditsDTO.js +7 -5
- package/lib/models/McpAuditEvent.d.ts +52 -0
- package/lib/models/McpAuditEvent.js +5 -0
- package/lib/models/McpBinding.d.ts +57 -0
- package/lib/models/McpBinding.js +5 -0
- package/lib/models/McpPolicy.d.ts +77 -0
- package/lib/models/McpPolicy.js +5 -0
- package/lib/models/McpTask.d.ts +94 -0
- package/lib/models/McpTask.js +7 -0
- package/lib/models/Organization.d.ts +69 -0
- package/lib/models/Organization.js +96 -0
- package/lib/models/Secret.d.ts +1 -2
- package/lib/models/Secret.js +2 -18
- package/lib/models/StartedBy.d.ts +91 -0
- package/lib/models/StartedBy.js +117 -0
- package/lib/models/Team.d.ts +2 -0
- package/lib/models/Team.js +2 -0
- package/lib/models/User.d.ts +4 -0
- package/lib/models/User.js +3 -0
- package/lib/models/UserDTO.js +4 -2
- package/lib/models/UserSettings.d.ts +13 -0
- package/lib/models/UserSettings.js +9 -0
- package/lib/models/contents/__fixtures__/solr-codec.json +57 -0
- package/lib/models/contents/__fixtures__/v1-contracts.json +194 -0
- package/lib/models/contents/fieldCase.d.ts +8 -0
- package/lib/models/contents/fieldCase.js +37 -0
- package/lib/models/contents/index.d.ts +2 -0
- package/lib/models/contents/index.js +6 -0
- package/lib/models/contents/permissions.d.ts +16 -0
- package/lib/models/contents/permissions.js +34 -0
- package/lib/models/index.d.ts +5 -1
- package/lib/models/index.js +5 -1
- package/lib/navigation/components.js +2 -3
- package/lib/routes/publicPaths.js +4 -0
- package/lib/state/index.d.ts +1 -0
- package/lib/state/index.js +1 -0
- package/lib/state/sessionEnd.d.ts +55 -0
- package/lib/state/sessionEnd.js +162 -0
- package/lib/state/substates/CoreState.d.ts +15 -7
- package/lib/state/substates/CoreState.js +21 -17
- package/lib/state/substates/IAMState.d.ts +1 -1
- package/lib/state/substates/IAMState.js +12 -5
- package/lib/state/substates/LayoutState.js +12 -0
- package/lib/state/substates/ProfileState.d.ts +1 -0
- package/lib/state/substates/ProfileState.js +1 -4
- package/lib/state/substates/index.d.ts +0 -1
- package/lib/state/substates/index.js +0 -1
- package/lib/utils/Jwt.d.ts +26 -0
- package/lib/utils/Jwt.js +37 -0
- package/lib/utils/Lazy.d.ts +20 -0
- package/lib/utils/Lazy.js +32 -6
- package/lib/utils/Screencapture.js +3 -0
- package/lib/utils/WithSuspense.d.ts +11 -1
- package/lib/utils/WithSuspense.js +11 -1
- package/lib/views/api-keys/APIKeyEdit.d.ts +1 -1
- package/lib/views/api-keys/APIKeyNew.d.ts +1 -1
- package/lib/views/api-keys/APIKeys.d.ts +1 -1
- package/lib/views/api-keys/APIKeys.js +30 -4
- package/lib/views/api-keys/APIKeysStandalone.d.ts +5 -1
- package/lib/views/api-keys/APIKeysStandalone.js +2 -2
- package/lib/views/datasources/DatasourceDetail.d.ts +12 -5
- package/lib/views/datasources/DatasourceDetail.js +80 -110
- package/lib/views/datasources/DatasourceNew.d.ts +14 -8
- package/lib/views/datasources/DatasourceNew.js +129 -118
- package/lib/views/datasources/Datasources.d.ts +39 -7
- package/lib/views/datasources/Datasources.js +95 -40
- package/lib/views/datasources/DatasourcesMock.d.ts +3 -0
- package/lib/views/datasources/DatasourcesMock.js +57 -0
- package/lib/views/iam/SignInSimple.d.ts +12 -0
- package/lib/views/iam/SignInSimple.js +4 -4
- package/lib/views/index.d.ts +1 -0
- package/lib/views/index.js +1 -0
- package/lib/views/mcp/AdmittedClients.d.ts +44 -0
- package/lib/views/mcp/AdmittedClients.js +59 -0
- package/lib/views/mcp/AlertDestinations.d.ts +34 -0
- package/lib/views/mcp/AlertDestinations.js +75 -0
- package/lib/views/mcp/AlertRules.d.ts +32 -0
- package/lib/views/mcp/AlertRules.js +245 -0
- package/lib/views/mcp/ApprovalQueue.d.ts +66 -0
- package/lib/views/mcp/ApprovalQueue.js +95 -0
- package/lib/views/mcp/AuditLog.d.ts +42 -0
- package/lib/views/mcp/AuditLog.js +144 -0
- package/lib/views/mcp/ConnectedAgents.d.ts +34 -0
- package/lib/views/mcp/ConnectedAgents.js +135 -0
- package/lib/views/mcp/EnterpriseConsole.d.ts +74 -0
- package/lib/views/mcp/EnterpriseConsole.js +195 -0
- package/lib/views/mcp/IdentityProviders.d.ts +33 -0
- package/lib/views/mcp/IdentityProviders.js +299 -0
- package/lib/views/mcp/McpDashboard.d.ts +50 -0
- package/lib/views/mcp/McpDashboard.js +430 -0
- package/lib/views/mcp/McpHome.d.ts +92 -0
- package/lib/views/mcp/McpHome.js +153 -0
- package/lib/views/mcp/McpObservability.d.ts +79 -0
- package/lib/views/mcp/McpObservability.js +236 -0
- package/lib/views/mcp/NotebookRuns.d.ts +39 -0
- package/lib/views/mcp/NotebookRuns.js +44 -0
- package/lib/views/mcp/OrganizationPolicy.d.ts +45 -0
- package/lib/views/mcp/OrganizationPolicy.js +108 -0
- package/lib/views/mcp/OrganizationUsage.d.ts +69 -0
- package/lib/views/mcp/OrganizationUsage.js +113 -0
- package/lib/views/mcp/PersonalPolicy.d.ts +54 -0
- package/lib/views/mcp/PersonalPolicy.js +126 -0
- package/lib/views/mcp/Policies.d.ts +53 -0
- package/lib/views/mcp/Policies.js +210 -0
- package/lib/views/mcp/PolicyForm.d.ts +83 -0
- package/lib/views/mcp/PolicyForm.js +113 -0
- package/lib/views/mcp/PolicyHistory.d.ts +58 -0
- package/lib/views/mcp/PolicyHistory.js +75 -0
- package/lib/views/mcp/RunDetail.d.ts +87 -0
- package/lib/views/mcp/RunDetail.js +186 -0
- package/lib/views/mcp/ScimProvisioning.d.ts +54 -0
- package/lib/views/mcp/ScimProvisioning.js +173 -0
- package/lib/views/mcp/ServiceAgents.d.ts +46 -0
- package/lib/views/mcp/ServiceAgents.js +194 -0
- package/lib/views/mcp/TeamPolicies.d.ts +33 -0
- package/lib/views/mcp/TeamPolicies.js +159 -0
- package/lib/views/mcp/ToolAccess.d.ts +60 -0
- package/lib/views/mcp/ToolAccess.js +101 -0
- package/lib/views/mcp/TraceTimeline.d.ts +81 -0
- package/lib/views/mcp/TraceTimeline.js +132 -0
- package/lib/views/mcp/format.d.ts +25 -0
- package/lib/views/mcp/format.js +77 -0
- package/lib/views/mcp/index.d.ts +34 -0
- package/lib/views/mcp/index.js +42 -0
- package/lib/views/mcp/types.d.ts +66 -0
- package/lib/views/mcp/types.js +5 -0
- package/lib/views/otel/simpleAuthStore.js +3 -0
- package/lib/views/secrets/SecretEdit.d.ts +5 -1
- package/lib/views/secrets/SecretEdit.js +5 -4
- package/lib/views/secrets/SecretNew.d.ts +11 -1
- package/lib/views/secrets/SecretNew.js +7 -3
- package/lib/views/secrets/Secrets.d.ts +12 -1
- package/lib/views/secrets/Secrets.js +2 -2
- package/package.json +269 -260
- package/scripts/generate-contents-types.py +169 -0
- package/scripts/generate-mcp-types.py +233 -0
- package/scripts/generate-orchestration-types.py +920 -0
- package/lib/api/iam/datasources.d.ts +0 -86
- package/lib/api/iam/datasources.js +0 -185
- package/lib/components/toolbars/index.d.ts +0 -1
- package/lib/models/Datasource.d.ts +0 -181
- package/lib/models/Datasource.js +0 -154
- package/lib/state/substates/DatasourceState.d.ts +0 -11
- package/lib/state/substates/DatasourceState.js +0 -16
- /package/lib/{components/toolbars/index.js → api/contents/generated.js} +0 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, Heading, Label, SegmentedControl, Spinner, Text, } from '@primer/react';
|
|
3
|
+
import { Blankslate, DataTable, Table } from '@primer/react/experimental';
|
|
4
|
+
import { Box } from '@datalayer/primer-addons';
|
|
5
|
+
import { AlertIcon, CheckCircleIcon, LockIcon, PlugIcon, } from '@primer/octicons-react';
|
|
6
|
+
import { ClientBadge, McpErrorBlankslate, ScopeList, } from '../../components/mcp/index.js';
|
|
7
|
+
import { useDisconnectAgent, useMcpActivity, useOrgMcpOverview, } from '../../hooks/useMcp.js';
|
|
8
|
+
import { useNavigate, useToast } from '../../hooks/index.js';
|
|
9
|
+
import { AuditLog } from './AuditLog.js';
|
|
10
|
+
import { McpObservability, } from './McpObservability.js';
|
|
11
|
+
import { AlertRules } from './AlertRules.js';
|
|
12
|
+
import { IdentityProviders } from './IdentityProviders.js';
|
|
13
|
+
import { ScimProvisioning } from './ScimProvisioning.js';
|
|
14
|
+
import { TeamPolicies } from './TeamPolicies.js';
|
|
15
|
+
import { OrganizationUsage } from './OrganizationUsage.js';
|
|
16
|
+
import { OrganizationPolicy } from './OrganizationPolicy.js';
|
|
17
|
+
import { ServiceAgents } from './ServiceAgents.js';
|
|
18
|
+
import { clientStatusOf, plural, timeAgo } from './format.js';
|
|
19
|
+
import { ApprovalQueue } from './ApprovalQueue.js';
|
|
20
|
+
export const ENTERPRISE_CONSOLE_PAGES = [
|
|
21
|
+
{ id: 'overview', label: 'Overview' },
|
|
22
|
+
{ id: 'usage', label: 'Usage' },
|
|
23
|
+
{ id: 'agents', label: 'Agents' },
|
|
24
|
+
{ id: 'service-agents', label: 'Service Agents' },
|
|
25
|
+
{ id: 'policy', label: 'Policy' },
|
|
26
|
+
{ id: 'teams', label: 'Teams' },
|
|
27
|
+
{ id: 'identity-providers', label: 'Identity' },
|
|
28
|
+
{ id: 'alerts', label: 'Alerts' },
|
|
29
|
+
{ id: 'approvals', label: 'Approvals' },
|
|
30
|
+
{ id: 'audit', label: 'Audit' },
|
|
31
|
+
{ id: 'observability', label: 'Observability' },
|
|
32
|
+
];
|
|
33
|
+
/** Which pages each organization role may read. */
|
|
34
|
+
export const pagesForRoles = (roles) => {
|
|
35
|
+
if (roles.includes('organization_owner')) {
|
|
36
|
+
return [
|
|
37
|
+
'overview',
|
|
38
|
+
'usage',
|
|
39
|
+
'agents',
|
|
40
|
+
'service-agents',
|
|
41
|
+
'policy',
|
|
42
|
+
'teams',
|
|
43
|
+
// Who may sign in here at all, and as what, is the organization's own
|
|
44
|
+
// authority — the same reason a provider needs an owner to register,
|
|
45
|
+
// never a security auditor or a usage reviewer.
|
|
46
|
+
'identity-providers',
|
|
47
|
+
'alerts',
|
|
48
|
+
'approvals',
|
|
49
|
+
'audit',
|
|
50
|
+
'observability',
|
|
51
|
+
];
|
|
52
|
+
}
|
|
53
|
+
if (roles.includes('organization_security_auditor')) {
|
|
54
|
+
// The service agents too, read-only: an auditor reading a row that names
|
|
55
|
+
// `agent_uid` needs somewhere to find out what that agent is, and the
|
|
56
|
+
// list carries no key.
|
|
57
|
+
// The policy too, read-only: an auditor asked why a call was refused
|
|
58
|
+
// needs to see the rule that refused it, and the page carries no secret.
|
|
59
|
+
return [
|
|
60
|
+
'overview',
|
|
61
|
+
'service-agents',
|
|
62
|
+
'policy',
|
|
63
|
+
// The team layers too: an auditor asked why one team's agents are
|
|
64
|
+
// treated differently needs the layer that treats them so.
|
|
65
|
+
'teams',
|
|
66
|
+
// Identity providers too, read-only: which directory an organization
|
|
67
|
+
// trusts and what its group mapping grants is exactly the posture an
|
|
68
|
+
// auditor is there to read, and the page carries no secret — the
|
|
69
|
+
// client secret is a reference, never the value.
|
|
70
|
+
'identity-providers',
|
|
71
|
+
// The alerts too: what an organization watches for is part of the
|
|
72
|
+
// security posture an auditor is there to read.
|
|
73
|
+
'alerts',
|
|
74
|
+
// The approvals are deliberately NOT here. Contents scopes
|
|
75
|
+
// `/mcp-approvals` to the caller — the actor, or the person who owns
|
|
76
|
+
// the source and must decide — so an auditor would open a queue of
|
|
77
|
+
// their own approvals under an organization's console and read it as
|
|
78
|
+
// that organization having none. An empty table that looks like an
|
|
79
|
+
// answer is worse than no tab. What an auditor needs is the decision
|
|
80
|
+
// *after* it was taken, and that is an audit row.
|
|
81
|
+
'audit',
|
|
82
|
+
'observability',
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
if (roles.includes('organization_usage_reviewer')) {
|
|
86
|
+
// The page the role is named for. It saw only the Overview, which counts
|
|
87
|
+
// runs and refusals and says nothing about a limit — a usage reviewer
|
|
88
|
+
// with no usage page had nothing to review.
|
|
89
|
+
return ['overview', 'usage'];
|
|
90
|
+
}
|
|
91
|
+
return [];
|
|
92
|
+
};
|
|
93
|
+
const Metric = ({ label, value, note, tone = 'neutral', }) => (_jsxs(Box, { sx: {
|
|
94
|
+
p: 3,
|
|
95
|
+
border: '1px solid',
|
|
96
|
+
borderColor: 'border.default',
|
|
97
|
+
borderRadius: 2,
|
|
98
|
+
minWidth: 0,
|
|
99
|
+
}, children: [_jsx(Text, { sx: {
|
|
100
|
+
display: 'block',
|
|
101
|
+
fontSize: 4,
|
|
102
|
+
fontWeight: 'bold',
|
|
103
|
+
color: tone === 'danger' ? 'danger.fg' : 'fg.default',
|
|
104
|
+
}, 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 }))] }));
|
|
105
|
+
export const EnterpriseConsole = ({ errorState, routes, organization, roles, page, onPageChange, auditFilters, onAuditFiltersChange, observabilityPane, onObservabilityPaneChange, observabilityTask, observabilityTrace, onObservabilitySelect, }) => {
|
|
106
|
+
const navigate = useNavigate();
|
|
107
|
+
const { enqueueToast } = useToast();
|
|
108
|
+
const allowed = pagesForRoles(roles);
|
|
109
|
+
const current = allowed.includes(page) ? page : allowed[0];
|
|
110
|
+
const overview = useOrgMcpOverview(organization.uid, {}, {
|
|
111
|
+
enabled: Boolean(current) && (current === 'overview' || current === 'agents'),
|
|
112
|
+
});
|
|
113
|
+
const activity = useMcpActivity({ org: organization.uid }, { enabled: current === 'agents' });
|
|
114
|
+
const disconnect = useDisconnectAgent();
|
|
115
|
+
if (allowed.length === 0) {
|
|
116
|
+
return (_jsxs(Blankslate, { border: true, spacious: true, children: [_jsx(Blankslate.Visual, { children: _jsx(LockIcon, { size: "medium" }) }), _jsx(Blankslate.Heading, { children: "Unauthorized" }), _jsx(Blankslate.Description, { children: _jsxs(Text, { sx: { textAlign: 'center' }, children: ["The MCP console of an organization is read by its owners, its security auditors and its usage reviewers. Ask an owner of", ' ', organization.name || organization.handle, " for the role you need."] }) })] }));
|
|
117
|
+
}
|
|
118
|
+
const agentRows = (activity.data?.clients ?? []).map(client => ({
|
|
119
|
+
...client,
|
|
120
|
+
id: client.clientId,
|
|
121
|
+
}));
|
|
122
|
+
const agentColumns = [
|
|
123
|
+
{
|
|
124
|
+
header: 'Client',
|
|
125
|
+
field: 'clientId',
|
|
126
|
+
rowHeader: true,
|
|
127
|
+
renderCell: row => (_jsx(ClientBadge, { clientId: row.clientId, clientName: row.clientName })),
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
header: 'Member',
|
|
131
|
+
id: 'member',
|
|
132
|
+
renderCell: row => (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: row.lastCall?.userUid || '—' })),
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
header: 'Allowed to',
|
|
136
|
+
id: 'scopes',
|
|
137
|
+
width: 'growCollapse',
|
|
138
|
+
renderCell: row => _jsx(ScopeList, { scopes: row.scopes ?? [] }),
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
header: 'Last used',
|
|
142
|
+
id: 'last-used',
|
|
143
|
+
width: '120px',
|
|
144
|
+
renderCell: row => (_jsx(Text, { sx: { fontSize: 0, color: 'fg.muted' }, children: timeAgo(row.lastCall?.at) || 'Never' })),
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
header: 'Status',
|
|
148
|
+
id: 'status',
|
|
149
|
+
width: '120px',
|
|
150
|
+
renderCell: row => {
|
|
151
|
+
const status = clientStatusOf(row.lastCall?.at);
|
|
152
|
+
return (_jsx(Label, { size: "small", variant: status === 'active'
|
|
153
|
+
? 'success'
|
|
154
|
+
: status === 'idle'
|
|
155
|
+
? 'attention'
|
|
156
|
+
: 'secondary', children: status }));
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
header: '',
|
|
161
|
+
id: 'actions',
|
|
162
|
+
width: '200px',
|
|
163
|
+
align: 'end',
|
|
164
|
+
renderCell: row => (_jsxs(Box, { sx: { 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
|
+
disconnect.mutate(row.grantUid, {
|
|
166
|
+
onSuccess: () => enqueueToast(`${row.clientName || row.clientId} is disconnected.`, {
|
|
167
|
+
variant: 'success',
|
|
168
|
+
}),
|
|
169
|
+
onError: () => enqueueToast('That grant belongs to another member and is revoked by them today. Revoking on their behalf arrives with the organization agent directory.', { variant: 'error' }),
|
|
170
|
+
}), children: "Revoke" })] })),
|
|
171
|
+
},
|
|
172
|
+
];
|
|
173
|
+
return (_jsxs(Box, { sx: { 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' &&
|
|
174
|
+
(overview.isError ? (_jsx(McpErrorBlankslate, { state: errorState(overview.error, 'The overview'), onRetry: () => overview.refetch() })) : overview.isPending && !overview.data ? (_jsx(Box, { sx: { display: 'flex', justifyContent: 'center', py: 6 }, children: _jsx(Spinner, {}) })) : (_jsxs(Box, { sx: { display: 'grid', gap: 4 }, children: [_jsxs(Box, { sx: {
|
|
175
|
+
display: 'grid',
|
|
176
|
+
gap: 3,
|
|
177
|
+
gridTemplateColumns: [
|
|
178
|
+
'repeat(2, 1fr)',
|
|
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 ||
|
|
183
|
+
overview.data?.runs.successRate === undefined
|
|
184
|
+
? '—'
|
|
185
|
+
: `${(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
|
+
? `${overview.data.spend.creditsMonth} of ${overview.data.spend.quotaMonth} this month`
|
|
187
|
+
: '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
|
+
? 'danger'
|
|
189
|
+
: 'neutral' })] }), (overview.data?.refusals ?? []).length > 0 && (_jsxs(Box, { sx: { display: 'grid', gap: 2 }, children: [_jsx(Heading, { as: "h4", sx: { fontSize: 1 }, children: "Why calls were refused" }), _jsx(Box, { sx: { 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, { sx: { 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, { sx: { display: 'grid', gap: 1 }, children: (overview.data?.compliance ?? []).map(check => (_jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(Box, { sx: {
|
|
190
|
+
color: check.ok ? 'success.fg' : 'attention.fg',
|
|
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." })] }));
|
|
194
|
+
};
|
|
195
|
+
export default EnterpriseConsole;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An organization's own identity provider.
|
|
3
|
+
*
|
|
4
|
+
* Enterprise sign-in used to be one Okta for the whole deployment. Here an
|
|
5
|
+
* organization registers the directory it already has — issuer, client id,
|
|
6
|
+
* the email domains it claims — and a sign-in with an address at one of
|
|
7
|
+
* those domains is routed to it.
|
|
8
|
+
*
|
|
9
|
+
* **A claim is not proof, and this page is careful to say so.** A domain
|
|
10
|
+
* just typed in and one proved by DNS are shown differently on purpose: a
|
|
11
|
+
* grey "claimed" label beside a domain that routes nothing yet, a green
|
|
12
|
+
* "verified" one beside a domain that does. Collapsing the two into one list
|
|
13
|
+
* would let an owner believe a claim is already live when it is not — and
|
|
14
|
+
* until it is verified, nobody signs in through it at all.
|
|
15
|
+
*
|
|
16
|
+
* **The client secret never appears here**, only its name in the
|
|
17
|
+
* organization's own secret store. This page has no field that could render
|
|
18
|
+
* one, by construction rather than by care taken while writing it.
|
|
19
|
+
*
|
|
20
|
+
* @module views/mcp/IdentityProviders
|
|
21
|
+
*/
|
|
22
|
+
import type { JSX } from 'react';
|
|
23
|
+
import type { McpErrorStateFn } from './types';
|
|
24
|
+
export interface IdentityProvidersProps {
|
|
25
|
+
errorState: McpErrorStateFn;
|
|
26
|
+
orgUid: string;
|
|
27
|
+
/** Read-only for anybody who is not an owner: registering a provider
|
|
28
|
+
* decides who may get into the organization at all. */
|
|
29
|
+
readOnly?: boolean;
|
|
30
|
+
showTitle?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export declare const IdentityProviders: ({ errorState, orgUid, readOnly, showTitle, }: IdentityProvidersProps) => JSX.Element;
|
|
33
|
+
export default IdentityProviders;
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useMemo, useRef, useState } from 'react';
|
|
3
|
+
import { ActionList, ActionMenu, Button, Flash, FormControl, Heading, IconButton, Label, Select, Spinner, Text, TextInput, ToggleSwitch, } from '@primer/react';
|
|
4
|
+
import { Blankslate, DataTable, Dialog, Table, } from '@primer/react/experimental';
|
|
5
|
+
import { Box } from '@datalayer/primer-addons';
|
|
6
|
+
import { KebabHorizontalIcon, KeyIcon, TrashIcon, } from '@primer/octicons-react';
|
|
7
|
+
import { McpErrorBlankslate } from '../../components/mcp/index.js';
|
|
8
|
+
import { useCreateIdentityProvider, useDeleteIdentityProvider, useDomainVerification, useIdentityProviders, useSetIdentityProviderEnabled, useUpdateIdentityProvider, useVerifyDomain, } from '../../hooks/useMcp.js';
|
|
9
|
+
import { useToast } from '../../hooks/index.js';
|
|
10
|
+
import { IdentityProviderInvalid, ORGANIZATION_ROLES, TEAM_ROLES, } from '../../api/iam/identityProviders.js';
|
|
11
|
+
const ROLE_LABELS = {
|
|
12
|
+
organization_owner: 'Organization owner',
|
|
13
|
+
organization_security_auditor: 'Organization security auditor',
|
|
14
|
+
organization_user_reviewer: 'Organization usage reviewer',
|
|
15
|
+
organization_member: 'Organization member',
|
|
16
|
+
team_owner: 'Team owner',
|
|
17
|
+
team_member: 'Team member',
|
|
18
|
+
};
|
|
19
|
+
const roleLabel = (role) => ROLE_LABELS[role] ?? role;
|
|
20
|
+
const isTeamRole = (role) => TEAM_ROLES.includes(role);
|
|
21
|
+
const BLANK = {
|
|
22
|
+
name: '',
|
|
23
|
+
protocol: 'oidc',
|
|
24
|
+
issuer: '',
|
|
25
|
+
clientId: '',
|
|
26
|
+
clientSecretRef: '',
|
|
27
|
+
domains: [],
|
|
28
|
+
groupClaim: 'groups',
|
|
29
|
+
allowEmailLinking: false,
|
|
30
|
+
roleMappings: [],
|
|
31
|
+
enabled: true,
|
|
32
|
+
};
|
|
33
|
+
const domainsToText = (domains) => domains.join(', ');
|
|
34
|
+
const textToDomains = (text) => Array.from(new Set(text
|
|
35
|
+
.split(/[,\s]+/)
|
|
36
|
+
.map(domain => domain.trim().toLowerCase())
|
|
37
|
+
.filter(Boolean)));
|
|
38
|
+
export const IdentityProviders = ({ errorState, orgUid, readOnly = false, showTitle = true, }) => {
|
|
39
|
+
const { enqueueToast } = useToast();
|
|
40
|
+
const providers = useIdentityProviders(orgUid);
|
|
41
|
+
const create = useCreateIdentityProvider(orgUid);
|
|
42
|
+
const update = useUpdateIdentityProvider(orgUid);
|
|
43
|
+
const setEnabled = useSetIdentityProviderEnabled(orgUid);
|
|
44
|
+
const remove = useDeleteIdentityProvider(orgUid);
|
|
45
|
+
const domainVerification = useDomainVerification(orgUid);
|
|
46
|
+
const verifyDomain = useVerifyDomain(orgUid);
|
|
47
|
+
const [editing, setEditing] = useState(null);
|
|
48
|
+
const [creating, setCreating] = useState(false);
|
|
49
|
+
const [draft, setDraft] = useState(BLANK);
|
|
50
|
+
const [domainsText, setDomainsText] = useState('');
|
|
51
|
+
const [refusal, setRefusal] = useState('');
|
|
52
|
+
const [removing, setRemoving] = useState(null);
|
|
53
|
+
const [managingDomains, setManagingDomains] = useState(null);
|
|
54
|
+
// Primer 37 types Dialog's focus refs with React 18's non-nullable
|
|
55
|
+
// `RefObject<HTMLElement>`. React 19's `useRef(null)` is nullable, and this
|
|
56
|
+
// ref is only handed to Dialog, so narrow it once here.
|
|
57
|
+
const returnFocusRef = useRef(null);
|
|
58
|
+
const rows = useMemo(() => (providers.data ?? []).map(provider => ({
|
|
59
|
+
...provider,
|
|
60
|
+
id: provider.uid,
|
|
61
|
+
})), [providers.data]);
|
|
62
|
+
const openCreate = () => {
|
|
63
|
+
setDraft(BLANK);
|
|
64
|
+
setDomainsText('');
|
|
65
|
+
setRefusal('');
|
|
66
|
+
setCreating(true);
|
|
67
|
+
};
|
|
68
|
+
const openEdit = (provider) => {
|
|
69
|
+
const { uid: _uid, orgUid: _org, verifiedDomains: _verified, createdBy: _by, createdAt: _c, updatedAt: _u, version: _v, ...rest } = provider;
|
|
70
|
+
setDraft(rest);
|
|
71
|
+
setDomainsText(domainsToText(provider.domains));
|
|
72
|
+
setRefusal('');
|
|
73
|
+
setEditing(provider);
|
|
74
|
+
};
|
|
75
|
+
const close = () => {
|
|
76
|
+
setCreating(false);
|
|
77
|
+
setEditing(null);
|
|
78
|
+
setRefusal('');
|
|
79
|
+
};
|
|
80
|
+
const onError = (error) => {
|
|
81
|
+
if (error instanceof IdentityProviderInvalid) {
|
|
82
|
+
// The registry's own words, beside the form: it names what is wrong,
|
|
83
|
+
// and the person can still fix it without guessing.
|
|
84
|
+
setRefusal(error.message);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
enqueueToast(`Could not save: ${error.message}`, { variant: 'error' });
|
|
88
|
+
};
|
|
89
|
+
const apply = () => {
|
|
90
|
+
setRefusal('');
|
|
91
|
+
const domains = textToDomains(domainsText);
|
|
92
|
+
if (domains.length === 0) {
|
|
93
|
+
setRefusal('At least one email domain is needed; a provider no domain routes ' +
|
|
94
|
+
'to is one nobody can sign in through.');
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const payload = { ...draft, domains };
|
|
98
|
+
if (editing) {
|
|
99
|
+
update.mutate({ uid: editing.uid, provider: payload }, {
|
|
100
|
+
onSuccess: () => {
|
|
101
|
+
close();
|
|
102
|
+
enqueueToast('Identity provider saved.', { variant: 'success' });
|
|
103
|
+
},
|
|
104
|
+
onError,
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
create.mutate(payload, {
|
|
109
|
+
onSuccess: () => {
|
|
110
|
+
close();
|
|
111
|
+
enqueueToast('Identity provider registered. Verify a domain before anybody ' +
|
|
112
|
+
'signs in through it.', { variant: 'success' });
|
|
113
|
+
},
|
|
114
|
+
onError,
|
|
115
|
+
});
|
|
116
|
+
};
|
|
117
|
+
/** Switching a provider off leaves its configuration here; only sign-in
|
|
118
|
+
* through it stops. */
|
|
119
|
+
const toggle = (provider, enabled) => {
|
|
120
|
+
setEnabled.mutate({ uid: provider.uid, enabled }, {
|
|
121
|
+
onError: error => enqueueToast(`Could not change the provider: ${error.message}`, {
|
|
122
|
+
variant: 'error',
|
|
123
|
+
}),
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
const confirmRemove = () => {
|
|
127
|
+
const provider = removing;
|
|
128
|
+
if (!provider) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
remove.mutate(provider.uid, {
|
|
132
|
+
onSuccess: () => {
|
|
133
|
+
setRemoving(null);
|
|
134
|
+
enqueueToast('Identity provider removed.', { variant: 'success' });
|
|
135
|
+
},
|
|
136
|
+
onError: error => {
|
|
137
|
+
setRemoving(null);
|
|
138
|
+
enqueueToast(`Could not remove: ${error.message}`, {
|
|
139
|
+
variant: 'error',
|
|
140
|
+
});
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
};
|
|
144
|
+
const set = (key, value) => setDraft(current => ({ ...current, [key]: value }));
|
|
145
|
+
const setMapping = (index, patch) => {
|
|
146
|
+
setDraft(current => ({
|
|
147
|
+
...current,
|
|
148
|
+
roleMappings: current.roleMappings.map((mapping, i) => i === index ? { ...mapping, ...patch } : mapping),
|
|
149
|
+
}));
|
|
150
|
+
};
|
|
151
|
+
const addMapping = () => setDraft(current => ({
|
|
152
|
+
...current,
|
|
153
|
+
roleMappings: [
|
|
154
|
+
...current.roleMappings,
|
|
155
|
+
{ group: '', role: 'organization_member', teamUid: '' },
|
|
156
|
+
],
|
|
157
|
+
}));
|
|
158
|
+
const removeMapping = (index) => setDraft(current => ({
|
|
159
|
+
...current,
|
|
160
|
+
roleMappings: current.roleMappings.filter((_, i) => i !== index),
|
|
161
|
+
}));
|
|
162
|
+
const columns = [
|
|
163
|
+
{
|
|
164
|
+
header: 'Provider',
|
|
165
|
+
id: 'name',
|
|
166
|
+
rowHeader: true,
|
|
167
|
+
width: 'growCollapse',
|
|
168
|
+
renderCell: row => (_jsxs(Box, { sx: { 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
|
+
},
|
|
170
|
+
{
|
|
171
|
+
header: 'Domains',
|
|
172
|
+
id: 'domains',
|
|
173
|
+
width: 'growCollapse',
|
|
174
|
+
renderCell: row => (_jsxs(Box, { sx: { 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
|
+
? ' · verified'
|
|
176
|
+
: ' · claimed'] }, domain)))] })),
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
header: 'On',
|
|
180
|
+
id: 'enabled',
|
|
181
|
+
width: '90px',
|
|
182
|
+
renderCell: row => (_jsxs(_Fragment, { children: [_jsx(Text, { id: `idp-toggle-${row.uid}`, sx: { display: 'none' }, children: `Sign-in through ${row.name}` }), _jsx(ToggleSwitch, { size: "small", checked: row.enabled, disabled: readOnly || setEnabled.isPending, "aria-labelledby": `idp-toggle-${row.uid}`, onClick: () => toggle(row, !row.enabled) })] })),
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
header: '',
|
|
186
|
+
id: 'actions',
|
|
187
|
+
width: '48px',
|
|
188
|
+
align: 'end',
|
|
189
|
+
renderCell: row => readOnly ? (_jsx(Text, { sx: { fontSize: 0, color: 'fg.subtle' }, children: "\u2014" })) : (_jsxs(ActionMenu, { children: [_jsx(ActionMenu.Anchor, { children: _jsx(Button, { variant: "invisible", size: "small", "aria-label": `Actions for ${row.name}`, icon: KebabHorizontalIcon }) }), _jsx(ActionMenu.Overlay, { align: "end", children: _jsxs(ActionList, { children: [_jsx(ActionList.Item, { onSelect: () => openEdit(row), children: "Edit" }), _jsx(ActionList.Item, { onSelect: () => setManagingDomains(row), disabled: row.domains.length === 0, children: "Manage domains" }), _jsx(ActionList.Item, { variant: "danger", onSelect: () => setRemoving(row), children: "Remove" })] }) })] })),
|
|
190
|
+
},
|
|
191
|
+
];
|
|
192
|
+
if (providers.isError) {
|
|
193
|
+
return (_jsx(McpErrorBlankslate, { state: errorState(providers.error, 'Identity providers'), onRetry: () => providers.refetch() }));
|
|
194
|
+
}
|
|
195
|
+
return (_jsxs(Box, { sx: { display: 'grid', gap: 3, minWidth: 0 }, children: [showTitle && (_jsxs(Box, { sx: {
|
|
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: [
|
|
201
|
+
{ buttonType: 'default', content: 'Cancel', onClick: close },
|
|
202
|
+
{
|
|
203
|
+
buttonType: 'primary',
|
|
204
|
+
content: editing ? 'Save' : 'Register',
|
|
205
|
+
onClick: apply,
|
|
206
|
+
disabled: create.isPending || update.isPending,
|
|
207
|
+
},
|
|
208
|
+
], children: _jsxs(Box, { sx: { 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, { sx: { 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, { sx: { 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, { sx: {
|
|
209
|
+
display: 'flex',
|
|
210
|
+
alignItems: 'center',
|
|
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, {
|
|
221
|
+
role: event.target.value,
|
|
222
|
+
}), 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
|
+
{
|
|
224
|
+
buttonType: 'default',
|
|
225
|
+
content: 'Keep it',
|
|
226
|
+
onClick: () => setRemoving(null),
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
buttonType: 'danger',
|
|
230
|
+
content: 'Remove',
|
|
231
|
+
onClick: confirmRemove,
|
|
232
|
+
disabled: remove.isPending,
|
|
233
|
+
},
|
|
234
|
+
], children: _jsx(Text, { sx: { fontSize: 1 }, children: "Sign-in through it stops immediately and its domains stop being claimed. If people have used it before, consider turning it off instead \u2014 that keeps its uid resolvable for the sign-in rows that name it." }) }))] }));
|
|
235
|
+
};
|
|
236
|
+
/**
|
|
237
|
+
* Proving one domain: what to publish, and the button that checks it.
|
|
238
|
+
*
|
|
239
|
+
* Kept as its own dialog rather than inline in the edit form, because
|
|
240
|
+
* proving a domain is not part of editing the provider's configuration —
|
|
241
|
+
* it is a separate act, done once DNS has actually been changed, and
|
|
242
|
+
* conflating the two would make "Save" look like it also verifies.
|
|
243
|
+
*/
|
|
244
|
+
const DomainVerificationDialog = ({ provider, onClose, fetchVerification, verify, }) => {
|
|
245
|
+
const { enqueueToast } = useToast();
|
|
246
|
+
const [selected, setSelected] = useState(provider.domains[0] ?? '');
|
|
247
|
+
const [record, setRecord] = useState(null);
|
|
248
|
+
const [verified, setVerified] = useState(provider.verifiedDomains.includes(selected));
|
|
249
|
+
const [refusal, setRefusal] = useState('');
|
|
250
|
+
const returnFocusRef = useRef(null);
|
|
251
|
+
const load = (domain) => {
|
|
252
|
+
setSelected(domain);
|
|
253
|
+
setRecord(null);
|
|
254
|
+
setRefusal('');
|
|
255
|
+
fetchVerification.mutate({ uid: provider.uid, domain }, {
|
|
256
|
+
onSuccess: result => {
|
|
257
|
+
setRecord(result.verification);
|
|
258
|
+
setVerified(result.verified);
|
|
259
|
+
},
|
|
260
|
+
onError: error => setRefusal(error.message),
|
|
261
|
+
});
|
|
262
|
+
};
|
|
263
|
+
const runVerify = () => {
|
|
264
|
+
setRefusal('');
|
|
265
|
+
verify.mutate({ uid: provider.uid, domain: selected }, {
|
|
266
|
+
onSuccess: updated => {
|
|
267
|
+
const done = updated.verifiedDomains.includes(selected);
|
|
268
|
+
setVerified(done);
|
|
269
|
+
if (done) {
|
|
270
|
+
enqueueToast(`${selected} is verified and now routes sign-in.`, {
|
|
271
|
+
variant: 'success',
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
},
|
|
275
|
+
onError: error => {
|
|
276
|
+
if (error instanceof IdentityProviderInvalid) {
|
|
277
|
+
// "No TXT record was found" and the like — the exact reason DNS
|
|
278
|
+
// did not check out, worth showing rather than a generic failure.
|
|
279
|
+
setRefusal(error.message);
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
setRefusal(error.message);
|
|
283
|
+
},
|
|
284
|
+
});
|
|
285
|
+
};
|
|
286
|
+
return (_jsx(Dialog, { title: `Verify a domain for ${provider.name}`, onClose: onClose, returnFocusRef: returnFocusRef, footerButtons: [
|
|
287
|
+
{ buttonType: 'default', content: 'Close', onClick: onClose },
|
|
288
|
+
], children: _jsxs(Box, { sx: { 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, { sx: {
|
|
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' }))] })] }) }));
|
|
298
|
+
};
|
|
299
|
+
export default IdentityProviders;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What the connected MCP clients are doing right now.
|
|
3
|
+
*
|
|
4
|
+
* One data call — `GET /api/mcp/v1/activity` — answers the whole page, so
|
|
5
|
+
* the counts and the four panels can never disagree with each other, and
|
|
6
|
+
* the home page's cards, which read the same query, can never disagree with
|
|
7
|
+
* this. It is refetched every ten seconds as the fallback under the
|
|
8
|
+
* ai-agents websocket, which patches the same cache entry.
|
|
9
|
+
*
|
|
10
|
+
* Top: the counts that answer "is anything happening". Then, in the idiom
|
|
11
|
+
* of the runtimes tables, four panels: the clients with a live grant, the
|
|
12
|
+
* tasks running, the sandboxes bound and the calls as they land. Each empty
|
|
13
|
+
* state names the next step rather than saying "nothing here".
|
|
14
|
+
*
|
|
15
|
+
* Milestone 1 draws the clients, the sandboxes, the calls and the counts;
|
|
16
|
+
* the running tasks and the live pane arrive with durable execution in
|
|
17
|
+
* milestone 2 and say so where they will be.
|
|
18
|
+
*
|
|
19
|
+
* @module views/mcp/McpDashboard
|
|
20
|
+
*/
|
|
21
|
+
import type { JSX } from 'react';
|
|
22
|
+
import { type McpErrorStateFn, type McpRoutes } from './types';
|
|
23
|
+
export interface McpDashboardProps {
|
|
24
|
+
/** The application's words for a failed request. */
|
|
25
|
+
errorState: McpErrorStateFn;
|
|
26
|
+
/** Where the surfaces this page links to live. */
|
|
27
|
+
/** Where this application puts the surfaces this view links to. */
|
|
28
|
+
routes: McpRoutes;
|
|
29
|
+
/** An owner's view of one organization, rather than the caller's own. */
|
|
30
|
+
org?: string;
|
|
31
|
+
/** Drawn without its heading, when the page around it carries one. */
|
|
32
|
+
showTitle?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Which part of the page to draw.
|
|
35
|
+
*
|
|
36
|
+
* Required, and there is no "draw everything": the whole thing on one page
|
|
37
|
+
* was a column of tables and blankslates a reader scrolled past to find
|
|
38
|
+
* the one they came for. Each part is a tab now, and a caller that has not
|
|
39
|
+
* decided which one it wants has not decided what it is showing.
|
|
40
|
+
*
|
|
41
|
+
* The counts belong to `'overview'` rather than repeating on each tab:
|
|
42
|
+
* they answer "is anything happening", which is the question somebody has
|
|
43
|
+
* *before* choosing where to look.
|
|
44
|
+
*/
|
|
45
|
+
section: McpDashboardSection;
|
|
46
|
+
}
|
|
47
|
+
/** The parts of the dashboard, each its own tab. */
|
|
48
|
+
export type McpDashboardSection = 'overview' | 'agents' | 'runs' | 'sandboxes' | 'calls';
|
|
49
|
+
export declare const McpDashboard: ({ errorState, routes, org, showTitle, section, }: McpDashboardProps) => JSX.Element;
|
|
50
|
+
export default McpDashboard;
|