Skip to content

Conversation

@andyjakubowski
Copy link
Contributor

@andyjakubowski andyjakubowski commented Oct 9, 2025

Signed-off-by: Andy Jakubowski [email protected]

Summary by CodeRabbit

  • Bug Fixes

    • Prevents crashes and incorrect updates when notebook metadata is invalid.
    • Ensures notebook list renders reliably; shows empty state when none are available.
    • Applies notebook changes only when a valid selection exists.
  • Improvements

    • More robust validation of notebook data for safer loading and rendering.
    • Smoother defaults for new/blank notebooks to avoid null metadata issues.
    • Enhanced compatibility with multiple notebooks, preserving names, cells, and version info during load.

@linear
Copy link

linear bot commented Oct 9, 2025

GRN-4910 Re-add notebook switching

Need to redo this after switching from Python to TypeScript conversion of .deepnote <> .ipynb

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 9, 2025

📝 Walkthrough

Walkthrough

  • Introduces zod-based runtime validation for Deepnote metadata via deepnoteMetadataSchema.safeParse in NotebookPicker change and render paths.
  • NotebookPicker handleChange now aborts on invalid metadata; on valid metadata, uses validated notebooks map to update the model with cells, nbformat, nbformat_minor, and metadata.deepnote.notebooks.
  • NotebookPicker render validates metadata and derives notebook names from the validated notebooks map; otherwise renders empty options.
  • Deepnote content provider renames the schema to deepnoteFileFromServerSchema; validation and error handling remain the same; still transforms validated content.
  • Transformer now constructs a notebooks map, returns content with cells, metadata.deepnote.notebooks, and nbformat fields.
  • Types updated: adds deepnoteMetadataSchema, shifts metadata to a typed notebooks map, and introduces IDeepnoteNotebookContent.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant NP as NotebookPicker
  participant Z as deepnoteMetadataSchema
  participant M as Notebook Model

  U->>NP: Select notebook (handleChange)
  NP->>Z: safeParse(metadata.deepnote)
  alt Metadata invalid
    Z-->>NP: failure
    NP->>NP: log error, abort
  else Metadata valid
    Z-->>NP: success (notebooks map)
    NP->>NP: lookup selected in notebooks
    alt Selected exists
      NP->>M: fromJSON({ cells, nbformat, nbformat_minor, metadata.deepnote.notebooks })
    else No selection
      NP->>NP: no-op
    end
  end
Loading
sequenceDiagram
  autonumber
  participant NP as NotebookPicker (render)
  participant Z as deepnoteMetadataSchema

  NP->>Z: safeParse(metadata.deepnote)
  alt Valid
    Z-->>NP: notebooks map
    NP->>NP: derive names for UI list
  else Invalid
    Z-->>NP: failure
    NP->>NP: render empty list
  end
Loading
sequenceDiagram
  autonumber
  participant S as Server (Deepnote YAML)
  participant CP as deepnote-content-provider
  participant SZ as deepnoteFileFromServerSchema
  participant T as transform-deepnote-yaml-to-notebook-content
  participant M as Notebook Model

  S-->>CP: content (YAML-derived JSON)
  CP->>SZ: safeParse(content)
  alt Invalid content
    SZ-->>CP: failure
    CP->>M: set model.content.cells = []
    CP-->>M: return model
  else Valid content
    SZ-->>CP: validatedModelContent
    CP->>T: transform(validatedModelContent)
    T-->>CP: { cells, metadata.deepnote.notebooks, nbformat, nbformat_minor }
    CP->>M: update model.content
  end
Loading
sequenceDiagram
  autonumber
  participant T as Transformer
  participant F as deepnoteFile
  participant C as Converter

  T->>F: read project.notebooks[]
  loop Build notebooks map
    T->>C: convertDeepnoteBlockToJupyterCell(block)
    C-->>T: cell
    T->>T: accumulate { id, name, cells[] } by notebook.id
  end
  alt Selected notebook found
    T-->>T: prepare cells from selected
    T-->>Caller: { cells, metadata.deepnote.notebooks, nbformat, nbformat_minor }
  else None found
    T-->>Caller: { cells:[code cell "No notebooks found"], metadata.deepnote.notebooks, nbformat, nbformat_minor }
  end
