@datalayer/core 1.1.59 → 1.1.66
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 +2 -2
- package/lib/api/DatalayerApi.d.ts +42 -1
- package/lib/api/DatalayerApi.js +90 -3
- package/lib/api/constants.d.ts +18 -0
- package/lib/api/constants.js +18 -0
- package/lib/api/contents/attachments.d.ts +9 -0
- package/lib/api/contents/attachments.js +43 -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 +15 -0
- package/lib/api/contents/datasets.js +45 -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 +53 -0
- package/lib/api/contents/sandboxUid.js +78 -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/iam/connectedAgents.d.ts +39 -0
- package/lib/api/iam/connectedAgents.js +52 -0
- package/lib/api/iam/index.d.ts +2 -1
- package/lib/api/iam/index.js +2 -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 +80 -0
- package/lib/api/iam/mcpPolicy.js +132 -0
- package/lib/api/iam/organizationTeams.d.ts +13 -0
- package/lib/api/iam/organizationTeams.js +43 -0
- package/lib/api/iam/serviceAgents.d.ts +68 -0
- package/lib/api/iam/serviceAgents.js +119 -0
- package/lib/api/index.d.ts +4 -1
- package/lib/api/index.js +3 -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 +125 -0
- package/lib/api/mcp/observability.js +254 -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/utils/validation.d.ts +1 -1
- package/lib/api/utils/validation.js +1 -1
- 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/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 +1 -0
- package/lib/components/animation/AnimatedText.js +0 -4
- 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 +18 -1
- package/lib/components/avatars/UserAvatar.js +14 -14
- 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 +10 -0
- package/lib/components/billing/BillingEntitySelect.js +0 -17
- package/lib/components/billing/index.js +0 -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 +31 -0
- package/lib/components/collaboration/LiveEditorCollaborators.js +98 -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 -2
- package/lib/components/display/DatalayerBox.js +6 -6
- 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/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 +10 -0
- package/lib/components/labels/StatusLabels.js +30 -1
- 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 +1 -0
- package/lib/components/principal/PrincipalAppearance.js +0 -8
- package/lib/components/principal/PrincipalAvatar.d.ts +9 -1
- package/lib/components/principal/PrincipalAvatar.js +25 -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 +31 -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 +7 -15
- 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/ScreencaptureButton.d.ts +1 -1
- package/lib/components/sharing/ShareAccessComponent.d.ts +15 -1
- package/lib/components/sharing/ShareAccessComponent.js +36 -23
- package/lib/components/sharing/SharingEditor.d.ts +17 -0
- package/lib/components/sharing/SharingEditor.js +0 -24
- 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/index.d.ts +2 -0
- package/lib/hooks/index.js +2 -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/useCache.d.ts +310 -105
- package/lib/hooks/useCache.js +142 -355
- package/lib/hooks/useContainsFocus.d.ts +1 -1
- package/lib/hooks/useContents.d.ts +313 -0
- package/lib/hooks/useContents.js +964 -0
- package/lib/hooks/useFocusTrap.d.ts +4 -4
- package/lib/hooks/useFocusTrap.js +1 -1
- package/lib/hooks/useMcp.d.ts +229 -0
- package/lib/hooks/useMcp.js +656 -0
- package/lib/hooks/useMobile.js +0 -5
- 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/useToast.js +0 -4
- package/lib/hooks/useUser.js +42 -0
- 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/McpAuditEvent.d.ts +52 -0
- package/lib/models/McpAuditEvent.js +5 -0
- package/lib/models/McpBinding.d.ts +51 -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/StartedBy.d.ts +57 -0
- package/lib/models/StartedBy.js +81 -0
- package/lib/models/UserDTO.js +4 -2
- package/lib/models/contents/__fixtures__/solr-codec.json +57 -0
- package/lib/models/contents/__fixtures__/v1-contracts.json +66 -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/state/substates/CoreState.d.ts +15 -7
- package/lib/state/substates/CoreState.js +18 -14
- package/lib/state/substates/IAMState.d.ts +1 -1
- package/lib/state/substates/IAMState.js +5 -5
- package/lib/state/substates/ProfileState.js +0 -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/WithSuspense.d.ts +1 -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/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/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 +100 -0
- package/lib/views/mcp/EnterpriseConsole.d.ts +74 -0
- package/lib/views/mcp/EnterpriseConsole.js +173 -0
- package/lib/views/mcp/McpDashboard.d.ts +50 -0
- package/lib/views/mcp/McpDashboard.js +347 -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 +50 -0
- package/lib/views/mcp/McpObservability.js +150 -0
- package/lib/views/mcp/OrganizationPolicy.d.ts +45 -0
- package/lib/views/mcp/OrganizationPolicy.js +107 -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 +125 -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 +67 -0
- package/lib/views/mcp/PolicyForm.js +91 -0
- package/lib/views/mcp/PolicyHistory.d.ts +45 -0
- package/lib/views/mcp/PolicyHistory.js +62 -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 +98 -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 +29 -0
- package/lib/views/mcp/index.js +37 -0
- package/lib/views/mcp/types.d.ts +66 -0
- package/lib/views/mcp/types.js +5 -0
- package/lib/views/secrets/SecretEdit.d.ts +5 -1
- package/lib/views/secrets/SecretEdit.js +2 -2
- package/lib/views/secrets/SecretNew.d.ts +11 -1
- package/lib/views/secrets/SecretNew.js +2 -2
- package/lib/views/secrets/Secrets.d.ts +12 -1
- package/lib/views/secrets/Secrets.js +2 -2
- package/package.json +28 -24
- package/scripts/generate-contents-types.py +169 -0
- package/scripts/generate-mcp-types.py +233 -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,964 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
|
6
|
+
import { cancelSyncSession, createAttachment, getBridge, getBridgeSession, isBridgeEnded, listBridges, revokeBridge, createSource, getCapabilities, getSyncSession, listSyncConflicts, listSyncSessions, resolveSyncConflict, createDatasetRevision, createDatasetPublication, cancelOperation, cancelTransfer, deleteHomeFolderObject, downloadHomeFolderObject, getOperation, getAttachmentManifest, getDatasetRevision, getTransfer, getSource, getSourceSharing, getHomeFolderQuota, getHomeFolder, listHomeFolderObjects, listHomeFolderObjectVersions, listSources, listAttachments, listDatasetRevisions, listDatasetPublications, listTransfers, restoreHomeFolderObject, revokeAttachment, unpublishDataset, archiveSource, replaceSourceSharing, statHomeFolderObject, uploadHomeFolderFile, updateSource, listCloudObjects, getCredentialDiagnostics, testCloudConnection, listPublishedDatasets, callMcpTool, createMcpSession, decideMcpApproval, discoverMcpTools, getMcpCall, getMcpSession, isMcpCallTerminal, listMcpApprovals, listMcpCalls, listMcpSessions, revokeMcpSession, testMcpSource, cancelDatasourceQuery, createDatasourceQuery, createDatasourceQueryTicket, discoverDatasourceSchema, downloadDatasourceQueryResults, drainDataserver, getDatasourceCapabilities, getDatasourceQuery, getDataserverStatus, isDatasourceQueryTerminal, listDatasourceQueries, resumeDataserver, revokeDataserver, rotateDataserverIdentity, saveDatasourceQueryAsDataset, testDatasource, testDataserver, attachRuntimeMounts, detachRuntimeMount, getRuntimeMounts, isRuntimeMountsSettled, } from '../api/contents/index.js';
|
|
7
|
+
import { useCoreStore, useIAMStore } from '../state/index.js';
|
|
8
|
+
import { queryKeys } from './useCache.js';
|
|
9
|
+
export const useDatasetRevisions = (sourceUid) => {
|
|
10
|
+
const token = useIAMStore(state => state.token);
|
|
11
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
12
|
+
return useQuery({
|
|
13
|
+
queryKey: queryKeys.contents.datasetRevisions(sourceUid ?? ''),
|
|
14
|
+
queryFn: () => listDatasetRevisions(token ?? '', sourceUid, contentsUrl),
|
|
15
|
+
enabled: Boolean(token && contentsUrl && sourceUid),
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
export const useDatasetRevision = (sourceUid, revisionUid) => {
|
|
19
|
+
const token = useIAMStore(state => state.token);
|
|
20
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
21
|
+
return useQuery({
|
|
22
|
+
queryKey: queryKeys.contents.datasetRevision(sourceUid ?? '', revisionUid ?? ''),
|
|
23
|
+
queryFn: () => getDatasetRevision(token ?? '', sourceUid, revisionUid, contentsUrl),
|
|
24
|
+
enabled: Boolean(token && contentsUrl && sourceUid && revisionUid),
|
|
25
|
+
});
|
|
26
|
+
};
|
|
27
|
+
export const useCreateDatasetRevision = () => {
|
|
28
|
+
const queryClient = useQueryClient();
|
|
29
|
+
const token = useIAMStore(state => state.token);
|
|
30
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
31
|
+
return useMutation({
|
|
32
|
+
mutationFn: ({ sourceUid, request, idempotencyKey }) => createDatasetRevision(token ?? '', sourceUid, request, idempotencyKey, contentsUrl),
|
|
33
|
+
onSuccess: revision => {
|
|
34
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.datasetRevisions(revision.sourceUid) });
|
|
35
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.source(revision.sourceUid) });
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
};
|
|
39
|
+
export const useDatasetPublications = (sourceUid) => {
|
|
40
|
+
const token = useIAMStore(state => state.token);
|
|
41
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
42
|
+
return useQuery({
|
|
43
|
+
queryKey: queryKeys.contents.datasetPublications(sourceUid ?? ''),
|
|
44
|
+
queryFn: () => listDatasetPublications(token ?? '', sourceUid, contentsUrl),
|
|
45
|
+
enabled: Boolean(token && contentsUrl && sourceUid),
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
export const useCreateDatasetPublication = () => {
|
|
49
|
+
const queryClient = useQueryClient();
|
|
50
|
+
const token = useIAMStore(state => state.token);
|
|
51
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
52
|
+
return useMutation({
|
|
53
|
+
mutationFn: ({ sourceUid, request, idempotencyKey }) => createDatasetPublication(token ?? '', sourceUid, request, idempotencyKey, contentsUrl),
|
|
54
|
+
onSuccess: publication => queryClient.invalidateQueries({
|
|
55
|
+
queryKey: queryKeys.contents.datasetPublications(publication.sourceUid),
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
};
|
|
59
|
+
export const useUnpublishDataset = () => {
|
|
60
|
+
const queryClient = useQueryClient();
|
|
61
|
+
const token = useIAMStore(state => state.token);
|
|
62
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
63
|
+
return useMutation({
|
|
64
|
+
mutationFn: ({ sourceUid, publicationUid }) => unpublishDataset(token ?? '', sourceUid, publicationUid, contentsUrl),
|
|
65
|
+
onSuccess: publication => queryClient.invalidateQueries({
|
|
66
|
+
queryKey: queryKeys.contents.datasetPublications(publication.sourceUid),
|
|
67
|
+
}),
|
|
68
|
+
});
|
|
69
|
+
};
|
|
70
|
+
export const useContentAttachments = (filters = {}) => {
|
|
71
|
+
const token = useIAMStore(state => state.token);
|
|
72
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
73
|
+
return useQuery({
|
|
74
|
+
queryKey: queryKeys.contents.attachmentList(filters),
|
|
75
|
+
queryFn: () => listAttachments(token ?? '', filters, contentsUrl),
|
|
76
|
+
enabled: Boolean(token && contentsUrl),
|
|
77
|
+
refetchInterval: filters.active ? 2_000 : false,
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
export const useContentAttachmentManifest = (sandboxUid) => {
|
|
81
|
+
const token = useIAMStore(state => state.token);
|
|
82
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
83
|
+
return useQuery({
|
|
84
|
+
queryKey: queryKeys.contents.attachmentManifest(sandboxUid ?? ''),
|
|
85
|
+
queryFn: () => getAttachmentManifest(token ?? '', sandboxUid, contentsUrl),
|
|
86
|
+
enabled: Boolean(token && contentsUrl && sandboxUid),
|
|
87
|
+
refetchInterval: 2_000,
|
|
88
|
+
});
|
|
89
|
+
};
|
|
90
|
+
export const useCreateContentAttachment = () => {
|
|
91
|
+
const queryClient = useQueryClient();
|
|
92
|
+
const token = useIAMStore(state => state.token);
|
|
93
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
94
|
+
return useMutation({
|
|
95
|
+
mutationFn: ({ request, idempotencyKey }) => createAttachment(token ?? '', request, idempotencyKey, contentsUrl),
|
|
96
|
+
onSuccess: attachment => {
|
|
97
|
+
queryClient.invalidateQueries({
|
|
98
|
+
queryKey: queryKeys.contents.attachments(),
|
|
99
|
+
});
|
|
100
|
+
queryClient.setQueryData(queryKeys.contents.attachmentManifest(attachment.sandboxUid), undefined);
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
export const useRevokeContentAttachment = () => {
|
|
105
|
+
const queryClient = useQueryClient();
|
|
106
|
+
const token = useIAMStore(state => state.token);
|
|
107
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
108
|
+
return useMutation({
|
|
109
|
+
mutationFn: attachmentUid => revokeAttachment(token ?? '', attachmentUid, contentsUrl),
|
|
110
|
+
onSuccess: () => queryClient.invalidateQueries({
|
|
111
|
+
queryKey: queryKeys.contents.attachments(),
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
};
|
|
115
|
+
/** Query the contents visible to the current user. */
|
|
116
|
+
export const useContentSources = (filters = {}) => {
|
|
117
|
+
const token = useIAMStore(state => state.token);
|
|
118
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
119
|
+
return useQuery({
|
|
120
|
+
queryKey: queryKeys.contents.sourceList(filters),
|
|
121
|
+
queryFn: () => listSources(token ?? '', filters, contentsUrl),
|
|
122
|
+
enabled: Boolean(token && contentsUrl),
|
|
123
|
+
staleTime: 30_000,
|
|
124
|
+
refetchOnWindowFocus: true,
|
|
125
|
+
});
|
|
126
|
+
};
|
|
127
|
+
/**
|
|
128
|
+
* What this deployment offers and what this caller may do with it.
|
|
129
|
+
*
|
|
130
|
+
* The Contents page shows entry points and a create menu; neither can be
|
|
131
|
+
* decided in the client, which knows neither what is running here nor what
|
|
132
|
+
* this principal is entitled to. Cached longer than a listing because it
|
|
133
|
+
* changes when the deployment does, not when a source does.
|
|
134
|
+
*/
|
|
135
|
+
export const useContentsCapabilities = () => {
|
|
136
|
+
const token = useIAMStore(state => state.token);
|
|
137
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
138
|
+
return useQuery({
|
|
139
|
+
queryKey: queryKeys.contents.capabilities(),
|
|
140
|
+
queryFn: () => getCapabilities(token ?? '', contentsUrl),
|
|
141
|
+
enabled: Boolean(token && contentsUrl),
|
|
142
|
+
staleTime: 300_000,
|
|
143
|
+
});
|
|
144
|
+
};
|
|
145
|
+
/** Query one catalog source, including its ETag and effective permissions. */
|
|
146
|
+
export const useContentSource = (sourceUid) => {
|
|
147
|
+
const token = useIAMStore(state => state.token);
|
|
148
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
149
|
+
return useQuery({
|
|
150
|
+
queryKey: queryKeys.contents.source(sourceUid ?? ''),
|
|
151
|
+
queryFn: () => getSource(token ?? '', sourceUid, contentsUrl),
|
|
152
|
+
enabled: Boolean(token && contentsUrl && sourceUid),
|
|
153
|
+
staleTime: 30_000,
|
|
154
|
+
refetchOnWindowFocus: true,
|
|
155
|
+
});
|
|
156
|
+
};
|
|
157
|
+
export const useCreateContentSource = () => {
|
|
158
|
+
const queryClient = useQueryClient();
|
|
159
|
+
const token = useIAMStore(state => state.token);
|
|
160
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
161
|
+
return useMutation({
|
|
162
|
+
mutationFn: ({ source, idempotencyKey }) => createSource(token ?? '', source, idempotencyKey, contentsUrl),
|
|
163
|
+
onSuccess: created => {
|
|
164
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.sources() });
|
|
165
|
+
queryClient.setQueryData(queryKeys.contents.source(created.value.source.uid), created);
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
export const useUpdateContentSource = () => {
|
|
170
|
+
const queryClient = useQueryClient();
|
|
171
|
+
const token = useIAMStore(state => state.token);
|
|
172
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
173
|
+
return useMutation({
|
|
174
|
+
mutationFn: ({ sourceUid, update, etag }) => updateSource(token ?? '', sourceUid, update, etag, contentsUrl),
|
|
175
|
+
onSuccess: updated => {
|
|
176
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.sources() });
|
|
177
|
+
queryClient.setQueryData(queryKeys.contents.source(updated.value.source.uid), updated);
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
};
|
|
181
|
+
export const useArchiveContentSource = () => {
|
|
182
|
+
const queryClient = useQueryClient();
|
|
183
|
+
const token = useIAMStore(state => state.token);
|
|
184
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
185
|
+
return useMutation({
|
|
186
|
+
mutationFn: ({ sourceUid, etag }) => archiveSource(token ?? '', sourceUid, etag, contentsUrl),
|
|
187
|
+
onSuccess: archived => {
|
|
188
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.sources() });
|
|
189
|
+
queryClient.setQueryData(queryKeys.contents.source(archived.value.source.uid), archived);
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
};
|
|
193
|
+
export const useContentSourceSharing = (sourceUid) => {
|
|
194
|
+
const token = useIAMStore(state => state.token);
|
|
195
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
196
|
+
return useQuery({
|
|
197
|
+
queryKey: queryKeys.contents.sourceSharing(sourceUid ?? ''),
|
|
198
|
+
queryFn: () => getSourceSharing(token ?? '', sourceUid, contentsUrl),
|
|
199
|
+
enabled: Boolean(token && contentsUrl && sourceUid),
|
|
200
|
+
});
|
|
201
|
+
};
|
|
202
|
+
export const useReplaceContentSourceSharing = () => {
|
|
203
|
+
const queryClient = useQueryClient();
|
|
204
|
+
const token = useIAMStore(state => state.token);
|
|
205
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
206
|
+
return useMutation({
|
|
207
|
+
mutationFn: ({ sourceUid, sharing, etag }) => replaceSourceSharing(token ?? '', sourceUid, sharing, etag, contentsUrl),
|
|
208
|
+
onSuccess: updated => {
|
|
209
|
+
queryClient.invalidateQueries({
|
|
210
|
+
queryKey: queryKeys.contents.sourceSharing(updated.value.source.uid),
|
|
211
|
+
});
|
|
212
|
+
queryClient.setQueryData(queryKeys.contents.source(updated.value.source.uid), updated);
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
/** Resolve and, on first access, provision the authenticated user's folder. */
|
|
217
|
+
export const useHomeFolder = () => {
|
|
218
|
+
const token = useIAMStore(state => state.token);
|
|
219
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
220
|
+
return useQuery({
|
|
221
|
+
queryKey: queryKeys.contents.homeFolder(),
|
|
222
|
+
queryFn: () => getHomeFolder(token ?? '', contentsUrl),
|
|
223
|
+
enabled: Boolean(token && contentsUrl),
|
|
224
|
+
staleTime: 5 * 60_000,
|
|
225
|
+
refetchOnWindowFocus: true,
|
|
226
|
+
});
|
|
227
|
+
};
|
|
228
|
+
/** Query durable used, reserved and configured Home Folder capacity. */
|
|
229
|
+
export const useHomeFolderQuota = () => {
|
|
230
|
+
const token = useIAMStore(state => state.token);
|
|
231
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
232
|
+
return useQuery({
|
|
233
|
+
queryKey: queryKeys.contents.homeFolderQuota(),
|
|
234
|
+
queryFn: () => getHomeFolderQuota(token ?? '', contentsUrl),
|
|
235
|
+
enabled: Boolean(token && contentsUrl),
|
|
236
|
+
staleTime: 30_000,
|
|
237
|
+
refetchOnWindowFocus: true,
|
|
238
|
+
});
|
|
239
|
+
};
|
|
240
|
+
/** Browse the authenticated user's persistent folder. */
|
|
241
|
+
export const useHomeFolderObjects = (filters = {}) => {
|
|
242
|
+
const token = useIAMStore(state => state.token);
|
|
243
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
244
|
+
return useQuery({
|
|
245
|
+
queryKey: queryKeys.contents.homeFolderObjects(filters),
|
|
246
|
+
queryFn: () => listHomeFolderObjects(token ?? '', filters, contentsUrl),
|
|
247
|
+
enabled: Boolean(token && contentsUrl),
|
|
248
|
+
staleTime: 30_000,
|
|
249
|
+
refetchOnWindowFocus: true,
|
|
250
|
+
});
|
|
251
|
+
};
|
|
252
|
+
/** Resolve one Home Folder path to its current object metadata. */
|
|
253
|
+
export const useHomeFolderObject = (path) => {
|
|
254
|
+
const token = useIAMStore(state => state.token);
|
|
255
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
256
|
+
return useQuery({
|
|
257
|
+
queryKey: queryKeys.contents.homeFolderObject(path ?? ''),
|
|
258
|
+
queryFn: () => statHomeFolderObject(token ?? '', path, contentsUrl),
|
|
259
|
+
enabled: Boolean(token && contentsUrl && path),
|
|
260
|
+
});
|
|
261
|
+
};
|
|
262
|
+
/** List immutable versions for a Home Folder object. */
|
|
263
|
+
export const useHomeFolderObjectVersions = (objectUid, options = {}) => {
|
|
264
|
+
const token = useIAMStore(state => state.token);
|
|
265
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
266
|
+
return useQuery({
|
|
267
|
+
queryKey: queryKeys.contents.homeFolderObjectVersions(objectUid ?? '', options.cursor),
|
|
268
|
+
queryFn: () => listHomeFolderObjectVersions(token ?? '', objectUid, options, contentsUrl),
|
|
269
|
+
enabled: Boolean(token && contentsUrl && objectUid),
|
|
270
|
+
});
|
|
271
|
+
};
|
|
272
|
+
/** Soft-delete a Home Folder object and invalidate its browse metadata. */
|
|
273
|
+
export const useDeleteHomeFolderObject = () => {
|
|
274
|
+
const queryClient = useQueryClient();
|
|
275
|
+
const token = useIAMStore(state => state.token);
|
|
276
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
277
|
+
return useMutation({
|
|
278
|
+
mutationFn: ({ objectUid, idempotencyKey }) => deleteHomeFolderObject(token ?? '', objectUid, idempotencyKey, contentsUrl),
|
|
279
|
+
onSuccess: object => {
|
|
280
|
+
queryClient.invalidateQueries({
|
|
281
|
+
queryKey: queryKeys.contents.homeFolder(),
|
|
282
|
+
});
|
|
283
|
+
queryClient.setQueryData(queryKeys.contents.homeFolderObject(object.path), object);
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
};
|
|
287
|
+
/** Restore an immutable version as the object's new current version. */
|
|
288
|
+
export const useRestoreHomeFolderObject = () => {
|
|
289
|
+
const queryClient = useQueryClient();
|
|
290
|
+
const token = useIAMStore(state => state.token);
|
|
291
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
292
|
+
return useMutation({
|
|
293
|
+
mutationFn: ({ objectUid, versionUid, idempotencyKey }) => restoreHomeFolderObject(token ?? '', objectUid, { versionUid }, idempotencyKey, contentsUrl),
|
|
294
|
+
onSuccess: object => {
|
|
295
|
+
queryClient.invalidateQueries({
|
|
296
|
+
queryKey: queryKeys.contents.homeFolder(),
|
|
297
|
+
});
|
|
298
|
+
queryClient.setQueryData(queryKeys.contents.homeFolderObject(object.path), object);
|
|
299
|
+
queryClient.invalidateQueries({
|
|
300
|
+
queryKey: [
|
|
301
|
+
...queryKeys.contents.homeFolder(),
|
|
302
|
+
'objects',
|
|
303
|
+
object.uid,
|
|
304
|
+
'versions',
|
|
305
|
+
],
|
|
306
|
+
});
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
};
|
|
310
|
+
const terminalOperationStatuses = new Set(['succeeded', 'failed', 'cancelled']);
|
|
311
|
+
/** Query an operation, polling only while it can still change. */
|
|
312
|
+
export const useContentOperation = (operationUid) => {
|
|
313
|
+
const token = useIAMStore(state => state.token);
|
|
314
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
315
|
+
return useQuery({
|
|
316
|
+
queryKey: queryKeys.contents.operation(operationUid ?? ''),
|
|
317
|
+
queryFn: () => getOperation(token ?? '', operationUid, contentsUrl),
|
|
318
|
+
enabled: Boolean(token && contentsUrl && operationUid),
|
|
319
|
+
refetchInterval: query => query.state.data && terminalOperationStatuses.has(query.state.data.status)
|
|
320
|
+
? false
|
|
321
|
+
: 1_000,
|
|
322
|
+
refetchOnWindowFocus: true,
|
|
323
|
+
});
|
|
324
|
+
};
|
|
325
|
+
/** Request cancellation and refresh the shared operation cache. */
|
|
326
|
+
export const useCancelContentOperation = () => {
|
|
327
|
+
const queryClient = useQueryClient();
|
|
328
|
+
const token = useIAMStore(state => state.token);
|
|
329
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
330
|
+
return useMutation({
|
|
331
|
+
mutationFn: operationUid => cancelOperation(token ?? '', operationUid, contentsUrl),
|
|
332
|
+
onSuccess: operation => {
|
|
333
|
+
queryClient.setQueryData(queryKeys.contents.operation(operation.uid), operation);
|
|
334
|
+
},
|
|
335
|
+
});
|
|
336
|
+
};
|
|
337
|
+
/** Poll a resumable transfer so progress survives navigation and reconnects. */
|
|
338
|
+
export const useContentTransfer = (transferUid) => {
|
|
339
|
+
const token = useIAMStore(state => state.token);
|
|
340
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
341
|
+
return useQuery({
|
|
342
|
+
queryKey: queryKeys.contents.transfer(transferUid ?? ''),
|
|
343
|
+
queryFn: () => getTransfer(token ?? '', transferUid, contentsUrl),
|
|
344
|
+
enabled: Boolean(token && contentsUrl && transferUid),
|
|
345
|
+
refetchInterval: query => query.state.data && terminalOperationStatuses.has(query.state.data.status)
|
|
346
|
+
? false
|
|
347
|
+
: 1_000,
|
|
348
|
+
refetchOnWindowFocus: true,
|
|
349
|
+
});
|
|
350
|
+
};
|
|
351
|
+
/** List the authenticated user's recent or active durable transfers. */
|
|
352
|
+
export const useContentTransfers = (filters = {}) => {
|
|
353
|
+
const token = useIAMStore(state => state.token);
|
|
354
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
355
|
+
return useQuery({
|
|
356
|
+
queryKey: queryKeys.contents.transferList(filters),
|
|
357
|
+
queryFn: () => listTransfers(token ?? '', filters, contentsUrl),
|
|
358
|
+
enabled: Boolean(token && contentsUrl),
|
|
359
|
+
refetchInterval: filters.active ? 1_000 : false,
|
|
360
|
+
refetchOnWindowFocus: true,
|
|
361
|
+
});
|
|
362
|
+
};
|
|
363
|
+
/** Cancel a transfer and refresh its durable progress plus folder listing. */
|
|
364
|
+
export const useCancelContentTransfer = () => {
|
|
365
|
+
const queryClient = useQueryClient();
|
|
366
|
+
const token = useIAMStore(state => state.token);
|
|
367
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
368
|
+
return useMutation({
|
|
369
|
+
mutationFn: transferUid => cancelTransfer(token ?? '', transferUid, contentsUrl),
|
|
370
|
+
onSuccess: transfer => {
|
|
371
|
+
queryClient.setQueryData(queryKeys.contents.transfer(transfer.uid), transfer);
|
|
372
|
+
queryClient.invalidateQueries({
|
|
373
|
+
queryKey: queryKeys.contents.homeFolder(),
|
|
374
|
+
});
|
|
375
|
+
},
|
|
376
|
+
});
|
|
377
|
+
};
|
|
378
|
+
/** The authenticated user's synchronization sessions, active ones polled. */
|
|
379
|
+
export const useSyncSessions = (filters = {}) => {
|
|
380
|
+
const token = useIAMStore(state => state.token);
|
|
381
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
382
|
+
return useQuery({
|
|
383
|
+
queryKey: queryKeys.contents.syncSessionList(filters),
|
|
384
|
+
queryFn: () => listSyncSessions(token ?? '', filters, contentsUrl),
|
|
385
|
+
enabled: Boolean(token && contentsUrl),
|
|
386
|
+
refetchInterval: filters.active ? 5_000 : false,
|
|
387
|
+
refetchOnWindowFocus: true,
|
|
388
|
+
});
|
|
389
|
+
};
|
|
390
|
+
/** One session, polled while it is still doing something. */
|
|
391
|
+
export const useSyncSession = (sessionUid) => {
|
|
392
|
+
const token = useIAMStore(state => state.token);
|
|
393
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
394
|
+
return useQuery({
|
|
395
|
+
queryKey: queryKeys.contents.syncSession(sessionUid ?? ''),
|
|
396
|
+
queryFn: () => getSyncSession(token ?? '', sessionUid, contentsUrl),
|
|
397
|
+
enabled: Boolean(token && contentsUrl && sessionUid),
|
|
398
|
+
refetchInterval: query => query.state.data && terminalOperationStatuses.has(query.state.data.status)
|
|
399
|
+
? false
|
|
400
|
+
: 5_000,
|
|
401
|
+
});
|
|
402
|
+
};
|
|
403
|
+
/** The paths a session left for a person to decide. */
|
|
404
|
+
export const useSyncConflicts = (sessionUid, openOnly = true) => {
|
|
405
|
+
const token = useIAMStore(state => state.token);
|
|
406
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
407
|
+
return useQuery({
|
|
408
|
+
queryKey: [...queryKeys.contents.syncConflicts(sessionUid ?? ''), openOnly],
|
|
409
|
+
queryFn: () => listSyncConflicts(token ?? '', sessionUid, { openOnly }, contentsUrl),
|
|
410
|
+
enabled: Boolean(token && contentsUrl && sessionUid),
|
|
411
|
+
});
|
|
412
|
+
};
|
|
413
|
+
/** Decide a conflict; the client applies the decision on its next pass. */
|
|
414
|
+
export const useResolveSyncConflict = () => {
|
|
415
|
+
const queryClient = useQueryClient();
|
|
416
|
+
const token = useIAMStore(state => state.token);
|
|
417
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
418
|
+
return useMutation({
|
|
419
|
+
mutationFn: ({ sessionUid, conflictUid, use }) => resolveSyncConflict(token ?? '', sessionUid, conflictUid, { use }, contentsUrl),
|
|
420
|
+
onSuccess: session => {
|
|
421
|
+
queryClient.setQueryData(queryKeys.contents.syncSession(session.uid), session);
|
|
422
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.syncConflicts(session.uid) });
|
|
423
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.syncSessions() });
|
|
424
|
+
},
|
|
425
|
+
});
|
|
426
|
+
};
|
|
427
|
+
/** End a session from the page; the client finds out on its next call. */
|
|
428
|
+
export const useCancelSyncSession = () => {
|
|
429
|
+
const queryClient = useQueryClient();
|
|
430
|
+
const token = useIAMStore(state => state.token);
|
|
431
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
432
|
+
return useMutation({
|
|
433
|
+
mutationFn: sessionUid => cancelSyncSession(token ?? '', sessionUid, contentsUrl),
|
|
434
|
+
onSuccess: session => {
|
|
435
|
+
queryClient.setQueryData(queryKeys.contents.syncSession(session.uid), session);
|
|
436
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.syncSessions() });
|
|
437
|
+
},
|
|
438
|
+
});
|
|
439
|
+
};
|
|
440
|
+
/**
|
|
441
|
+
* The bridge of one `local-bridge` attachment, polled while it can still
|
|
442
|
+
* change; `null` when none has been opened for it yet.
|
|
443
|
+
*/
|
|
444
|
+
export const useBridgeSession = (attachmentUid) => {
|
|
445
|
+
const token = useIAMStore(state => state.token);
|
|
446
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
447
|
+
return useQuery({
|
|
448
|
+
queryKey: queryKeys.contents.bridgeSession(attachmentUid ?? ''),
|
|
449
|
+
queryFn: () => getBridgeSession(token ?? '', attachmentUid, contentsUrl),
|
|
450
|
+
enabled: Boolean(token && contentsUrl && attachmentUid),
|
|
451
|
+
// A bridge changes state on its own — a laptop lid closes — so the page
|
|
452
|
+
// keeps looking until the bridge reaches a state it will not leave.
|
|
453
|
+
refetchInterval: query => query.state.data && isBridgeEnded(query.state.data) ? false : 5_000,
|
|
454
|
+
refetchOnWindowFocus: true,
|
|
455
|
+
});
|
|
456
|
+
};
|
|
457
|
+
/** The caller's bridge sessions; the active ones polled. */
|
|
458
|
+
export const useBridges = (filters = {}) => {
|
|
459
|
+
const token = useIAMStore(state => state.token);
|
|
460
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
461
|
+
return useQuery({
|
|
462
|
+
queryKey: queryKeys.contents.bridgeList(filters),
|
|
463
|
+
queryFn: () => listBridges(token ?? '', filters, contentsUrl),
|
|
464
|
+
enabled: Boolean(token && contentsUrl),
|
|
465
|
+
refetchInterval: filters.active ? 5_000 : false,
|
|
466
|
+
refetchOnWindowFocus: true,
|
|
467
|
+
});
|
|
468
|
+
};
|
|
469
|
+
/** One session by uid, polled until it has ended. */
|
|
470
|
+
export const useBridge = (bridgeUid) => {
|
|
471
|
+
const token = useIAMStore(state => state.token);
|
|
472
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
473
|
+
return useQuery({
|
|
474
|
+
queryKey: queryKeys.contents.bridge(bridgeUid ?? ''),
|
|
475
|
+
queryFn: () => getBridge(token ?? '', bridgeUid, contentsUrl),
|
|
476
|
+
enabled: Boolean(token && contentsUrl && bridgeUid),
|
|
477
|
+
refetchInterval: query => query.state.data && isBridgeEnded(query.state.data) ? false : 5_000,
|
|
478
|
+
});
|
|
479
|
+
};
|
|
480
|
+
/**
|
|
481
|
+
* Revoke a bridge by uid. The attachment goes `revoking` with it on the
|
|
482
|
+
* service, so every attachment view refreshes as well as the bridge ones.
|
|
483
|
+
*/
|
|
484
|
+
export const useRevokeBridge = () => {
|
|
485
|
+
const queryClient = useQueryClient();
|
|
486
|
+
const token = useIAMStore(state => state.token);
|
|
487
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
488
|
+
return useMutation({
|
|
489
|
+
mutationFn: bridgeUid => revokeBridge(token ?? '', bridgeUid, contentsUrl),
|
|
490
|
+
onSuccess: bridge => {
|
|
491
|
+
queryClient.setQueryData(queryKeys.contents.bridge(bridge.uid), bridge);
|
|
492
|
+
queryClient.setQueryData(queryKeys.contents.bridgeSession(bridge.attachmentUid), bridge);
|
|
493
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.bridges() });
|
|
494
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.attachments() });
|
|
495
|
+
},
|
|
496
|
+
});
|
|
497
|
+
};
|
|
498
|
+
/** Upload a browser file with resumable verified parts and durable progress. */
|
|
499
|
+
export const useUploadHomeFolderFile = () => {
|
|
500
|
+
const queryClient = useQueryClient();
|
|
501
|
+
const token = useIAMStore(state => state.token);
|
|
502
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
503
|
+
return useMutation({
|
|
504
|
+
mutationFn: ({ path, content, ...options }) => uploadHomeFolderFile(token ?? '', path, content, options, contentsUrl),
|
|
505
|
+
onSuccess: transfer => {
|
|
506
|
+
queryClient.setQueryData(queryKeys.contents.transfer(transfer.uid), transfer);
|
|
507
|
+
queryClient.invalidateQueries({
|
|
508
|
+
queryKey: queryKeys.contents.homeFolder(),
|
|
509
|
+
});
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
};
|
|
513
|
+
/** Fetch a complete object version or a resumable HTTP byte range. */
|
|
514
|
+
export const useDownloadHomeFolderObject = () => {
|
|
515
|
+
const token = useIAMStore(state => state.token);
|
|
516
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
517
|
+
return useMutation({
|
|
518
|
+
mutationFn: ({ objectUid, ...options }) => downloadHomeFolderObject(token ?? '', objectUid, options, contentsUrl),
|
|
519
|
+
});
|
|
520
|
+
};
|
|
521
|
+
/** One page of a Cloud Storage source under a prefix. */
|
|
522
|
+
export const useCloudObjects = (sourceUid, options = {}) => {
|
|
523
|
+
const token = useIAMStore(state => state.token);
|
|
524
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
525
|
+
return useQuery({
|
|
526
|
+
queryKey: queryKeys.contents.cloudObjects(sourceUid ?? '', options.prefix, options.cursor),
|
|
527
|
+
queryFn: () => listCloudObjects(token ?? '', sourceUid, options, contentsUrl),
|
|
528
|
+
enabled: Boolean(token && contentsUrl && sourceUid),
|
|
529
|
+
staleTime: 30_000,
|
|
530
|
+
});
|
|
531
|
+
};
|
|
532
|
+
/** Whether the source's credential is referenced and resolvable — never its value. */
|
|
533
|
+
export const useCredentialDiagnostics = (sourceUid) => {
|
|
534
|
+
const token = useIAMStore(state => state.token);
|
|
535
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
536
|
+
return useQuery({
|
|
537
|
+
queryKey: queryKeys.contents.credentialDiagnostics(sourceUid ?? ''),
|
|
538
|
+
queryFn: () => getCredentialDiagnostics(token ?? '', sourceUid, contentsUrl),
|
|
539
|
+
enabled: Boolean(token && contentsUrl && sourceUid),
|
|
540
|
+
staleTime: 60_000,
|
|
541
|
+
});
|
|
542
|
+
};
|
|
543
|
+
/** Try the bucket with the credential attached; the answer is a verdict. */
|
|
544
|
+
export const useTestCloudConnection = () => {
|
|
545
|
+
const token = useIAMStore(state => state.token);
|
|
546
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
547
|
+
return useMutation({
|
|
548
|
+
mutationFn: sourceUid => testCloudConnection(token ?? '', sourceUid, contentsUrl),
|
|
549
|
+
});
|
|
550
|
+
};
|
|
551
|
+
/** Every Dataset publication, for the Library. */
|
|
552
|
+
export const usePublishedDatasets = () => {
|
|
553
|
+
const token = useIAMStore(state => state.token);
|
|
554
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
555
|
+
return useQuery({
|
|
556
|
+
queryKey: queryKeys.contents.publishedDatasets(),
|
|
557
|
+
queryFn: () => listPublishedDatasets(token ?? '', contentsUrl),
|
|
558
|
+
enabled: Boolean(token && contentsUrl),
|
|
559
|
+
staleTime: 30_000,
|
|
560
|
+
});
|
|
561
|
+
};
|
|
562
|
+
// -- MCP ----------------------------------------------------------------
|
|
563
|
+
//
|
|
564
|
+
// An MCP source is a server somebody connected. None of these hooks talk to
|
|
565
|
+
// it: Contents does, through a session it opens for the caller. The browser
|
|
566
|
+
// sees tool definitions, call records and approvals.
|
|
567
|
+
/** The tools and resources the server behind a source offers. */
|
|
568
|
+
export const useMcpTools = (sourceUid) => {
|
|
569
|
+
const token = useIAMStore(state => state.token);
|
|
570
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
571
|
+
return useQuery({
|
|
572
|
+
queryKey: queryKeys.contents.mcpTools(sourceUid ?? ''),
|
|
573
|
+
queryFn: () => discoverMcpTools(token ?? '', sourceUid, contentsUrl),
|
|
574
|
+
enabled: Boolean(token && contentsUrl && sourceUid),
|
|
575
|
+
staleTime: 300_000,
|
|
576
|
+
});
|
|
577
|
+
};
|
|
578
|
+
/** Try the server through the source; the answer is a verdict. */
|
|
579
|
+
export const useMcpHealth = () => {
|
|
580
|
+
const token = useIAMStore(state => state.token);
|
|
581
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
582
|
+
return useMutation({
|
|
583
|
+
mutationFn: sourceUid => testMcpSource(token ?? '', sourceUid, contentsUrl),
|
|
584
|
+
});
|
|
585
|
+
};
|
|
586
|
+
/**
|
|
587
|
+
* The sessions the caller opened, optionally narrowed to one source or to
|
|
588
|
+
* the active ones. The contract lists them whole; the narrowing is here.
|
|
589
|
+
*/
|
|
590
|
+
export const useMcpSessions = (filters = {}, options = {}) => {
|
|
591
|
+
const token = useIAMStore(state => state.token);
|
|
592
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
593
|
+
return useQuery({
|
|
594
|
+
queryKey: queryKeys.contents.mcpSessionList(filters),
|
|
595
|
+
queryFn: async () => {
|
|
596
|
+
const page = await listMcpSessions(token ?? '', contentsUrl);
|
|
597
|
+
return {
|
|
598
|
+
items: page.items.filter(session => (!filters.sourceUid || session.sourceUid === filters.sourceUid) &&
|
|
599
|
+
(!filters.active || session.status === 'active')),
|
|
600
|
+
};
|
|
601
|
+
},
|
|
602
|
+
enabled: Boolean(token && contentsUrl) && (options.enabled ?? true),
|
|
603
|
+
staleTime: 30_000,
|
|
604
|
+
});
|
|
605
|
+
};
|
|
606
|
+
export const useMcpSession = (sessionUid) => {
|
|
607
|
+
const token = useIAMStore(state => state.token);
|
|
608
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
609
|
+
return useQuery({
|
|
610
|
+
queryKey: queryKeys.contents.mcpSession(sessionUid ?? ''),
|
|
611
|
+
queryFn: () => getMcpSession(token ?? '', sessionUid, contentsUrl),
|
|
612
|
+
enabled: Boolean(token && contentsUrl && sessionUid),
|
|
613
|
+
staleTime: 30_000,
|
|
614
|
+
});
|
|
615
|
+
};
|
|
616
|
+
export const useCreateMcpSession = () => {
|
|
617
|
+
const queryClient = useQueryClient();
|
|
618
|
+
const token = useIAMStore(state => state.token);
|
|
619
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
620
|
+
return useMutation({
|
|
621
|
+
mutationFn: ({ request, idempotencyKey }) => createMcpSession(token ?? '', request, idempotencyKey, contentsUrl),
|
|
622
|
+
onSuccess: () => {
|
|
623
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.mcpSessions() });
|
|
624
|
+
},
|
|
625
|
+
});
|
|
626
|
+
};
|
|
627
|
+
export const useRevokeMcpSession = () => {
|
|
628
|
+
const queryClient = useQueryClient();
|
|
629
|
+
const token = useIAMStore(state => state.token);
|
|
630
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
631
|
+
return useMutation({
|
|
632
|
+
mutationFn: sessionUid => revokeMcpSession(token ?? '', sessionUid, contentsUrl),
|
|
633
|
+
onSuccess: () => {
|
|
634
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.mcpSessions() });
|
|
635
|
+
},
|
|
636
|
+
});
|
|
637
|
+
};
|
|
638
|
+
/**
|
|
639
|
+
* One call, watched until the service is done with it.
|
|
640
|
+
*
|
|
641
|
+
* A call that is pending approval or running is polled; a terminal one is
|
|
642
|
+
* not, so a page that shows a finished call does not keep asking.
|
|
643
|
+
*/
|
|
644
|
+
export const useMcpCall = (sessionUid, callUid) => {
|
|
645
|
+
const token = useIAMStore(state => state.token);
|
|
646
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
647
|
+
return useQuery({
|
|
648
|
+
queryKey: queryKeys.contents.mcpCall(sessionUid ?? '', callUid ?? ''),
|
|
649
|
+
queryFn: () => getMcpCall(token ?? '', sessionUid, callUid, contentsUrl),
|
|
650
|
+
enabled: Boolean(token && contentsUrl && sessionUid && callUid),
|
|
651
|
+
refetchInterval: query => query.state.data && isMcpCallTerminal(query.state.data.status) ? false : 2_000,
|
|
652
|
+
});
|
|
653
|
+
};
|
|
654
|
+
/** The calls made through a session — the provenance of what they acquired. */
|
|
655
|
+
export const useMcpCalls = (sessionUid) => {
|
|
656
|
+
const token = useIAMStore(state => state.token);
|
|
657
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
658
|
+
return useQuery({
|
|
659
|
+
queryKey: queryKeys.contents.mcpCalls(sessionUid ?? ''),
|
|
660
|
+
queryFn: () => listMcpCalls(token ?? '', sessionUid, contentsUrl),
|
|
661
|
+
enabled: Boolean(token && contentsUrl && sessionUid),
|
|
662
|
+
staleTime: 15_000,
|
|
663
|
+
});
|
|
664
|
+
};
|
|
665
|
+
export const useCallMcpTool = () => {
|
|
666
|
+
const queryClient = useQueryClient();
|
|
667
|
+
const token = useIAMStore(state => state.token);
|
|
668
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
669
|
+
return useMutation({
|
|
670
|
+
mutationFn: ({ sessionUid, request }) => callMcpTool(token ?? '', sessionUid, request, contentsUrl),
|
|
671
|
+
onSuccess: call => {
|
|
672
|
+
queryClient.setQueryData(queryKeys.contents.mcpCall(call.sessionUid, call.uid), call);
|
|
673
|
+
queryClient.invalidateQueries({
|
|
674
|
+
queryKey: queryKeys.contents.mcpCalls(call.sessionUid),
|
|
675
|
+
});
|
|
676
|
+
if (call.status === 'pending-approval') {
|
|
677
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.mcpApprovals() });
|
|
678
|
+
}
|
|
679
|
+
},
|
|
680
|
+
});
|
|
681
|
+
};
|
|
682
|
+
/**
|
|
683
|
+
* The approvals waiting on the caller, or those already decided. The
|
|
684
|
+
* contract filters on the status alone; a source narrows the answer here.
|
|
685
|
+
*/
|
|
686
|
+
export const useMcpApprovals = (status = 'pending', filters = {}, options = {}) => {
|
|
687
|
+
const token = useIAMStore(state => state.token);
|
|
688
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
689
|
+
const listFilters = { status, ...filters };
|
|
690
|
+
return useQuery({
|
|
691
|
+
queryKey: queryKeys.contents.mcpApprovalList(listFilters),
|
|
692
|
+
queryFn: async () => {
|
|
693
|
+
const page = await listMcpApprovals(token ?? '', { status }, contentsUrl);
|
|
694
|
+
return {
|
|
695
|
+
items: filters.sourceUid
|
|
696
|
+
? page.items.filter(approval => approval.sourceUid === filters.sourceUid)
|
|
697
|
+
: page.items,
|
|
698
|
+
};
|
|
699
|
+
},
|
|
700
|
+
enabled: Boolean(token && contentsUrl) && (options.enabled ?? true),
|
|
701
|
+
staleTime: 10_000,
|
|
702
|
+
refetchInterval: status === 'pending' ? 15_000 : false,
|
|
703
|
+
});
|
|
704
|
+
};
|
|
705
|
+
/** Approve or reject a pending call; the affected call is refreshed. */
|
|
706
|
+
export const useDecideMcpApproval = () => {
|
|
707
|
+
const queryClient = useQueryClient();
|
|
708
|
+
const token = useIAMStore(state => state.token);
|
|
709
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
710
|
+
return useMutation({
|
|
711
|
+
mutationFn: ({ approvalUid, decision, note }) => decideMcpApproval(token ?? '', approvalUid, decision, note, contentsUrl),
|
|
712
|
+
onSuccess: approval => {
|
|
713
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.mcpApprovals() });
|
|
714
|
+
queryClient.invalidateQueries({
|
|
715
|
+
queryKey: queryKeys.contents.mcpCalls(approval.sessionUid),
|
|
716
|
+
});
|
|
717
|
+
},
|
|
718
|
+
});
|
|
719
|
+
};
|
|
720
|
+
// -- Datasources ----------------------------------------------------------
|
|
721
|
+
//
|
|
722
|
+
// A Datasource is a database somebody connected. None of these hooks talk
|
|
723
|
+
// to it: Contents does, with the credential it holds, directly or through a
|
|
724
|
+
// Dataserver. The browser sees verdicts, schemas and query jobs — and reads
|
|
725
|
+
// a finished result as bytes, by range.
|
|
726
|
+
/** The tables and columns a source exposes; asked once, then kept. */
|
|
727
|
+
export const useDatasourceSchema = (sourceUid, options = {}) => {
|
|
728
|
+
const token = useIAMStore(state => state.token);
|
|
729
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
730
|
+
return useQuery({
|
|
731
|
+
queryKey: queryKeys.contents.datasourceSchema(sourceUid ?? ''),
|
|
732
|
+
queryFn: () => discoverDatasourceSchema(token ?? '', sourceUid, contentsUrl),
|
|
733
|
+
enabled: Boolean(token && contentsUrl && sourceUid) && (options.enabled ?? true),
|
|
734
|
+
staleTime: 300_000,
|
|
735
|
+
});
|
|
736
|
+
};
|
|
737
|
+
/** What the source may be asked, and how the answer can travel. */
|
|
738
|
+
export const useDatasourceCapabilities = (sourceUid) => {
|
|
739
|
+
const token = useIAMStore(state => state.token);
|
|
740
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
741
|
+
return useQuery({
|
|
742
|
+
queryKey: queryKeys.contents.datasourceCapabilities(sourceUid ?? ''),
|
|
743
|
+
queryFn: () => getDatasourceCapabilities(token ?? '', sourceUid, contentsUrl),
|
|
744
|
+
enabled: Boolean(token && contentsUrl && sourceUid),
|
|
745
|
+
staleTime: 300_000,
|
|
746
|
+
});
|
|
747
|
+
};
|
|
748
|
+
/** Try the database through the source; the answer is a verdict. */
|
|
749
|
+
export const useTestDatasource = () => {
|
|
750
|
+
const token = useIAMStore(state => state.token);
|
|
751
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
752
|
+
return useMutation({
|
|
753
|
+
mutationFn: sourceUid => testDatasource(token ?? '', sourceUid, contentsUrl),
|
|
754
|
+
});
|
|
755
|
+
};
|
|
756
|
+
/** Submit a statement. The answer is the job; `useDatasourceQuery` follows it. */
|
|
757
|
+
export const useCreateDatasourceQuery = () => {
|
|
758
|
+
const queryClient = useQueryClient();
|
|
759
|
+
const token = useIAMStore(state => state.token);
|
|
760
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
761
|
+
return useMutation({
|
|
762
|
+
mutationFn: ({ sourceUid, request, idempotencyKey }) => createDatasourceQuery(token ?? '', sourceUid, request, idempotencyKey, contentsUrl),
|
|
763
|
+
onSuccess: query => {
|
|
764
|
+
queryClient.setQueryData(queryKeys.contents.query(query.uid), query);
|
|
765
|
+
queryClient.invalidateQueries({
|
|
766
|
+
queryKey: queryKeys.contents.datasourceQueries(query.sourceUid),
|
|
767
|
+
});
|
|
768
|
+
},
|
|
769
|
+
});
|
|
770
|
+
};
|
|
771
|
+
/**
|
|
772
|
+
* One query job, polled while it can still change.
|
|
773
|
+
*
|
|
774
|
+
* A pending or running query is asked about every second; a finished one is
|
|
775
|
+
* not, so a page that shows a result does not keep asking.
|
|
776
|
+
*/
|
|
777
|
+
export const useDatasourceQuery = (queryUid) => {
|
|
778
|
+
const token = useIAMStore(state => state.token);
|
|
779
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
780
|
+
return useQuery({
|
|
781
|
+
queryKey: queryKeys.contents.query(queryUid ?? ''),
|
|
782
|
+
queryFn: () => getDatasourceQuery(token ?? '', queryUid, contentsUrl),
|
|
783
|
+
enabled: Boolean(token && contentsUrl && queryUid),
|
|
784
|
+
refetchInterval: query => query.state.data && isDatasourceQueryTerminal(query.state.data.status) ? false : 1_000,
|
|
785
|
+
refetchOnWindowFocus: true,
|
|
786
|
+
});
|
|
787
|
+
};
|
|
788
|
+
/** The queries run against a source, newest first: its history. */
|
|
789
|
+
export const useDatasourceQueries = (sourceUid, options = {}) => {
|
|
790
|
+
const token = useIAMStore(state => state.token);
|
|
791
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
792
|
+
return useQuery({
|
|
793
|
+
queryKey: queryKeys.contents.datasourceQueries(sourceUid ?? ''),
|
|
794
|
+
queryFn: () => listDatasourceQueries(token ?? '', sourceUid, {}, contentsUrl),
|
|
795
|
+
enabled: Boolean(token && contentsUrl && sourceUid) && (options.enabled ?? true),
|
|
796
|
+
staleTime: 15_000,
|
|
797
|
+
});
|
|
798
|
+
};
|
|
799
|
+
/** Ask for a query to stop; the shared job record is refreshed. */
|
|
800
|
+
export const useCancelDatasourceQuery = () => {
|
|
801
|
+
const queryClient = useQueryClient();
|
|
802
|
+
const token = useIAMStore(state => state.token);
|
|
803
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
804
|
+
return useMutation({
|
|
805
|
+
mutationFn: queryUid => cancelDatasourceQuery(token ?? '', queryUid, contentsUrl),
|
|
806
|
+
onSuccess: query => {
|
|
807
|
+
queryClient.setQueryData(queryKeys.contents.query(query.uid), query);
|
|
808
|
+
queryClient.invalidateQueries({
|
|
809
|
+
queryKey: queryKeys.contents.datasourceQueries(query.sourceUid),
|
|
810
|
+
});
|
|
811
|
+
},
|
|
812
|
+
});
|
|
813
|
+
};
|
|
814
|
+
/** The bytes of a result, or a range of them — a preview, or a resume. */
|
|
815
|
+
export const useDownloadDatasourceQueryResults = () => {
|
|
816
|
+
const token = useIAMStore(state => state.token);
|
|
817
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
818
|
+
return useMutation({
|
|
819
|
+
mutationFn: ({ queryUid, range }) => downloadDatasourceQueryResults(token ?? '', queryUid, { range }, contentsUrl),
|
|
820
|
+
});
|
|
821
|
+
};
|
|
822
|
+
/** Keep a result as a Dataset revision; the Dataset's revisions refresh. */
|
|
823
|
+
export const useSaveQueryAsDataset = () => {
|
|
824
|
+
const queryClient = useQueryClient();
|
|
825
|
+
const token = useIAMStore(state => state.token);
|
|
826
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
827
|
+
return useMutation({
|
|
828
|
+
mutationFn: ({ queryUid, datasetUid, path }) => saveDatasourceQueryAsDataset(token ?? '', queryUid, { datasetUid, path }, contentsUrl),
|
|
829
|
+
onSuccess: revision => {
|
|
830
|
+
queryClient.invalidateQueries({
|
|
831
|
+
queryKey: queryKeys.contents.datasetRevisions(revision.sourceUid),
|
|
832
|
+
});
|
|
833
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.source(revision.sourceUid) });
|
|
834
|
+
},
|
|
835
|
+
});
|
|
836
|
+
};
|
|
837
|
+
/** A Flight ticket for a result, for a client inside a sandbox. */
|
|
838
|
+
export const useCreateDatasourceQueryTicket = () => {
|
|
839
|
+
const token = useIAMStore(state => state.token);
|
|
840
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
841
|
+
return useMutation({
|
|
842
|
+
mutationFn: ({ queryUid, request }) => createDatasourceQueryTicket(token ?? '', queryUid, request ?? {}, contentsUrl),
|
|
843
|
+
});
|
|
844
|
+
};
|
|
845
|
+
// -- Dataservers ----------------------------------------------------------
|
|
846
|
+
/**
|
|
847
|
+
* The gateway as last heard, polled on a bounded interval.
|
|
848
|
+
*
|
|
849
|
+
* The previous answer stays on screen while the next is fetched — a status
|
|
850
|
+
* that blinks to nothing every ten seconds reads as flapping — and a
|
|
851
|
+
* gateway that is revoked is not polled: nothing will change on its own.
|
|
852
|
+
*/
|
|
853
|
+
export const useDataserverStatus = (sourceUid, options = {}) => {
|
|
854
|
+
const token = useIAMStore(state => state.token);
|
|
855
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
856
|
+
return useQuery({
|
|
857
|
+
queryKey: queryKeys.contents.dataserverStatus(sourceUid ?? ''),
|
|
858
|
+
queryFn: () => getDataserverStatus(token ?? '', sourceUid, contentsUrl),
|
|
859
|
+
enabled: Boolean(token && contentsUrl && sourceUid) && (options.enabled ?? true),
|
|
860
|
+
placeholderData: previous => previous,
|
|
861
|
+
refetchInterval: query => query.state.data?.state === 'revoked' ? false : (options.intervalMs ?? 10_000),
|
|
862
|
+
refetchOnWindowFocus: true,
|
|
863
|
+
});
|
|
864
|
+
};
|
|
865
|
+
/** Drain, resume or revoke a gateway; its status and its record refresh. */
|
|
866
|
+
export const useDataserverAction = () => {
|
|
867
|
+
const queryClient = useQueryClient();
|
|
868
|
+
const token = useIAMStore(state => state.token);
|
|
869
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
870
|
+
return useMutation({
|
|
871
|
+
mutationFn: ({ sourceUid, action }) => (action === 'drain'
|
|
872
|
+
? drainDataserver
|
|
873
|
+
: action === 'resume'
|
|
874
|
+
? resumeDataserver
|
|
875
|
+
: revokeDataserver)(token ?? '', sourceUid, contentsUrl),
|
|
876
|
+
onSuccess: (status, { sourceUid }) => {
|
|
877
|
+
queryClient.setQueryData(queryKeys.contents.dataserverStatus(sourceUid), status);
|
|
878
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.source(sourceUid) });
|
|
879
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.sources() });
|
|
880
|
+
},
|
|
881
|
+
});
|
|
882
|
+
};
|
|
883
|
+
/** Try the gateway on Flight and on the HTTPS fallback; the answer is a verdict. */
|
|
884
|
+
export const useTestDataserver = () => {
|
|
885
|
+
const token = useIAMStore(state => state.token);
|
|
886
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
887
|
+
return useMutation({
|
|
888
|
+
mutationFn: sourceUid => testDataserver(token ?? '', sourceUid, contentsUrl),
|
|
889
|
+
});
|
|
890
|
+
};
|
|
891
|
+
/** A new certificate from a CSR; the old one stays valid while it overlaps. */
|
|
892
|
+
export const useRotateDataserverIdentity = () => {
|
|
893
|
+
const queryClient = useQueryClient();
|
|
894
|
+
const token = useIAMStore(state => state.token);
|
|
895
|
+
const contentsUrl = useCoreStore(state => state.configuration.contentsUrl || state.configuration.runtimesUrl);
|
|
896
|
+
return useMutation({
|
|
897
|
+
mutationFn: ({ sourceUid, csr }) => rotateDataserverIdentity(token ?? '', sourceUid, { csr }, contentsUrl),
|
|
898
|
+
onSuccess: (_identity, { sourceUid }) => {
|
|
899
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.dataserverStatus(sourceUid) });
|
|
900
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.source(sourceUid) });
|
|
901
|
+
},
|
|
902
|
+
});
|
|
903
|
+
};
|
|
904
|
+
// --- The folders mounted into a Runtime that is already running -------------
|
|
905
|
+
//
|
|
906
|
+
// A Pod's volumes are fixed when it is created; the mount gateway is what
|
|
907
|
+
// lets the Home Folder arrive afterwards. `mountGateway` on the Runtime says
|
|
908
|
+
// whether this one can take it, so a view can offer the action instead of
|
|
909
|
+
// finding out by failing.
|
|
910
|
+
/**
|
|
911
|
+
* What a running Runtime is granted, and what has arrived.
|
|
912
|
+
*
|
|
913
|
+
* Polled while the platform is still applying a change and left alone once it
|
|
914
|
+
* has settled: a mount takes a second or two, and a runtime lives for hours.
|
|
915
|
+
*/
|
|
916
|
+
export const useRuntimeMounts = (runtimeName, enabled = true) => {
|
|
917
|
+
const token = useIAMStore(state => state.token);
|
|
918
|
+
const runtimesUrl = useCoreStore(state => state.configuration.runtimesUrl);
|
|
919
|
+
return useQuery({
|
|
920
|
+
queryKey: queryKeys.contents.runtimeMounts(runtimeName ?? ''),
|
|
921
|
+
queryFn: () => getRuntimeMounts(token ?? '', runtimeName, runtimesUrl),
|
|
922
|
+
enabled: Boolean(token && runtimesUrl && runtimeName && enabled),
|
|
923
|
+
refetchInterval: query => (isRuntimeMountsSettled(query.state.data) ? false : 2_000),
|
|
924
|
+
});
|
|
925
|
+
};
|
|
926
|
+
/**
|
|
927
|
+
* Mount the caller's home folders into a Runtime that is already running.
|
|
928
|
+
*
|
|
929
|
+
* Which folders is not a parameter: the platform resolves the caller's own
|
|
930
|
+
* memberships. A Runtime that cannot take a mount answers with the reason —
|
|
931
|
+
* 409 for a sandbox created without the gateway, 504 when the platform could
|
|
932
|
+
* not confirm it — and the caller shows that rather than a generic failure.
|
|
933
|
+
*/
|
|
934
|
+
export const useAttachRuntimeMounts = () => {
|
|
935
|
+
const token = useIAMStore(state => state.token);
|
|
936
|
+
const runtimesUrl = useCoreStore(state => state.configuration.runtimesUrl);
|
|
937
|
+
const queryClient = useQueryClient();
|
|
938
|
+
return useMutation({
|
|
939
|
+
mutationFn: runtimeName => attachRuntimeMounts(token ?? '', runtimeName, runtimesUrl),
|
|
940
|
+
onSuccess: (_data, runtimeName) => {
|
|
941
|
+
queryClient.invalidateQueries({
|
|
942
|
+
queryKey: queryKeys.contents.runtimeMounts(runtimeName),
|
|
943
|
+
});
|
|
944
|
+
// The Home Folder browser shows the same folders; a mount that appeared
|
|
945
|
+
// in a sandbox and not on the page is the disagreement to avoid.
|
|
946
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.attachments() });
|
|
947
|
+
},
|
|
948
|
+
});
|
|
949
|
+
};
|
|
950
|
+
/** Take one folder out of a running Runtime, by the name it appears under. */
|
|
951
|
+
export const useDetachRuntimeMount = () => {
|
|
952
|
+
const token = useIAMStore(state => state.token);
|
|
953
|
+
const runtimesUrl = useCoreStore(state => state.configuration.runtimesUrl);
|
|
954
|
+
const queryClient = useQueryClient();
|
|
955
|
+
return useMutation({
|
|
956
|
+
mutationFn: ({ runtimeName, target }) => detachRuntimeMount(token ?? '', runtimeName, target, runtimesUrl),
|
|
957
|
+
onSuccess: (_data, { runtimeName }) => {
|
|
958
|
+
queryClient.invalidateQueries({
|
|
959
|
+
queryKey: queryKeys.contents.runtimeMounts(runtimeName),
|
|
960
|
+
});
|
|
961
|
+
queryClient.invalidateQueries({ queryKey: queryKeys.contents.attachments() });
|
|
962
|
+
},
|
|
963
|
+
});
|
|
964
|
+
};
|