Skip to content

Commit b185341

Browse files
authored
Merge branch 'main' into tomaskislan/package-lock-drift-check-ci
2 parents 5d75213 + b8c52a6 commit b185341

18 files changed

+870
-36
lines changed

package.json

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,12 @@
9999
"category": "Deepnote",
100100
"icon": "$(plug)"
101101
},
102+
{
103+
"command": "deepnote.openInDeepnote",
104+
"title": "Open in Deepnote",
105+
"category": "Deepnote",
106+
"icon": "$(globe)"
107+
},
102108
{
103109
"command": "deepnote.newProject",
104110
"title": "New project",
@@ -129,6 +135,12 @@
129135
"category": "Deepnote",
130136
"icon": "$(graph)"
131137
},
138+
{
139+
"command": "deepnote.addChartBlock",
140+
"title": "%deepnote.commands.addChartBlock.title%",
141+
"category": "Deepnote",
142+
"icon": "$(graph-line)"
143+
},
132144
{
133145
"command": "deepnote.addInputTextBlock",
134146
"title": "%deepnote.commands.addInputTextBlock.title%",
@@ -761,6 +773,11 @@
761773
"when": "editorFocus && editorLangId == python && jupyter.hascodecells && !notebookEditorFocused && isWorkspaceTrusted",
762774
"command": "jupyter.exportfileasnotebook",
763775
"group": "Jupyter3@2"
776+
},
777+
{
778+
"when": "resourceExtname == .deepnote",
779+
"command": "deepnote.openInDeepnote",
780+
"group": "navigation"
764781
}
765782
],
766783
"editor.interactiveWindow.context": [
@@ -850,6 +867,51 @@
850867
"group": "navigation@1",
851868
"when": "notebookType == 'deepnote'"
852869
},
870+
{
871+
"command": "deepnote.addChartBlock",
872+
"group": "navigation@2",
873+
"when": "notebookType == 'deepnote'"
874+
},
875+
{
876+
"command": "deepnote.addBigNumberChartBlock",
877+
"group": "navigation@3",
878+
"when": "notebookType == 'deepnote'"
879+
},
880+
{
881+
"command": "deepnote.addInputTextBlock",
882+
"group": "navigation@4",
883+
"when": "notebookType == 'deepnote'"
884+
},
885+
{
886+
"command": "deepnote.addInputTextareaBlock",
887+
"group": "navigation@5",
888+
"when": "notebookType == 'deepnote'"
889+
},
890+
{
891+
"command": "deepnote.addInputSelectBlock",
892+
"group": "navigation@6",
893+
"when": "notebookType == 'deepnote'"
894+
},
895+
{
896+
"command": "deepnote.addInputSliderBlock",
897+
"group": "navigation@7",
898+
"when": "notebookType == 'deepnote'"
899+
},
900+
{
901+
"command": "deepnote.addInputCheckboxBlock",
902+
"group": "navigation@8",
903+
"when": "notebookType == 'deepnote'"
904+
},
905+
{
906+
"command": "deepnote.addInputDateBlock",
907+
"group": "navigation@9",
908+
"when": "notebookType == 'deepnote'"
909+
},
910+
{
911+
"command": "deepnote.addInputDateRangeBlock",
912+
"group": "navigation@10",
913+
"when": "notebookType == 'deepnote'"
914+
},
853915
{
854916
"command": "jupyter.restartkernel",
855917
"group": "navigation/execute@5",
@@ -1386,6 +1448,18 @@
13861448
"type": "object",
13871449
"title": "Deepnote",
13881450
"properties": {
1451+
"deepnote.domain": {
1452+
"type": "string",
1453+
"default": "deepnote.com",
1454+
"description": "Deepnote domain (e.g., 'deepnote.com' or 'ra-18838.deepnote-staging.com')",
1455+
"scope": "application"
1456+
},
1457+
"deepnote.disableSSLVerification": {
1458+
"type": "boolean",
1459+
"default": false,
1460+
"description": "Disable SSL certificate verification (for development only)",
1461+
"scope": "application"
1462+
},
13891463
"jupyter.experiments.enabled": {
13901464
"type": "boolean",
13911465
"default": true,

package.nls.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,8 @@
255255
"deepnote.commands.importNotebook.title": "Import Notebook",
256256
"deepnote.commands.importJupyterNotebook.title": "Import Jupyter Notebook",
257257
"deepnote.commands.addSqlBlock.title": "Add SQL Block",
258-
"deepnote.commands.addBigNumberChartBlock.title": "Add Big Number Chart Block",
258+
"deepnote.commands.addBigNumberChartBlock.title": "Add Big Number Block",
259+
"deepnote.commands.addChartBlock.title": "Add Chart Block",
259260
"deepnote.commands.addInputTextBlock.title": "Add Input Text Block",
260261
"deepnote.commands.addInputTextareaBlock.title": "Add Input Textarea Block",
261262
"deepnote.commands.addInputSelectBlock.title": "Add Input Select Block",

src/commands.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ export interface ICommandNameArgumentTypeMapping {
188188
[DSCommands.ContinueEditSessionInCodespace]: [];
189189
[DSCommands.AddSqlBlock]: [];
190190
[DSCommands.AddBigNumberChartBlock]: [];
191+
[DSCommands.AddChartBlock]: [];
191192
[DSCommands.AddInputTextBlock]: [];
192193
[DSCommands.AddInputTextareaBlock]: [];
193194
[DSCommands.AddInputSelectBlock]: [];
@@ -197,4 +198,5 @@ export interface ICommandNameArgumentTypeMapping {
197198
[DSCommands.AddInputDateRangeBlock]: [];
198199
[DSCommands.AddInputFileBlock]: [];
199200
[DSCommands.AddButtonBlock]: [];
201+
[DSCommands.OpenInDeepnote]: [];
200202
}

src/notebooks/deepnote/blocks.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ project:
4545
type: 'code'
4646
content: "df = pd.DataFrame({'a': [1, 2, 3]})\ndf"
4747
sortingKey: '001'
48-
blockGroup: 'default-group'
48+
blockGroup: 'uuid-v4'
4949
executionCount: 1
5050
metadata:
5151
table_state_spec: '{"pageSize": 25, "pageIndex": 0}'
@@ -150,7 +150,7 @@ Example of a cell after pocket conversion:
150150
__deepnotePocket: {
151151
type: 'code',
152152
sortingKey: '001',
153-
blockGroup: 'default-group',
153+
blockGroup: 'uuid-v4',
154154
executionCount: 1
155155
}
156156
},
@@ -472,7 +472,7 @@ blocks:
472472
type: 'big-number'
473473
content: ''
474474
sortingKey: '001'
475-
blockGroup: 'default-group'
475+
blockGroup: 'uuid-v4'
476476
metadata:
477477
deepnote_big_number_title: 'Customers'
478478
deepnote_big_number_value: 'customers'
@@ -517,7 +517,7 @@ When opened in VS Code, the block becomes a cell with JSON content showing the c
517517
__deepnotePocket: {
518518
type: 'big-number',
519519
sortingKey: '001',
520-
blockGroup: 'default-group'
520+
blockGroup: 'uuid-v4'
521521
}
522522
}
523523
}

src/notebooks/deepnote/deepnoteDataConverter.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
ButtonBlockConverter
2828
} from './converters/inputConverters';
2929
import { CHART_BIG_NUMBER_MIME_TYPE } from '../../platform/deepnote/deepnoteConstants';
30+
import { generateUuid } from '../../platform/common/uuid';
3031

