Skip to content

Conversation

@Artmann
Copy link
Contributor

@Artmann Artmann commented Dec 3, 2025

Export projects and/or notebooks as Jupyter notebooks.

Fixes #230

CleanShot 2025-12-03 at 08 44 28

Summary by CodeRabbit

  • New Features
    • Export entire Deepnote projects and individual notebooks to Jupyter format via new Export Project and Export Notebook commands, accessible from the command palette and context menus; exported notebooks preserve metadata and cell structure.
  • Localization
    • Added UI labels for the new export commands.
  • Tests
    • Added unit tests covering export flows, prompts, overwrite handling, and error messaging.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 3, 2025

📝 Walkthrough

Walkthrough

This pull request adds export functionality to the Deepnote VSCode extension. Two new commands (deepnote.exportProject and deepnote.exportNotebook) are introduced with corresponding UI registrations, localization strings, and command constants. The implementation in deepnoteExplorerView.ts enables users to export Deepnote projects or individual notebooks to Jupyter notebook format using the newly imported convertDeepnoteToJupyterNotebooks function. A test mock for the conversion is added in the VSCode test loader, comprehensive unit tests cover both export workflows and error scenarios, and the @deepnote/convert dependency is bumped to ^1.3.0. Command groups in the extension manifest were adjusted.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant User
participant VSCode as "VSCode UI"
participant Extension as "DeepnoteExplorerView"
participant Convert as "@deepnote/convert"
participant FS as "File System (workspace)"
Note over User,VSCode: Export command invoked (project or notebook)
User->>VSCode: Trigger command (exportProject / exportNotebook)
VSCode->>Extension: call command handler
Extension->>VSCode: prompt for format (quickPick)
alt user cancels
VSCode->>User: cancel flow
else user selects format
Extension->>VSCode: show folder picker
alt user cancels
VSCode->>User: cancel flow
else user selects folder
Extension->>Extension: load deepnote project data (read .deepnote / convert inputs)
Extension->>Convert: convertDeepnoteToJupyterNotebooks(projectData)
Convert-->>Extension: list of Jupyter notebook objects
loop for each notebook to write
Extension->>FS: check file exists
alt exists
Extension->>VSCode: prompt overwrite?
alt user cancels
VSCode->>Extension: stop writing remaining files
else user confirms
Extension->>FS: write file (JSON)
end
else not exists
Extension->>FS: write file (JSON)
end
end
Extension->>VSCode: show success / error messages
end
end

Pre-merge checks

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding export functionality for projects and notebooks as Jupyter notebooks.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov
Copy link

codecov bot commented Dec 3, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 0%. Comparing base (7b7576e) to head (9c166b0).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@     Coverage Diff     @@
##   main   #234   +/-   ##
===========================
===========================
🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
build/mocha-esm-loader.js (1)

72-79: Mock for @deepnote/convert is reasonable but must track real API

The loader intercept and deepnote-convert mock look coherent and match how tests use convertDeepnoteToJupyterNotebooks (filename + nbformat 4 JSON with Deepnote metadata). Two minor points:

  • This reimplements the converter’s behavior; if @deepnote/convert changes its output shape, tests may still pass while runtime code breaks. Consider adding a brief comment noting that this mock must stay aligned with the library’s contract, or deriving its types from the real package to reduce drift.
  • The mock attaches outputs even to markdown cells. That’s harmless for current tests, but if you later add stricter nbformat validation, you may want to mirror the real converter’s behavior more closely.

Also applies to: 310-344

package.json (1)

1583-1615: Explorer context menu grouping for project/notebook actions looks consistent

Re‑grouping:

  • addNotebookToProject under 1_add@1,
  • renameProject under 2_manage@1 with exportProject at 2_manage@2,
  • notebook rename/duplicate under 1_edit@1/2 with exportNotebook under 2_export@1,

creates a clear “add / manage / export / delete” ordering in the Deepnote explorer. This wiring matches the new export commands and should produce a sensible context menu.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 7b7576e and 76b2381.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (6)
  • build/mocha-esm-loader.js (2 hunks)
  • package.json (4 hunks)
  • package.nls.json (1 hunks)
  • src/notebooks/deepnote/deepnoteExplorerView.ts (3 hunks)
  • src/notebooks/deepnote/deepnoteExplorerView.unit.test.ts (1 hunks)
  • src/platform/common/constants.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

**/*.{ts,tsx}: Use l10n.t() for all user-facing strings in TypeScript files
Use typed error classes from src/platform/errors/ instead of generic errors
Use ILogger service instead of console.log for logging
Preserve error details in error messages while scrubbing personally identifiable information (PII)
Prefer async/await over promise chains
Handle cancellation with CancellationToken

Order method, fields and properties first by accessibility (public/private/protected) and then by alphabetical order

Files:

  • src/platform/common/constants.ts
  • src/notebooks/deepnote/deepnoteExplorerView.unit.test.ts
  • src/notebooks/deepnote/deepnoteExplorerView.ts
src/platform/**/*.ts

📄 CodeRabbit inference engine (.github/instructions/platform.instructions.md)

src/platform/**/*.ts: Use Inversify-based dependency injection with IServiceManager and IServiceContainer for managing service relationships and dependencies
Define service interfaces using Symbol-based exports (e.g., export const IFileSystem = Symbol('IFileSystem')) paired with corresponding TypeScript interfaces
Register types using the pattern serviceManager.addSingleton<IService>(IService, ServiceImplementation) in registerTypes functions
Use @Injectable() and @Inject() decorators from Inversify for class dependency injection configuration
Implement unified interfaces for cross-platform services (IFileSystem, IPlatformService, etc.) with graceful degradation for web environment limitations
Use structured logging with context via logger.info, logger.error, etc. rather than console.log
Provide platform capability checks and feature detection before using advanced platform-specific features
Register separate service implementations for desktop and web environments, allowing the DI container to resolve the correct platform implementation

