Skip to content

Commit 5baa483

Browse files
committed
Merge remote-tracking branch 'origin/main' into tomaskislan/deepnote-notebook-management
Signed-off-by: Tomas Kislan <[email protected]>
2 parents 40cf352 + c1b5526 commit 5baa483

31 files changed

+1931
-211
lines changed

package-lock.json

Lines changed: 61 additions & 101 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vscode-deepnote",
33
"displayName": "Deepnote",
4-
"version": "0.1.0",
4+
"version": "0.2.0",
55
"description": "Deepnote notebook support.",
66
"publisher": "Deepnote",
77
"author": {
@@ -23,7 +23,7 @@
2323
"theme": "light"
2424
},
2525
"engines": {
26-
"vscode": "^1.103.0"
26+
"vscode": "^1.95.0"
2727
},
2828
"l10n": "./l10n",
2929
"extensionKind": [
@@ -70,6 +70,14 @@
7070
"key": "escape",
7171
"when": "isCompositeNotebook && !editorHoverVisible && !suggestWidgetVisible && !isComposing && !inSnippetMode && !exceptionWidgetVisible && !selectionAnchorSet && !LinkedEditingInputVisible && !renameInputVisible && !editorHasSelection && !accessibilityHelpWidgetVisible && !breakpointWidgetVisible && !findWidgetVisible && !markersNavigationVisible && !parameterHintsVisible && !editorHasMultipleSelections && !notificationToastsVisible && !notebookEditorFocused && !inlineChatVisible",
7272
"command": "interactive.input.clear"
73+
},
74+
{
75+
"key": "cmd+enter",
76+
"mac": "cmd+enter",
77+
"win": "ctrl+enter",
78+
"linux": "ctrl+enter",
79+
"when": "notebookEditorFocused && !findInputFocussed && !replaceInputFocussed",
80+
"command": "jupyter.notebookeditor.runfocusedcell"
7381
}
7482
],
7583
"commands": [
@@ -121,6 +129,12 @@
121129
"category": "Deepnote",
122130
"icon": "$(graph)"
123131
},
132+
{
133+
"command": "deepnote.addChartBlock",
134+
"title": "%deepnote.commands.addChartBlock.title%",
135+
"category": "Deepnote",
136+
"icon": "$(graph-line)"
137+
},
124138
{
125139
"command": "deepnote.addInputTextBlock",
126140
"title": "%deepnote.commands.addInputTextBlock.title%",
@@ -586,6 +600,12 @@
586600
"category": "Notebook",
587601
"enablement": "!jupyter.webExtension"
588602
},
603+
{
604+
"command": "jupyter.notebookeditor.runfocusedcell",
605+
"title": "%jupyter.command.jupyter.notebookeditor.runfocusedcell.title%",
606+
"category": "Notebook",
607+
"enablement": "notebookEditorFocused"
608+
},
589609
{
590610
"command": "jupyter.expandallcells",
591611
"title": "%jupyter.command.jupyter.expandallcells.title%",
@@ -756,9 +776,30 @@
756776
{
757777
"id": "editor.interactiveWindow.context",
758778
"label": "%jupyter.command.editor.interactiveWindow.context.label%"
779+
},
780+
{
781+
"id": "deepnote.explorer.context",
782+
"label": "Deepnote"
759783
}
760784
],
761785
"menus": {
786+
"view/title": [
787+
{
788+
"command": "deepnote.newProject",
789+
"when": "view == deepnoteExplorer",
790+
"group": "navigation@1"
791+
},
792+
{
793+
"command": "deepnote.importNotebook",
794+
"when": "view == deepnoteExplorer",
795+
"group": "navigation@2"
796+
},
797+
{
798+
"command": "deepnote.refreshExplorer",
799+
"when": "view == deepnoteExplorer",
800+
"group": "navigation@3"
801+
}
802+
],
762803
"editor/context": [
763804
{
764805
"submenu": "editor.interactiveWindow.context",
@@ -807,6 +848,14 @@
807848
"when": "editorFocus && editorLangId == python && !notebookEditorFocused && isWorkspaceTrusted"
808849
}
809850
],
851+
"deepnote.explorer.context": [
852+
{
853+
"command": "deepnote.newProject"
854+
},
855+
{
856+
"command": "deepnote.importNotebook"
857+
}
858+
],
810859
"editor/title": [
811860
{
812861
"command": "jupyter.restartkernel",
@@ -854,6 +903,51 @@
854903
"group": "navigation@2",
855904
"when": "notebookType == 'deepnote'"
856905
},
906+
{
907+
"command": "deepnote.addChartBlock",
908+
"group": "navigation@3",
909+
"when": "notebookType == 'deepnote'"
910+
},
911+
{
912+
"command": "deepnote.addBigNumberChartBlock",
913+
"group": "navigation@4",
914+
"when": "notebookType == 'deepnote'"
915+
},
916+
{
917+
"command": "deepnote.addInputTextBlock",
918+
"group": "navigation@5",
919+
"when": "notebookType == 'deepnote'"
920+
},
921+
{
922+
"command": "deepnote.addInputTextareaBlock",
923+
"group": "navigation@6",
924+
"when": "notebookType == 'deepnote'"
925+
},
926+
{
927+
"command": "deepnote.addInputSelectBlock",
928+
"group": "navigation@7",
929+
"when": "notebookType == 'deepnote'"
930+
},
931+
{
932+
"command": "deepnote.addInputSliderBlock",
933+
"group": "navigation@8",
934+
"when": "notebookType == 'deepnote'"
935+
},
936+
{
937+
"command": "deepnote.addInputCheckboxBlock",
938+
"group": "navigation@9",
939+
"when": "notebookType == 'deepnote'"
940+
},
941+
{
942+
"command": "deepnote.addInputDateBlock",
943+
"group": "navigation@10",
944+
"when": "notebookType == 'deepnote'"
945+
},
946+
{
947+
"command": "deepnote.addInputDateRangeBlock",
948+
"group": "navigation@11",
949+
"when": "notebookType == 'deepnote'"
950+
},
857951
{
858952
"command": "jupyter.restartkernel",
859953
"group": "navigation/execute@5",
@@ -984,6 +1078,11 @@
9841078
}
9851079
],
9861080
"explorer/context": [
1081+
{
1082+
"submenu": "deepnote.explorer.context",
1083+
"when": "isWorkspaceTrusted",
1084+
"group": "navigation@10"
1085+
},
9871086
{
9881087
"when": "resourceLangId == python && !notebookEditorFocused && isWorkspaceTrusted",
9891088
"command": "jupyter.runFileInteractive",

package.nls.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
"message": "Add Empty Cell to Notebook File",
9393
"comment": ["{Locked='Notebook'}"]
9494
},
95+
"jupyter.command.jupyter.notebookeditor.runfocusedcell.title": "Run Focused Cell",
9596
"jupyter.command.jupyter.interruptkernel.title": "Interrupt Kernel",
9697
"jupyter.command.jupyter.interruptkernel.shorttitle": "Interrupt",
9798
"jupyter.command.jupyter.restartkernel.title": "Restart Kernel",
@@ -254,7 +255,8 @@
254255
"deepnote.commands.importNotebook.title": "Import Notebook",
255256
"deepnote.commands.importJupyterNotebook.title": "Import Jupyter Notebook",
256257
"deepnote.commands.addSqlBlock.title": "Add SQL Block",
257-
"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",
258260
"deepnote.commands.addInputTextBlock.title": "Add Input Text Block",
259261
"deepnote.commands.addInputTextareaBlock.title": "Add Input Textarea Block",
260262
"deepnote.commands.addInputSelectBlock.title": "Add Input Select Block",

src/commands.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export interface ICommandNameArgumentTypeMapping {
5858
[DSCommands.RestartKernelAndRunUpToSelectedCell]: [{ notebookEditor: { notebookUri: Uri } } | undefined];
5959
[DSCommands.NotebookEditorRemoveAllCells]: [];
6060
[DSCommands.NotebookEditorRunAllCells]: [];
61+
[DSCommands.NotebookEditorRunFocusedCell]: [];
6162
[DSCommands.NotebookEditorAddCellBelow]: [];
6263
[DSCommands.ExpandAllCells]: [];
6364
[DSCommands.CollapseAllCells]: [];
@@ -185,9 +186,10 @@ export interface ICommandNameArgumentTypeMapping {
185186
[DSCommands.InstallPythonExtensionViaKernelPicker]: [];
186187
[DSCommands.InstallPythonViaKernelPicker]: [];
187188
[DSCommands.ContinueEditSessionInCodespace]: [];
189+
[DSCommands.NewNotebook]: [];
188190
[DSCommands.AddSqlBlock]: [];
189191
[DSCommands.AddBigNumberChartBlock]: [];
190-
[DSCommands.NewNotebook]: [];
192+
[DSCommands.AddChartBlock]: [];
191193
[DSCommands.AddInputTextBlock]: [];
192194
[DSCommands.AddInputTextareaBlock]: [];
193195
[DSCommands.AddInputSelectBlock]: [];

src/messageTypes.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ export type LocalizedMessages = {
182182
// Integration type labels
183183
integrationsPostgresTypeLabel: string;
184184
integrationsBigQueryTypeLabel: string;
185+
integrationsSnowflakeTypeLabel: string;
185186
// PostgreSQL form strings
186187
integrationsPostgresNameLabel: string;
187188
integrationsPostgresNamePlaceholder: string;
@@ -204,9 +205,36 @@ export type LocalizedMessages = {
204205
integrationsBigQueryCredentialsLabel: string;
205206
integrationsBigQueryCredentialsPlaceholder: string;
206207
integrationsBigQueryCredentialsRequired: string;
208+
// Snowflake form strings
209+
integrationsSnowflakeNameLabel: string;
210+
integrationsSnowflakeNamePlaceholder: string;
211+
integrationsSnowflakeAccountLabel: string;
212+
integrationsSnowflakeAccountPlaceholder: string;
213+
integrationsSnowflakeAuthMethodLabel: string;
214+
integrationsSnowflakeAuthMethodSubLabel: string;
215+
integrationsSnowflakeAuthMethodUsernamePassword: string;
216+
integrationsSnowflakeAuthMethodKeyPair: string;
217+
integrationsSnowflakeUnsupportedAuthMethod: string;
218+
integrationsSnowflakeUsernameLabel: string;
219+
integrationsSnowflakePasswordLabel: string;
220+
integrationsSnowflakePasswordPlaceholder: string;
221+
integrationsSnowflakeServiceAccountUsernameLabel: string;
222+
integrationsSnowflakeServiceAccountUsernameHelp: string;
223+
integrationsSnowflakePrivateKeyLabel: string;
224+
integrationsSnowflakePrivateKeyHelp: string;
225+
integrationsSnowflakePrivateKeyPlaceholder: string;
226+
integrationsSnowflakePrivateKeyPassphraseLabel: string;
227+
integrationsSnowflakePrivateKeyPassphraseHelp: string;
228+
integrationsSnowflakeDatabaseLabel: string;
229+
integrationsSnowflakeDatabasePlaceholder: string;
230+
integrationsSnowflakeRoleLabel: string;
231+
integrationsSnowflakeRolePlaceholder: string;
232+
integrationsSnowflakeWarehouseLabel: string;
233+
integrationsSnowflakeWarehousePlaceholder: string;
207234
// Common form strings
208235
integrationsRequiredField: string;
209236
integrationsOptionalField: string;
237+
integrationsUnnamedIntegration: string;
210238
};
211239
// Map all messages to specific payloads
212240
export class IInteractiveWindowMapping {

src/notebooks/deepnote/deepnoteNotebookCommandListener.ts

Lines changed: 63 additions & 2 deletions
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,
@@ -30,6 +31,7 @@ import {
3031
DeepnoteButtonMetadataSchema,
3132
DeepnoteSqlMetadata
3233
} from './deepnoteSchemas';
34+
import { DATAFRAME_SQL_INTEGRATION_ID } from '../../platform/notebooks/deepnote/integrationTypes';
3335

3436
export type InputBlockType =
3537
| 'input-text'
@@ -75,7 +77,10 @@ export function getInputBlockMetadata(blockType: InputBlockType, variableName: s
7577

7678
export function safeParseDeepnoteVariableNameFromContentJson(content: string): string | undefined {
7779
try {
78-
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);
7984
return variableNameResult.success ? variableNameResult.data : undefined;
8085
} catch (error) {
8186
logger.error('Error parsing deepnote variable name from content JSON', error);
@@ -147,6 +152,7 @@ export class DeepnoteNotebookCommandListener implements IExtensionSyncActivation
147152
this.disposableRegistry.push(
148153
commands.registerCommand(Commands.AddBigNumberChartBlock, () => this.addBigNumberChartBlock())
149154
);
155+
this.disposableRegistry.push(commands.registerCommand(Commands.AddChartBlock, () => this.addChartBlock()));
150156
this.disposableRegistry.push(
151157
commands.registerCommand(Commands.AddInputTextBlock, () => this.addInputBlock('input-text'))
152158
);
@@ -189,7 +195,7 @@ export class DeepnoteNotebookCommandListener implements IExtensionSyncActivation
189195
const defaultMetadata: DeepnoteSqlMetadata = {
190196
deepnote_variable_name: deepnoteVariableName,
191197
deepnote_return_variable_type: 'dataframe',
192-
sql_integration_id: 'deepnote-dataframe-sql'
198+
sql_integration_id: DATAFRAME_SQL_INTEGRATION_ID
193199
};
194200

195201
// Determine the index where to insert the new cell (below current selection or at the end)
@@ -261,6 +267,61 @@ export class DeepnoteNotebookCommandListener implements IExtensionSyncActivation
261267
await commands.executeCommand('notebook.cell.edit');
262268
}
263269

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+
264325
public async addInputBlock(blockType: InputBlockType): Promise<void> {
265326
const editor = window.activeNotebookEditor;
266327
if (!editor) {

0 commit comments

Comments
 (0)