Loading

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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title “fix: re-add notebook switching” succinctly captures the primary change of restoring notebook switching functionality through metadata validation and model updates, making it clear and directly related to the core update in the changeset. It is concise, specific, and free of extraneous details.

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

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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 45fb503 and f47ba96.

📒 Files selected for processing (5)
  • src/components/NotebookPicker.tsx (3 hunks)
  • src/deepnote-content-provider.ts (3 hunks)
  • src/fallback-data.ts (1 hunks)
  • src/transform-deepnote-yaml-to-notebook-content.ts (3 hunks)
  • src/types.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (5)
📚 Learning: 2025-10-09T11:21:57.482Z
Learnt from: CR
PR: deepnote/vscode-deepnote#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-09T11:21:57.482Z
Learning: Applies to src/notebooks/deepnote/deepnoteDataConverter.ts : deepnoteDataConverter.ts performs Deepnote data transformations

Applied to files:

  • src/transform-deepnote-yaml-to-notebook-content.ts
  • src/deepnote-content-provider.ts
  • src/types.ts
  • src/fallback-data.ts
📚 Learning: 2025-10-09T11:21:57.482Z
Learnt from: CR
PR: deepnote/vscode-deepnote#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-09T11:21:57.482Z
Learning: Applies to src/notebooks/deepnote/deepnoteNotebookManager.ts : deepnoteNotebookManager.ts handles Deepnote notebook state management

Applied to files:

  • src/transform-deepnote-yaml-to-notebook-content.ts
  • src/components/NotebookPicker.tsx
📚 Learning: 2025-10-09T11:21:57.482Z
Learnt from: CR
PR: deepnote/vscode-deepnote#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-09T11:21:57.482Z
Learning: Applies to src/notebooks/deepnote/deepnoteTypes.ts : deepnoteTypes.ts contains Deepnote-related type definitions

Applied to files:

  • src/transform-deepnote-yaml-to-notebook-content.ts
  • src/deepnote-content-provider.ts
  • src/types.ts
  • src/fallback-data.ts
📚 Learning: 2025-10-09T11:21:57.482Z
Learnt from: CR
PR: deepnote/vscode-deepnote#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-09T11:21:57.482Z
Learning: Applies to src/notebooks/deepnote/deepnoteSerializer.ts : deepnoteSerializer.ts is the main serializer orchestrating Deepnote integration

Applied to files:

  • src/deepnote-content-provider.ts
  • src/types.ts
📚 Learning: 2025-10-09T11:21:57.482Z
Learnt from: CR
PR: deepnote/vscode-deepnote#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-09T11:21:57.482Z
Learning: Applies to src/notebooks/deepnote/deepnoteNotebookSelector.ts : deepnoteNotebookSelector.ts implements UI selection logic for Deepnote notebooks

Applied to files:

  • src/components/NotebookPicker.tsx
🧬 Code graph analysis (2)
src/transform-deepnote-yaml-to-notebook-content.ts (2)
src/convert-deepnote-block-to-jupyter-cell.ts (1)
  • convertDeepnoteBlockToJupyterCell (10-44)
src/types.ts (1)
  • IDeepnoteNotebookMetadata (21-32)
src/components/NotebookPicker.tsx (1)
src/types.ts (1)
  • deepnoteMetadataSchema (10-19)
⏰ 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). (2)
  • GitHub Check: build
  • GitHub Check: check_release
🔇 Additional comments (11)
src/fallback-data.ts (1)

24-24: LGTM!

The shift to a notebooks map cleanly replaces the previous null placeholders.

src/deepnote-content-provider.ts (3)

7-16: LGTM!

The renamed schema better describes its purpose (validating server response structure).


32-34: LGTM!

Validation call correctly uses the renamed schema.


46-50: LGTM!

Comment clarifies the transformation step.