3132
/**
3233
* Utility class for converting between Deepnote block structures and VS Code notebook cells.
@@ -168,7 +169,7 @@ export class DeepnoteDataConverter {
168169

169170
private createFallbackBlock(cell: NotebookCellData, index: number): DeepnoteBlock {
170171
return {
171-
blockGroup: 'default-group',
172+
blockGroup: generateUuid(),
172173
id: generateBlockId(),
173174
sortingKey: generateSortingKey(index),
174175
type: cell.kind === NotebookCellKind.Code ? 'code' : 'markdown',

src/notebooks/deepnote/deepnoteExplorerView.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { IDeepnoteNotebookManager } from '../types';
88
import { DeepnoteTreeDataProvider } from './deepnoteTreeDataProvider';
99
import { type DeepnoteTreeItem, DeepnoteTreeItemType, type DeepnoteTreeItemContext } from './deepnoteTreeItem';
1010
import { generateUuid } from '../../platform/common/uuid';
11+
import { DeepnoteBlock, DeepnoteFile } from '@deepnote/blocks';
1112

1213
/**
1314
* Manages the Deepnote explorer tree view and related commands
@@ -213,10 +214,10 @@ export class DeepnoteExplorerView {
213214
const projectId = generateUuid();
214215
const notebookId = generateUuid();
215216

216-
const firstBlock = {
217+
const firstBlock: DeepnoteBlock = {
217218
blockGroup: generateUuid(),
218219
content: '',
219-
executionCount: null,
220+
executionCount: 0,
220221
id: generateUuid(),
221222
metadata: {},
222223
outputs: [],
@@ -225,9 +226,10 @@ export class DeepnoteExplorerView {
225226
version: 1
226227
};
227228

228-
const projectData = {
229-
version: 1.0,
229+
const projectData: DeepnoteFile = {
230+
version: '1.0.0',
230231
metadata: {
232+
createdAt: new Date().toISOString(),
231233
modifiedAt: new Date().toISOString()
232234
},
233235
project: {

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,9 @@ suite('DeepnoteExplorerView - Empty State Commands', () => {
265265
const yamlContent = Buffer.from(capturedContent!).toString('utf8');
266266
const projectData = yaml.load(yamlContent) as any;
267267

268-
expect(projectData.version).to.equal(1.0);
268+
expect(projectData.version).to.equal('1.0.0');
269+
expect(projectData.metadata.createdAt).to.exist;
270+
expect(projectData.metadata.modifiedAt).to.exist;
269271
expect(projectData.project.id).to.equal(projectId);
270272
expect(projectData.project.name).to.equal(projectName);
271273
expect(projectData.project.notebooks).to.have.lengthOf(1);

src/notebooks/deepnote/deepnoteNotebookCommandListener.ts

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import { IExtensionSyncActivationService } from '../../platform/activation/types
1717
import { IDisposableRegistry } from '../../platform/common/types';
1818
import { Commands } from '../../platform/common/constants';
1919
import { chainWithPendingUpdates } from '../../kernels/execution/notebookUpdater';
20+
import { WrappedError } from '../../platform/errors/types';
2021
import {
2122
DeepnoteBigNumberMetadataSchema,
2223
DeepnoteTextInputMetadataSchema,
@@ -76,7 +77,10 @@ export function getInputBlockMetadata(blockType: InputBlockType, variableName: s
7677

7778
export function safeParseDeepnoteVariableNameFromContentJson(content: string): string | undefined {
7879
try {
79-
const variableNameResult = z.string().safeParse(JSON.parse(content)['deepnote_variable_name']);
80+
const parsed = JSON.parse(content);
81+
// Chart blocks use 'variable' key, other blocks use 'deepnote_variable_name'
82+
const variableName = parsed['variable'] ?? parsed['deepnote_variable_name'];
83+
const variableNameResult = z.string().safeParse(variableName);
8084
return variableNameResult.success ? variableNameResult.data : undefined;
8185
} catch (error) {
8286
logger.error('Error parsing deepnote variable name from content JSON', error);
@@ -148,6 +152,7 @@ export class DeepnoteNotebookCommandListener implements IExtensionSyncActivation
148152
this.disposableRegistry.push(
149153
commands.registerCommand(Commands.AddBigNumberChartBlock, () => this.addBigNumberChartBlock())
150154
);
155+
this.disposableRegistry.push(commands.registerCommand(Commands.AddChartBlock, () => this.addChartBlock()));
151156
this.disposableRegistry.push(
152157
commands.registerCommand(Commands.AddInputTextBlock, () => this.addInputBlock('input-text'))
153158
);
@@ -262,6 +267,61 @@ export class DeepnoteNotebookCommandListener implements IExtensionSyncActivation
262267
await commands.executeCommand('notebook.cell.edit');
263268
}
264269

270+
public async addChartBlock(): Promise<void> {
271+
const editor = window.activeNotebookEditor;
272+
273+
if (!editor) {
274+
throw new WrappedError(l10n.t('No active notebook editor found'));
275+
}
276+
277+
const document = editor.notebook;
278+
const selection = editor.selection;
279+
const insertIndex = selection ? selection.end : document.cellCount;
280+
281+
const defaultVisualizationSpec = {
282+
mark: 'line',
283+
$schema: 'https://vega.github.io/schema/vega-lite/v5.json',
284+
data: { values: [] },
285+
encoding: {
286+
x: { field: 'x', type: 'quantitative' },
287+
y: { field: 'y', type: 'quantitative' }
288+
}
289+
};
290+
291+
const cellContent = {
292+
variable: 'df_1',
293+
spec: defaultVisualizationSpec,
294+
filters: []
295+
};
296+
297+
const metadata = {
298+
__deepnotePocket: {
299+
type: 'visualization'
300+
}
301+
};
302+
303+
const result = await chainWithPendingUpdates(document, (edit) => {
304+
const newCell = new NotebookCellData(NotebookCellKind.Code, JSON.stringify(cellContent, null, 2), 'json');
305+
306+
newCell.metadata = metadata;
307+
308+
const nbEdit = NotebookEdit.insertCells(insertIndex, [newCell]);
309+
310+
edit.set(document.uri, [nbEdit]);
311+
});
312+
313+
if (result !== true) {
314+
throw new WrappedError(l10n.t('Failed to insert chart block'));
315+
}
316+
317+
const notebookRange = new NotebookRange(insertIndex, insertIndex + 1);
318+
319+
editor.revealRange(notebookRange, NotebookEditorRevealType.Default);
320+
editor.selection = notebookRange;
321+
322+
await commands.executeCommand('notebook.cell.edit');
323+
}
324+
265325
public async addInputBlock(blockType: InputBlockType): Promise<void> {
266326
const editor = window.activeNotebookEditor;
267327
if (!editor) {

0 commit comments

Comments
 (0)