Files:

  • src/platform/common/constants.ts
**/*.ts

📄 CodeRabbit inference engine (.github/instructions/typescript.instructions.md)

**/*.ts: ALWAYS check the 'Core - Build' task output for TypeScript compilation errors before running any script or declaring work complete
ALWAYS run npm run format-fix before committing changes to ensure proper code formatting
FIX all TypeScript compilation errors before moving forward with development
Use npm run format-fix to auto-fix TypeScript formatting issues before committing
Use npm run lint to check for linter issues in TypeScript files and attempt to fix before committing

Files:

  • src/platform/common/constants.ts
  • src/notebooks/deepnote/deepnoteExplorerView.unit.test.ts
  • src/notebooks/deepnote/deepnoteExplorerView.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

src/**/*.{ts,tsx}: Don't add the Microsoft copyright header to new files
Use Uri.joinPath() for constructing file paths instead of string concatenation with / to ensure platform-correct path separators
Follow established patterns when importing new packages, using helper imports rather than direct imports (e.g., use import { generateUuid } from '../platform/common/uuid' instead of importing uuid directly)
Add blank lines after const groups and before return statements for readability
Separate third-party and local file imports

Files:

  • src/platform/common/constants.ts
  • src/notebooks/deepnote/deepnoteExplorerView.unit.test.ts
  • src/notebooks/deepnote/deepnoteExplorerView.ts
**/*.unit.test.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Create unit tests in *.unit.test.ts files

**/*.unit.test.ts: Unit tests use Mocha/Chai framework with .unit.test.ts extension
Test files should be placed alongside the source files they test
Use assert.deepStrictEqual() for object comparisons instead of checking individual properties

Files:

  • src/notebooks/deepnote/deepnoteExplorerView.unit.test.ts
**/*.test.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Create integration tests in *.test.ts files (not *.unit.test.ts)

**/*.test.ts: ALWAYS check the 'Unittest - Build' task output for TypeScript compilation errors before running any script or declaring work complete
When a mock is returned from a promise in unit tests, ensure the mocked instance has an undefined then property to avoid hanging tests
Use npm run test:unittests for TypeScript unit tests before committing changes

Files:

  • src/notebooks/deepnote/deepnoteExplorerView.unit.test.ts
src/notebooks/deepnote/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Deepnote integration located in src/notebooks/deepnote/ with refactored architecture: deepnoteTypes.ts (type definitions), deepnoteNotebookManager.ts (state management), deepnoteNotebookSelector.ts (UI selection logic), deepnoteDataConverter.ts (data transformations), deepnoteSerializer.ts (main serializer/orchestration), deepnoteActivationService.ts (VSCode activation)

Files:

  • src/notebooks/deepnote/deepnoteExplorerView.unit.test.ts
  • src/notebooks/deepnote/deepnoteExplorerView.ts
🧬 Code graph analysis (1)
src/notebooks/deepnote/deepnoteExplorerView.ts (2)
src/notebooks/deepnote/deepnoteTreeItem.ts (1)
  • DeepnoteTreeItem (25-126)
src/notebooks/deepnote/deepnoteProjectUtils.ts (1)
  • readDeepnoteProjectFile (5-10)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build & Test
🔇 Additional comments (7)
src/platform/common/constants.ts (1)

250-251: New Deepnote export command IDs are consistent

ExportProject and ExportNotebook match the new manifest command IDs and follow existing naming patterns; no issues spotted.

package.nls.json (1)

276-277: Localization entries line up with new commands

The added titles for project/notebook export use the expected key naming and match the new commands; looks good.

src/notebooks/deepnote/deepnoteExplorerView.unit.test.ts (1)

2074-2317: Export‑notebook tests cover the key branches cleanly

The exportNotebook suite mirrors the project export tests well: early returns on user cancel, invalid Deepnote file handling, single‑notebook filtering by notebookId, not‑found behavior, and write failures are all exercised. The mocking pattern (VS Code APIs + workspace.fs) is consistent with the rest of the file; no issues from a test‑logic standpoint.

package.json (1)

282-293: Export commands are correctly declared in the manifest

deepnote.exportProject and deepnote.exportNotebook are added with localized titles, category, and icons, and match the identifiers in constants.ts and package.nls.json. Nothing problematic here.

src/notebooks/deepnote/deepnoteExplorerView.ts (3)

5-5: Import addition looks good.

Follows existing import pattern from @deepnote/convert.


401-412: Command registrations follow the established pattern.


1032-1035: Error handling follows project conventions.

Uses l10n.t() and extracts error message safely.

Also applies to: 1092-1095

coderabbitai[bot]
coderabbitai bot previously approved these changes Dec 3, 2025
@Artmann Artmann marked this pull request as ready for review December 3, 2025 08:55
@Artmann Artmann requested a review from a team as a code owner December 3, 2025 08:55
Copy link
Contributor

@saltenasl saltenasl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 🚀 🚀

@saltenasl saltenasl merged commit b248326 into main Dec 3, 2025
13 checks passed
@saltenasl saltenasl deleted the export-as-jupyter branch December 3, 2025 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Export project as Jupyter notebooks

3 participants