@datalayer/core 1.1.60 → 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 +9 -0
- package/lib/components/avatars/UserAvatar.js +0 -12
- 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 +86 -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 +1 -0
- 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 +1 -0
- package/lib/components/principal/PrincipalAvatar.js +17 -9
- 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 +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/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/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
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs
|
|
2
|
-
|
|
3
|
-
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
-
* Distributed under the terms of the Modified BSD License.
|
|
5
|
-
*/
|
|
6
|
-
import { useCallback, useEffect, useState, } from 'react';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback, useEffect, useRef, useState, } from 'react';
|
|
7
3
|
import { PathExt } from '@jupyterlab/coreutils';
|
|
8
4
|
import { PromiseDelegate } from '@lumino/coreutils';
|
|
9
|
-
import { ActionList, ActionMenu, Heading, IconButton, Spinner, TreeView, } from '@primer/react';
|
|
5
|
+
import { ActionList, ActionMenu, Heading, IconButton, SegmentedControl, Spinner, TreeView, Text, } from '@primer/react';
|
|
10
6
|
import { Box } from '@datalayer/primer-addons';
|
|
11
7
|
import { Blankslate, Dialog } from '@primer/react/experimental';
|
|
12
|
-
import { SyncIcon } from '@primer/octicons-react';
|
|
8
|
+
import { ListUnorderedIcon, SyncIcon, TableIcon } from '@primer/octicons-react';
|
|
13
9
|
import { useIsMounted } from 'usehooks-ts';
|
|
14
10
|
import { useToast } from '../../hooks/index.js';
|
|
15
11
|
import { UploadIconButton } from '../buttons/index.js';
|
|
16
12
|
import { DirectoryItem, TreeItem, modelToView, } from './ContentsItems.js';
|
|
13
|
+
import { CONTENTS_BROWSER_MOCK_MANAGER } from './ContentsBrowserMock.js';
|
|
14
|
+
import { ContentsTable } from './ContentsTable.js';
|
|
17
15
|
/**
|
|
18
16
|
* The maximum upload size (in bytes) for notebook version < 5.1.0
|
|
19
17
|
*/
|
|
@@ -22,15 +20,33 @@ export const LARGE_FILE_SIZE = 15 * 1024 * 1024;
|
|
|
22
20
|
* The size (in bytes) of the biggest chunk we should upload at once.
|
|
23
21
|
*/
|
|
24
22
|
export const CHUNK_SIZE = 1024 * 1024;
|
|
23
|
+
/**
|
|
24
|
+
* Views offered by the header toggle.
|
|
25
|
+
*/
|
|
26
|
+
const CONTENTS_BROWSER_VIEWS = [
|
|
27
|
+
{ value: 'tree', label: 'Tree view', icon: ListUnorderedIcon },
|
|
28
|
+
{ value: 'table', label: 'Table view', icon: TableIcon },
|
|
29
|
+
];
|
|
25
30
|
/**
|
|
26
31
|
* Storage browser component.
|
|
27
32
|
*/
|
|
28
33
|
export function ContentsBrowser(props) {
|
|
29
|
-
const {
|
|
34
|
+
const { mock = false, title = (_jsx(Heading, { as: "h4", sx: {
|
|
30
35
|
fontSize: 'var(--text-title-size-small)',
|
|
31
36
|
lineHeight: 'var(--text-title-lineHeight-medium)',
|
|
32
37
|
fontWeight: 'var(--text-title-weight-medium)',
|
|
33
38
|
}, children: "Contents Browser" })), } = props;
|
|
39
|
+
// A browser with nothing behind it shows nothing — never the sample tree.
|
|
40
|
+
// The sample is for a documentation preview that asks for it by name; a
|
|
41
|
+
// caller that has not resolved its sandbox yet must not appear to have.
|
|
42
|
+
const contents = props.contents ?? (mock ? CONTENTS_BROWSER_MOCK_MANAGER : undefined);
|
|
43
|
+
if (!contents) {
|
|
44
|
+
return (_jsxs(Box, { sx: { p: 3 }, children: [title, _jsx(Text, { sx: { display: 'block', color: 'fg.muted', fontSize: 1, mt: 2 }, children: "No filesystem is connected." })] }));
|
|
45
|
+
}
|
|
46
|
+
return (_jsx(ConnectedContentsBrowser, { ...props, contents: contents, mock: mock, title: title }));
|
|
47
|
+
}
|
|
48
|
+
const ConnectedContentsBrowser = (props) => {
|
|
49
|
+
const { contents, mock, title, localContents, documentRegistry, onViewChange, } = props;
|
|
34
50
|
const isMounted = useIsMounted();
|
|
35
51
|
const { trackAsyncTask } = useToast();
|
|
36
52
|
const [children, setChildren] = useState(null);
|
|
@@ -39,6 +55,21 @@ export function ContentsBrowser(props) {
|
|
|
39
55
|
const [contextMenuAnchor, setContextMenuAnchor] = useState(null);
|
|
40
56
|
const [openDeleteConfirmation, setOpenDeleteConfirmation] = useState(false);
|
|
41
57
|
const [copyToLocalConfirmation, setCopyToLocalConfirmation] = useState(false);
|
|
58
|
+
const [view, setView] = useState(props.view ?? 'tree');
|
|
59
|
+
/**
|
|
60
|
+
* Folder listed by the table view; the empty string is the root.
|
|
61
|
+
*/
|
|
62
|
+
const [folderPath, setFolderPath] = useState('');
|
|
63
|
+
const [folderItems, setFolderItems] = useState(null);
|
|
64
|
+
const [isFolderLoading, setIsFolderLoading] = useState(false);
|
|
65
|
+
/**
|
|
66
|
+
* Identifier of the latest folder request, so that a slow response for a
|
|
67
|
+
* folder the user already left is dropped.
|
|
68
|
+
*/
|
|
69
|
+
const folderRequest = useRef(0);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
setView(props.view ?? 'tree');
|
|
72
|
+
}, [props.view]);
|
|
42
73
|
const refresh = useCallback(() => {
|
|
43
74
|
contents
|
|
44
75
|
.get('')
|
|
@@ -54,6 +85,56 @@ export function ContentsBrowser(props) {
|
|
|
54
85
|
useEffect(() => {
|
|
55
86
|
refresh();
|
|
56
87
|
}, [refresh]);
|
|
88
|
+
const refreshFolder = useCallback(() => {
|
|
89
|
+
const request = ++folderRequest.current;
|
|
90
|
+
setIsFolderLoading(true);
|
|
91
|
+
contents
|
|
92
|
+
.get(folderPath)
|
|
93
|
+
.then(model => {
|
|
94
|
+
if (request !== folderRequest.current || !isMounted()) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
setIsFolderLoading(false);
|
|
98
|
+
setFolderItems(modelToView(model.content, documentRegistry));
|
|
99
|
+
})
|
|
100
|
+
.catch(reason => {
|
|
101
|
+
if (request !== folderRequest.current || !isMounted()) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
setIsFolderLoading(false);
|
|
105
|
+
console.error(`Failed to fetch folder '${folderPath}' content for manager ${contents.serverSettings.appUrl}.`, reason);
|
|
106
|
+
});
|
|
107
|
+
}, [contents, folderPath, documentRegistry]);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (view === 'table') {
|
|
110
|
+
refreshFolder();
|
|
111
|
+
}
|
|
112
|
+
}, [view, refreshFolder]);
|
|
113
|
+
/**
|
|
114
|
+
* Refresh whatever the active view displays.
|
|
115
|
+
*/
|
|
116
|
+
const refreshView = view === 'table' ? refreshFolder : refresh;
|
|
117
|
+
const changeView = useCallback((next) => {
|
|
118
|
+
if (next === view) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
// The selection belongs to the view being left.
|
|
122
|
+
setSelectedItem(null);
|
|
123
|
+
setContextMenuAnchor(null);
|
|
124
|
+
setView(next);
|
|
125
|
+
onViewChange?.(next);
|
|
126
|
+
}, [view, onViewChange]);
|
|
127
|
+
const navigateTo = useCallback((path) => {
|
|
128
|
+
setSelectedItem(null);
|
|
129
|
+
setContextMenuAnchor(null);
|
|
130
|
+
if (path === folderPath) {
|
|
131
|
+
// Already there: reload the folder instead.
|
|
132
|
+
refreshFolder();
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
setFolderPath(path);
|
|
136
|
+
}
|
|
137
|
+
}, [folderPath, refreshFolder]);
|
|
57
138
|
const upload = useCallback(
|
|
58
139
|
/**
|
|
59
140
|
* @param file File to upload
|
|
@@ -70,7 +151,9 @@ export function ContentsBrowser(props) {
|
|
|
70
151
|
? selectedItem.type === 'directory'
|
|
71
152
|
? selectedItem.path
|
|
72
153
|
: PathExt.dirname(selectedItem.path)
|
|
73
|
-
: ''
|
|
154
|
+
: view === 'table'
|
|
155
|
+
? folderPath
|
|
156
|
+
: '';
|
|
74
157
|
const path = currentDirectory
|
|
75
158
|
? PathExt.join(currentDirectory, file.name)
|
|
76
159
|
: file.name;
|
|
@@ -127,7 +210,7 @@ export function ContentsBrowser(props) {
|
|
|
127
210
|
selectedItem.refresh();
|
|
128
211
|
}
|
|
129
212
|
else {
|
|
130
|
-
|
|
213
|
+
refreshView();
|
|
131
214
|
}
|
|
132
215
|
return finalModel;
|
|
133
216
|
}
|
|
@@ -144,12 +227,12 @@ export function ContentsBrowser(props) {
|
|
|
144
227
|
selectedItem.refresh();
|
|
145
228
|
}
|
|
146
229
|
else {
|
|
147
|
-
|
|
230
|
+
refreshView();
|
|
148
231
|
}
|
|
149
232
|
});
|
|
150
233
|
return task;
|
|
151
234
|
}
|
|
152
|
-
}, [contents, selectedItem,
|
|
235
|
+
}, [contents, selectedItem, refreshView, view, folderPath]);
|
|
153
236
|
const onContextMenu = useCallback((ref) => {
|
|
154
237
|
if (contextMenuAnchor === ref) {
|
|
155
238
|
setContextMenuAnchor(null);
|
|
@@ -225,53 +308,63 @@ export function ContentsBrowser(props) {
|
|
|
225
308
|
alignItems: 'center',
|
|
226
309
|
flexWrap: 'nowrap',
|
|
227
310
|
flexShrink: 0,
|
|
228
|
-
}, children: [_jsx(
|
|
311
|
+
}, children: [_jsx(SegmentedControl, { "aria-label": "Contents view", size: "small", onChange: index => {
|
|
312
|
+
changeView(CONTENTS_BROWSER_VIEWS[index].value);
|
|
313
|
+
}, children: CONTENTS_BROWSER_VIEWS.map(candidate => (_jsx(SegmentedControl.IconButton, { icon: candidate.icon, "aria-label": candidate.label, selected: candidate.value === view }, candidate.value))) }), _jsx(IconButton, { variant: "invisible", "aria-label": 'Refresh contents browser.', title: 'Refresh contents browser.', icon: SyncIcon, onClick: refreshView, disabled: mock }), !mock && (_jsx(UploadIconButton, { label: 'Upload a file', multiple: true, upload: upload }))] })] }), isLoading ? (_jsx(Box, { sx: {
|
|
229
314
|
gridArea: 'content',
|
|
230
315
|
display: 'flex',
|
|
231
316
|
alignItems: 'center',
|
|
232
317
|
justifyContent: 'center',
|
|
233
318
|
minHeight: '40px',
|
|
234
319
|
height: '100vh',
|
|
235
|
-
}, children: _jsx(Spinner, {}) })) : (
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
320
|
+
}, children: _jsx(Spinner, {}) })) : (_jsxs(Box, { sx: { gridArea: 'content' }, children: [view === 'table' ? (folderItems === null && !isFolderLoading ? (_jsx(Blankslate, { children: _jsx(Blankslate.Heading, { children: "No contents" }) })) : (_jsx(ContentsTable, { path: folderPath, items: folderItems ?? [], current: selectedItem, loading: isFolderLoading, onNavigate: navigateTo, onSelect: item => {
|
|
321
|
+
onSelect(item, refreshFolder);
|
|
322
|
+
}, onContextMenu: onContextMenu }))) : children ? (_jsx(TreeView, { children: children?.map(child => {
|
|
323
|
+
return child.type === 'directory' ? (_jsx(DirectoryItem, { item: child, contents: contents, current: selectedItem, documentRegistry: documentRegistry, onContextMenu: onContextMenu, onSelect: onSelect }, child.name)) : (_jsx(TreeItem, { item: child, current: selectedItem?.path === child.path, onSelect: item => {
|
|
324
|
+
onSelect(item, refresh);
|
|
325
|
+
}, onContextMenu: onContextMenu }, child.name));
|
|
326
|
+
}) })) : (_jsx(Blankslate, { children: _jsx(Blankslate.Heading, { children: "No contents" }) })), !mock && contextMenuAnchor !== null && (_jsx(ActionMenu
|
|
327
|
+
// Primer 37 types `anchorRef` with React 18's non-nullable
|
|
328
|
+
// `RefObject<HTMLElement>`; the anchor this menu tracks is nullable.
|
|
329
|
+
, {
|
|
330
|
+
// Primer 37 types `anchorRef` with React 18's non-nullable
|
|
331
|
+
// `RefObject<HTMLElement>`; the anchor this menu tracks is nullable.
|
|
332
|
+
anchorRef: (contextMenuAnchor ?? undefined), open: contextMenuAnchor?.current !== null, onOpenChange: () => {
|
|
333
|
+
setContextMenuAnchor(null);
|
|
334
|
+
}, children: _jsx(ActionMenu.Overlay, { children: _jsxs(ActionList, { children: [_jsx(ActionList.Item, { title: "Delete the active item.", onSelect: onSelectDelete, children: "Delete\u2026" }), localContents && (_jsx(ActionList.Item, { title: "Copy the active item to the local drive.", onSelect: onSelectCopyToLocal, children: "Copy to local drive\u2026" }))] }) }) })), openDeleteConfirmation && (_jsx(Dialog, { title: _jsx("span", { style: { color: 'var(--fgColor-default)' }, children: "Confirm deletion" }), onClose: () => {
|
|
335
|
+
setOpenDeleteConfirmation(false);
|
|
336
|
+
}, footerButtons: [
|
|
337
|
+
{
|
|
338
|
+
buttonType: 'default',
|
|
339
|
+
content: 'Cancel',
|
|
340
|
+
onClick: () => {
|
|
341
|
+
setOpenDeleteConfirmation(false);
|
|
250
342
|
},
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
buttonType: 'danger',
|
|
346
|
+
content: 'Delete',
|
|
347
|
+
onClick: () => {
|
|
348
|
+
deleteItem();
|
|
257
349
|
},
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
350
|
+
},
|
|
351
|
+
], children: `Are you sure you want to delete ${selectedItem?.path}?` })), copyToLocalConfirmation && (_jsx(Dialog, { title: _jsx("span", { style: { color: 'var(--fgColor-default)' }, children: "Confirm copy to local" }), onClose: () => {
|
|
352
|
+
setCopyToLocalConfirmation(false);
|
|
353
|
+
}, footerButtons: [
|
|
354
|
+
{
|
|
355
|
+
buttonType: 'default',
|
|
356
|
+
content: 'Cancel',
|
|
357
|
+
onClick: () => {
|
|
358
|
+
setCopyToLocalConfirmation(false);
|
|
267
359
|
},
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
buttonType: 'danger',
|
|
363
|
+
content: 'Copy to local',
|
|
364
|
+
onClick: () => {
|
|
365
|
+
copyToLocal();
|
|
274
366
|
},
|
|
275
|
-
|
|
276
|
-
}
|
|
367
|
+
},
|
|
368
|
+
], children: `Are you sure you want to copy to local ${selectedItem?.path}?` }))] }))] }));
|
|
369
|
+
};
|
|
277
370
|
export default ContentsBrowser;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
3
|
+
* Distributed under the terms of the Modified BSD License.
|
|
4
|
+
*/
|
|
5
|
+
const timestamp = '2026-08-24T08:00:00.000Z';
|
|
6
|
+
function directory(name, path, content) {
|
|
7
|
+
return {
|
|
8
|
+
name,
|
|
9
|
+
path,
|
|
10
|
+
type: 'directory',
|
|
11
|
+
writable: true,
|
|
12
|
+
created: timestamp,
|
|
13
|
+
last_modified: timestamp,
|
|
14
|
+
mimetype: '',
|
|
15
|
+
content,
|
|
16
|
+
format: 'json',
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function file(name, path) {
|
|
20
|
+
return {
|
|
21
|
+
name,
|
|
22
|
+
path,
|
|
23
|
+
type: 'file',
|
|
24
|
+
writable: true,
|
|
25
|
+
created: timestamp,
|
|
26
|
+
last_modified: timestamp,
|
|
27
|
+
mimetype: 'application/octet-stream',
|
|
28
|
+
content: null,
|
|
29
|
+
format: null,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const entries = new Map();
|
|
33
|
+
const workspace = directory('workspace', 'workspace', [
|
|
34
|
+
file('analysis.ipynb', 'workspace/analysis.ipynb'),
|
|
35
|
+
file('prepare_data.py', 'workspace/prepare_data.py'),
|
|
36
|
+
directory('results', 'workspace/results', [
|
|
37
|
+
file('summary.parquet', 'workspace/results/summary.parquet'),
|
|
38
|
+
]),
|
|
39
|
+
]);
|
|
40
|
+
const data = directory('data', 'data', [
|
|
41
|
+
directory('earth-observation', 'data/earth-observation', [
|
|
42
|
+
file('manifest.json', 'data/earth-observation/manifest.json'),
|
|
43
|
+
file('observations.parquet', 'data/earth-observation/observations.parquet'),
|
|
44
|
+
]),
|
|
45
|
+
directory('model-artifacts', 'data/model-artifacts', [
|
|
46
|
+
file('checkpoint.bin', 'data/model-artifacts/checkpoint.bin'),
|
|
47
|
+
]),
|
|
48
|
+
]);
|
|
49
|
+
const environment = directory('environment', 'environment', [
|
|
50
|
+
directory('tutorials', 'environment/tutorials', [
|
|
51
|
+
file('README.md', 'environment/tutorials/README.md'),
|
|
52
|
+
file('example.ipynb', 'environment/tutorials/example.ipynb'),
|
|
53
|
+
]),
|
|
54
|
+
directory('reference-data', 'environment/reference-data', [
|
|
55
|
+
file('sentinel-catalog.json', 'environment/reference-data/sentinel-catalog.json'),
|
|
56
|
+
]),
|
|
57
|
+
]);
|
|
58
|
+
const root = directory('', '', [workspace, data, environment]);
|
|
59
|
+
function index(model) {
|
|
60
|
+
entries.set(model.path, model);
|
|
61
|
+
if (model.type === 'directory' && Array.isArray(model.content)) {
|
|
62
|
+
model.content.forEach(index);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
index(root);
|
|
66
|
+
/** Invented sandbox filesystem used by documentation previews. */
|
|
67
|
+
export const CONTENTS_BROWSER_MOCK_MANAGER = {
|
|
68
|
+
serverSettings: { appUrl: 'mock://code-sandbox/' },
|
|
69
|
+
get: async (path) => entries.get(path) ?? root,
|
|
70
|
+
save: async (path, model) => ({
|
|
71
|
+
...file(model.name ?? path, path),
|
|
72
|
+
...model,
|
|
73
|
+
}),
|
|
74
|
+
delete: async () => undefined,
|
|
75
|
+
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { JSX } from 'react';
|
|
1
2
|
import { MutableRefObject } from 'react';
|
|
2
3
|
import { DocumentRegistry } from '@jupyterlab/docregistry';
|
|
3
4
|
import { Contents } from '@jupyterlab/services';
|
|
@@ -54,5 +55,5 @@ export declare function modelToView(models: Contents.IModel[], docRegistry?: Doc
|
|
|
54
55
|
* Directory tree item component
|
|
55
56
|
*/
|
|
56
57
|
export declare function DirectoryItem(props: IDirectoryItemProps): JSX.Element;
|
|
57
|
-
export declare function TreeItem(props: ITreeItemProps):
|
|
58
|
+
export declare function TreeItem(props: ITreeItemProps): JSX.Element;
|
|
58
59
|
export {};
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2023-2025 Datalayer, Inc.
|
|
4
|
-
* Distributed under the terms of the Modified BSD License.
|
|
5
|
-
*/
|
|
6
2
|
import { useCallback, useRef, useState } from 'react';
|
|
7
3
|
import { TreeView } from '@primer/react';
|
|
8
4
|
import { FileIcon } from '@primer/octicons-react';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { JSX } from 'react';
|
|
2
|
+
import { type MutableRefObject } from 'react';
|
|
3
|
+
import { IContentsView } from './ContentsItems';
|
|
4
|
+
/**
|
|
5
|
+
* Contents table component properties.
|
|
6
|
+
*/
|
|
7
|
+
export interface IContentsTableProps {
|
|
8
|
+
/**
|
|
9
|
+
* Path of the folder listed by the table; the empty string is the root.
|
|
10
|
+
*/
|
|
11
|
+
path: string;
|
|
12
|
+
/**
|
|
13
|
+
* Items of the listed folder.
|
|
14
|
+
*/
|
|
15
|
+
items: IContentsView[];
|
|
16
|
+
/**
|
|
17
|
+
* Currently selected item.
|
|
18
|
+
*/
|
|
19
|
+
current: IContentsView | null;
|
|
20
|
+
/**
|
|
21
|
+
* Whether the folder content is being (re)fetched; a spinner replaces the
|
|
22
|
+
* rows while it is.
|
|
23
|
+
*/
|
|
24
|
+
loading?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Callback when a folder is opened, either from a row, the `..` row or the
|
|
27
|
+
* path bar. Navigating to the listed folder reloads it.
|
|
28
|
+
*/
|
|
29
|
+
onNavigate: (path: string) => void;
|
|
30
|
+
/**
|
|
31
|
+
* Callback on item selection.
|
|
32
|
+
*/
|
|
33
|
+
onSelect: (item: IContentsView) => void;
|
|
34
|
+
/**
|
|
35
|
+
* Callback on context menu event.
|
|
36
|
+
*/
|
|
37
|
+
onContextMenu: (ref: MutableRefObject<HTMLElement | null>) => void;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Format a byte count for display.
|
|
41
|
+
*/
|
|
42
|
+
export declare function formatSize(size?: number | null): string;
|
|
43
|
+
/**
|
|
44
|
+
* Table listing the content of one folder.
|
|
45
|
+
*
|
|
46
|
+
* Folder rows open the folder, the `..` row goes to the parent folder and
|
|
47
|
+
* the path bar jumps to any ancestor (or reloads the listed folder).
|
|
48
|
+
*/
|
|
49
|
+
export declare function ContentsTable(props: IContentsTableProps): JSX.Element;
|
|
50
|
+
export default ContentsTable;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment, useRef, } from 'react';
|
|
3
|
+
import { PathExt } from '@jupyterlab/coreutils';
|
|
4
|
+
import { Link, RelativeTime, Spinner, Text } from '@primer/react';
|
|
5
|
+
import { Table } from '@primer/react/experimental';
|
|
6
|
+
import { Box } from '@datalayer/primer-addons';
|
|
7
|
+
import { FileDirectoryFillIcon, FileDirectoryIcon, FileIcon, } from '@primer/octicons-react';
|
|
8
|
+
const SIZE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
9
|
+
/**
|
|
10
|
+
* Format a byte count for display.
|
|
11
|
+
*/
|
|
12
|
+
export function formatSize(size) {
|
|
13
|
+
if (size === undefined || size === null) {
|
|
14
|
+
return '';
|
|
15
|
+
}
|
|
16
|
+
let value = size;
|
|
17
|
+
let unit = 0;
|
|
18
|
+
while (value >= 1024 && unit < SIZE_UNITS.length - 1) {
|
|
19
|
+
value /= 1024;
|
|
20
|
+
unit += 1;
|
|
21
|
+
}
|
|
22
|
+
return `${unit === 0 ? value : value.toFixed(1)} ${SIZE_UNITS[unit]}`;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Split a folder path into its ancestors, root first.
|
|
26
|
+
*/
|
|
27
|
+
function pathSegments(path) {
|
|
28
|
+
const segments = [];
|
|
29
|
+
if (path) {
|
|
30
|
+
path.split('/').forEach(name => {
|
|
31
|
+
const parent = segments[segments.length - 1]?.path ?? '';
|
|
32
|
+
segments.push({
|
|
33
|
+
name,
|
|
34
|
+
path: parent ? PathExt.join(parent, name) : name,
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return segments;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* One clickable part of the path bar.
|
|
42
|
+
*/
|
|
43
|
+
function PathSegment(props) {
|
|
44
|
+
const { name, path, current, title, onNavigate } = props;
|
|
45
|
+
return (_jsx(Link, { as: "button", type: "button", title: title, "aria-current": current ? 'location' : undefined, onClick: () => onNavigate(path), sx: current ? { color: 'fg.default', fontWeight: 'semibold' } : undefined, children: name }));
|
|
46
|
+
}
|
|
47
|
+
const ROW_STYLE = { cursor: 'pointer' };
|
|
48
|
+
const SELECTED_ROW_STYLE = {
|
|
49
|
+
...ROW_STYLE,
|
|
50
|
+
backgroundColor: 'var(--bgColor-accent-muted)',
|
|
51
|
+
};
|
|
52
|
+
function isActivationKey(event) {
|
|
53
|
+
return event.key === 'Enter' || event.key === ' ';
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The `..` row navigating to the parent folder.
|
|
57
|
+
*/
|
|
58
|
+
function ParentRow(props) {
|
|
59
|
+
const { path, onNavigate } = props;
|
|
60
|
+
const goUp = () => onNavigate(path);
|
|
61
|
+
return (_jsxs(Table.Row, { tabIndex: 0, style: ROW_STYLE, title: "Go to the parent folder.", onClick: goUp, onKeyDown: event => {
|
|
62
|
+
if (isActivationKey(event)) {
|
|
63
|
+
event.preventDefault();
|
|
64
|
+
goUp();
|
|
65
|
+
}
|
|
66
|
+
}, children: [_jsx(Table.Cell, { scope: "row", children: _jsxs(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 }, children: [_jsx(FileDirectoryIcon, {}), _jsx("span", { children: ".." })] }) }), _jsx(Table.Cell, {}), _jsx(Table.Cell, {})] }));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A folder or file row.
|
|
70
|
+
*/
|
|
71
|
+
function ContentsRow(props) {
|
|
72
|
+
const { item, current, onNavigate, onSelect, onContextMenu } = props;
|
|
73
|
+
const ref = useRef(null);
|
|
74
|
+
const isDirectory = item.type === 'directory';
|
|
75
|
+
const icon = item.fileType?.icon;
|
|
76
|
+
const activate = () => {
|
|
77
|
+
if (isDirectory) {
|
|
78
|
+
onNavigate(item.path);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
onSelect(item);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return (_jsxs(Table.Row, { tabIndex: 0, "aria-selected": current, style: current ? SELECTED_ROW_STYLE : ROW_STYLE, title: isDirectory ? `Open ${item.path}` : item.path, onClick: activate, onKeyDown: event => {
|
|
85
|
+
if (isActivationKey(event)) {
|
|
86
|
+
event.preventDefault();
|
|
87
|
+
activate();
|
|
88
|
+
}
|
|
89
|
+
}, onContextMenu: (event) => {
|
|
90
|
+
event.preventDefault();
|
|
91
|
+
if (!current) {
|
|
92
|
+
onSelect(item);
|
|
93
|
+
}
|
|
94
|
+
onContextMenu(ref);
|
|
95
|
+
}, children: [_jsx(Table.Cell, { scope: "row", children: _jsxs(Box, { ref: ref, sx: { display: 'flex', alignItems: 'center', gap: 2, minWidth: 0 }, children: [isDirectory ? (_jsx(FileDirectoryFillIcon, {})) : icon ? (_jsx(icon.react, { tag: 'span' })) : (_jsx(FileIcon, {})), _jsx("span", { style: {
|
|
96
|
+
overflow: 'hidden',
|
|
97
|
+
textOverflow: 'ellipsis',
|
|
98
|
+
whiteSpace: 'nowrap',
|
|
99
|
+
}, children: item.name })] }) }), _jsx(Table.Cell, { children: item.last_modified ? (_jsx(RelativeTime, { date: new Date(item.last_modified) })) : null }), _jsx(Table.Cell, { align: "end", children: isDirectory ? '' : formatSize(item.size) })] }));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Table listing the content of one folder.
|
|
103
|
+
*
|
|
104
|
+
* Folder rows open the folder, the `..` row goes to the parent folder and
|
|
105
|
+
* the path bar jumps to any ancestor (or reloads the listed folder).
|
|
106
|
+
*/
|
|
107
|
+
export function ContentsTable(props) {
|
|
108
|
+
const { path, items, current, loading = false, onNavigate, onSelect, onContextMenu, } = props;
|
|
109
|
+
const segments = pathSegments(path);
|
|
110
|
+
const label = path ? `Contents of ${path}` : 'Contents of the root folder';
|
|
111
|
+
return (_jsxs(Box, { sx: { display: 'flex', flexDirection: 'column', gap: 2 }, children: [_jsx(Box, { sx: {
|
|
112
|
+
display: 'flex',
|
|
113
|
+
alignItems: 'center',
|
|
114
|
+
gap: 2,
|
|
115
|
+
minWidth: 0,
|
|
116
|
+
overflow: 'hidden',
|
|
117
|
+
}, children: _jsxs(Box, { role: "navigation", "aria-label": "Folder path", sx: {
|
|
118
|
+
display: 'flex',
|
|
119
|
+
alignItems: 'center',
|
|
120
|
+
flexWrap: 'wrap',
|
|
121
|
+
gap: 1,
|
|
122
|
+
minWidth: 0,
|
|
123
|
+
fontSize: 1,
|
|
124
|
+
}, children: [_jsx(PathSegment, { name: "/", path: "", current: segments.length === 0, title: "Go to the root folder.", onNavigate: onNavigate }), segments.map((segment, index) => (_jsxs(Fragment, { children: [index > 0 && _jsx(Text, { sx: { color: 'fg.muted' }, children: "/" }), _jsx(PathSegment, { name: segment.name, path: segment.path, current: index === segments.length - 1, title: index === segments.length - 1
|
|
125
|
+
? `Reload ${segment.path}`
|
|
126
|
+
: `Go to ${segment.path}`, onNavigate: onNavigate })] }, segment.path)))] }) }), loading ? (_jsx(Box, { sx: {
|
|
127
|
+
display: 'flex',
|
|
128
|
+
alignItems: 'center',
|
|
129
|
+
justifyContent: 'center',
|
|
130
|
+
minHeight: '40px',
|
|
131
|
+
padding: 3,
|
|
132
|
+
}, children: _jsx(Spinner, { "aria-label": "Loading folder\u2026" }) })) : (_jsx(Table.Container, { children: _jsxs(Table, { "aria-label": label, cellPadding: "condensed", gridTemplateColumns: "minmax(0, 1fr) max-content max-content", children: [_jsx(Table.Head, { children: _jsxs(Table.Row, { children: [_jsx(Table.Header, { children: "Name" }), _jsx(Table.Header, { children: "Last modified" }), _jsx(Table.Header, { align: "end", children: "Size" })] }) }), _jsxs(Table.Body, { children: [path && (_jsx(ParentRow, { path: PathExt.dirname(path), onNavigate: onNavigate })), items.map(item => (_jsx(ContentsRow, { item: item, current: item.path === current?.path, onNavigate: onNavigate, onSelect: onSelect, onContextMenu: onContextMenu }, item.path)))] })] }) }))] }));
|
|
133
|
+
}
|
|
134
|
+
export default ContentsTable;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The caller's Home Folders as a JupyterLab drive.
|
|
3
|
+
*
|
|
4
|
+
* One implementation of `Contents.IDrive`, so JupyterLab's file browser, the
|
|
5
|
+
* shared `ContentsBrowser` and VS Code's file system provider all read the
|
|
6
|
+
* same listing and write through the same transfer — `uploadHomeFolderFile`,
|
|
7
|
+
* verified, resumable — rather than each carrying an upload of its own.
|
|
8
|
+
*
|
|
9
|
+
* The tree is two levels of one address space: the root names the folders the
|
|
10
|
+
* caller reaches — their own, and one per organization and team — and
|
|
11
|
+
* everything below is a path inside one of them.
|
|
12
|
+
*
|
|
13
|
+
* @module components/storage/HomeFolderDrive
|
|
14
|
+
*/
|
|
15
|
+
import type { Contents, ServerConnection } from '@jupyterlab/services';
|
|
16
|
+
import { ISignal } from '@lumino/signaling';
|
|
17
|
+
export type HomeFolderDriveOptions = {
|
|
18
|
+
/** Where the Contents service is reached. */
|
|
19
|
+
contentsUrl: string;
|
|
20
|
+
/** The caller's token; the reachable folders are resolved from it. */
|
|
21
|
+
token: string;
|
|
22
|
+
/** The drive's name in JupyterLab, the prefix before `:` in a path. */
|
|
23
|
+
name?: string;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The Home Folders, as one JupyterLab drive.
|
|
27
|
+
*
|
|
28
|
+
* Reads come from the shared filesystem — what a sandbox wrote as well as what
|
|
29
|
+
* was uploaded. Writes go through the transfer contract: a file the browser
|
|
30
|
+
* hands over in chunks is gathered and sent whole, created, its parts
|
|
31
|
+
* checksummed, then completed; an interrupted upload resumes from the parts
|
|
32
|
+
* the service verified. Checkpoints are the immutable versions the catalog
|
|
33
|
+
* keeps of every object, so there is nothing to create here.
|
|
34
|
+
*/
|
|
35
|
+
export declare class HomeFolderDrive implements Contents.IDrive {
|
|
36
|
+
readonly name: string;
|
|
37
|
+
readonly serverSettings: ServerConnection.ISettings;
|
|
38
|
+
private readonly _token;
|
|
39
|
+
private readonly _base;
|
|
40
|
+
private readonly _fileChanged;
|
|
41
|
+
private readonly _pending;
|
|
42
|
+
private _isDisposed;
|
|
43
|
+
constructor(options: HomeFolderDriveOptions);
|
|
44
|
+
get fileChanged(): ISignal<Contents.IDrive, Contents.IChangedArgs>;
|
|
45
|
+
get isDisposed(): boolean;
|
|
46
|
+
dispose(): void;
|
|
47
|
+
get(localPath: string, options?: Contents.IFetchOptions): Promise<Contents.IModel>;
|
|
48
|
+
getDownloadUrl(localPath: string): Promise<string>;
|
|
49
|
+
newUntitled(options?: Contents.ICreateOptions): Promise<Contents.IModel>;
|
|
50
|
+
delete(localPath: string): Promise<void>;
|
|
51
|
+
rename(oldLocalPath: string, newLocalPath: string): Promise<Contents.IModel>;
|
|
52
|
+
/**
|
|
53
|
+
* Upload, through the same transfer the CLI and the objects view use.
|
|
54
|
+
*
|
|
55
|
+
* A file is chunked by the browser — Jupyter's protocol numbers the chunks
|
|
56
|
+
* and marks the last one `-1` — and whole by the transfer contract, so the
|
|
57
|
+
* chunks are gathered and sent when the last one arrives. One idempotency
|
|
58
|
+
* key per file and size, so the retry of an interrupted upload resumes the
|
|
59
|
+
* transfer it started rather than opening a second.
|
|
60
|
+
*/
|
|
61
|
+
save(localPath: string, model?: Partial<Contents.IModel>): Promise<Contents.IModel>;
|
|
62
|
+
copy(localPath: string, toLocalDir: string): Promise<Contents.IModel>;
|
|
63
|
+
/** Every version the catalog keeps is a checkpoint already; nothing to create. */
|
|
64
|
+
createCheckpoint(localPath: string): Promise<Contents.ICheckpointModel>;
|
|
65
|
+
listCheckpoints(): Promise<Contents.ICheckpointModel[]>;
|
|
66
|
+
restoreCheckpoint(): Promise<void>;
|
|
67
|
+
deleteCheckpoint(): Promise<void>;
|
|
68
|
+
private _directory;
|
|
69
|
+
private _bytes;
|
|
70
|
+
}
|
|
71
|
+
export default HomeFolderDrive;
|