src/transform-deepnote-yaml-to-notebook-content.ts (2)

43-50: LGTM!

The return structure correctly includes cells, metadata with notebooks map, and nbformat fields, matching the IDeepnoteNotebookContent interface.


12-22: Verify notebook.name uniqueness or switch to id key
Unable to locate the DeepnoteFile definition locally; ensure notebook.name is guaranteed unique in deepnoteFile.project.notebooks. If not, use notebook.id as the map key to avoid collisions.

src/components/NotebookPicker.tsx (3)

35-44: LGTM!

Validation with early return prevents accessing invalid metadata.


69-74: Verify that Object.values preserves notebook order.

If notebook order matters for the dropdown, note that Object.values() iteration order depends on key insertion order. With string keys, this should be stable in modern JS, but consider whether the dropdown should display notebooks in a specific order (e.g., by ID or creation time).


46-60: Verify notebook key uniqueness and fromJSON metadata support

  • Ensure deepnoteMetadataValidated.data.notebooks is keyed by a unique ID (not just notebook.name) to avoid selecting the wrong notebook.
  • Manually confirm that NotebookPanel.model.fromJSON accepts the metadata shape { deepnote: { notebooks } } and adjust if it doesn’t.
src/types.ts (2)

21-32: LGTM!

The interface correctly defines the notebooks map structure with typed cells.


34-37: LGTM!

The IDeepnoteNotebookContent interface properly extends INotebookContent with the custom metadata type.

Comment on lines +10 to +19
export const deepnoteMetadataSchema = z.object({
notebooks: z.record(
z.string(),
z.object({
id: z.string(),
name: z.string(),
cells: z.array(z.any())
})
)
});
Copy link
Contributor

@coderabbitai coderabbitai bot Oct 9, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Tighten schema cell typing to match the interface.

The schema uses z.array(z.any()) for cells (line 16), while the interface specifies Array<ICodeCell | IMarkdownCell> (line 28). This inconsistency allows invalid cells to pass validation.

Apply this diff to align the schema with the interface:

+const cellSchema = z.object({
+  cell_type: z.enum(['code', 'markdown']),
+  source: z.union([z.string(), z.array(z.string())]),
+  metadata: z.record(z.any())
+});
+
 export const deepnoteMetadataSchema = z.object({
   notebooks: z.record(
     z.string(),
     z.object({
       id: z.string(),
       name: z.string(),
-      cells: z.array(z.any())
+      cells: z.array(cellSchema)
     })
   )
 });
🤖 Prompt for AI Agents
In src/types.ts around lines 10 to 19, the deepnoteMetadataSchema currently uses
z.array(z.any()) for cells which is too permissive; change it to validate
against the two cell shapes declared by the interface (ICodeCell and
IMarkdownCell). Replace z.array(z.any()) with a z.array(z.union([<ICodeCell
schema>, <IMarkdownCell schema>])) — or better, if the cell objects have a
distinguishing "type" field, use z.discriminatedUnion('type', [{ type:
z.literal('code'), ...code cell fields schema }, { type: z.literal('markdown'),
...markdown cell fields schema }]) — ensuring each schema includes the exact
fields and types from the ICodeCell and IMarkdownCell interfaces so invalid
cells are rejected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No, I don’t want to recreate schemas for ICodeCell and IMarkdownCell types. This is fine

Copy link
Contributor

Choose a reason for hiding this comment

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

@andyjakubowski, understood. I'll leave the schema as is.


🧠 Learnings used
Learnt from: CR
PR: deepnote/vscode-deepnote#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-09T11:21:57.482Z
Learning: Applies to src/notebooks/deepnote/deepnoteTypes.ts : deepnoteTypes.ts contains Deepnote-related type definitions

Learnt from: CR
PR: deepnote/vscode-deepnote#0
File: CLAUDE.md:0-0
Timestamp: 2025-10-09T11:21:57.482Z
Learning: Applies to src/notebooks/deepnote/deepnoteDataConverter.ts : deepnoteDataConverter.ts performs Deepnote data transformations

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.

2 participants