From 71016e92cd31932902222ef249f53761b522875a Mon Sep 17 00:00:00 2001 From: Ilia Babanov Date: Tue, 17 Mar 2026 12:10:27 +0100 Subject: [PATCH 1/4] Add remote mode: disable all commands and show placeholder UI when DATABRICKS_REMOTE_ENV=1 When running inside a Databricks Remote SSH session (DATABRICKS_REMOTE_ENV=1 and DATABRICKS_VIRTUAL_ENV set), the extension now activates in a minimal mode: it sets the Python virtual env path, registers a placeholder tree view, and disables all Databricks-specific commands/views/menus via the new `databricks.context.remoteMode` when-context. Co-authored-by: Isaac --- packages/databricks-vscode/package.json | 117 +++++++++--------- packages/databricks-vscode/src/extension.ts | 22 ++++ .../RemoteModeDataProvider.test.ts | 40 ++++++ .../RemoteModeDataProvider.ts | 36 ++++++ .../src/vscode-objs/CustomWhenContext.ts | 8 ++ 5 files changed, 166 insertions(+), 57 deletions(-) create mode 100644 packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.test.ts create mode 100644 packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.ts diff --git a/packages/databricks-vscode/package.json b/packages/databricks-vscode/package.json index 3532cadc8..ea448111e 100644 --- a/packages/databricks-vscode/package.json +++ b/packages/databricks-vscode/package.json @@ -55,67 +55,67 @@ "command": "databricks.connection.logout", "title": "Logout", "category": "Databricks", - "enablement": "databricks.context.activated && databricks.context.loggedIn" + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode" }, { "command": "databricks.connection.configureLogin", "icon": "$(gear)", "title": "Sign in to Databricks workspace", - "enablement": "databricks.context.activated && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.connection.openDatabricksConfigFile", "title": "Open Databricks configuration file", - "enablement": "databricks.context.activated", + "enablement": "databricks.context.activated && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.connection.attachCluster", "title": "Attach cluster", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "icon": "$(plug)" }, { "command": "databricks.connection.attachClusterQuickPick", "title": "Configure cluster", "category": "Databricks", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "icon": "$(gear)" }, { "command": "databricks.connection.detachCluster", "title": "Detach cluster", "category": "Databricks", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "icon": "$(debug-disconnect)" }, { "command": "databricks.cluster.filterByAll", "title": "All", - "enablement": "databricks.context.activated && databricks.context.loggedIn" + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode" }, { "command": "databricks.cluster.filterByRunning", "title": "Running", - "enablement": "databricks.context.activated && databricks.context.loggedIn" + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode" }, { "command": "databricks.cluster.filterByMe", "title": "Created by me", - "enablement": "databricks.context.activated && databricks.context.loggedIn" + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode" }, { "command": "databricks.cluster.refresh", "icon": "$(refresh)", "title": "Refresh", - "enablement": "databricks.context.activated && databricks.context.loggedIn" + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode" }, { "command": "databricks.run.runEditorContentsAsWorkflow", "title": "Run File as Workflow", "category": "Databricks", - "enablement": "!inDebugMode && databricks.context.activated && databricks.context.loggedIn", + "enablement": "!inDebugMode && databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "icon": { "dark": "resources/dark/databricks-run-icon.svg", "light": "resources/light/databricks-run-icon.svg" @@ -125,7 +125,7 @@ "command": "databricks.run.runEditorContents", "title": "Upload and Run File", "category": "Databricks", - "enablement": "!inDebugMode && databricks.context.activated && databricks.context.loggedIn && !databricks.context.serverless", + "enablement": "!inDebugMode && databricks.context.activated && databricks.context.loggedIn && !databricks.context.serverless && !databricks.context.remoteMode", "icon": { "dark": "resources/dark/databricks-run-icon.svg", "light": "resources/light/databricks-run-icon.svg" @@ -134,7 +134,8 @@ { "command": "databricks.quickstart.open", "title": "Show Quickstart", - "category": "Databricks" + "category": "Databricks", + "enablement": "!databricks.context.remoteMode" }, { "command": "databricks.logs.openFolder", @@ -144,21 +145,21 @@ { "command": "databricks.autocomplete.configure", "title": "Configure autocomplete for Databricks globals", - "enablement": "databricks.context.activated", + "enablement": "databricks.context.activated && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.cluster.start", "title": "Start Cluster", "icon": "$(debug-start)", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.cluster.stop", "title": "Stop Cluster", "icon": "$(stop-circle)", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "category": "Databricks" }, { @@ -177,14 +178,14 @@ "command": "databricks.wsfs.refresh", "title": "Refresh workspace filesystem view", "icon": "$(refresh)", - "enablement": "databricks.context.activated && databricks.context.loggedIn && config.databricks.sync.destinationType == workspace && databricks.feature.views.workspace", + "enablement": "databricks.context.activated && databricks.context.loggedIn && config.databricks.sync.destinationType == workspace && databricks.feature.views.workspace && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.wsfs.createFolder", "title": "Create Folder", "icon": "$(new-folder)", - "enablement": "databricks.context.activated && databricks.context.loggedIn && databricks.feature.views.workspace", + "enablement": "databricks.context.activated && databricks.context.loggedIn && databricks.feature.views.workspace && !databricks.context.remoteMode", "category": "Databricks" }, { @@ -200,63 +201,63 @@ { "command": "databricks.notebookInitScript.verify", "title": "Verify Databricks notebook init scripts", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.connection.bundle.selectTarget", "icon": "$(gear)", "title": "Select a Databricks Asset Bundle target", - "enablement": "databricks.context.activated", + "enablement": "databricks.context.activated && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.selectActiveProjectFolder", "icon": "$(gear)", "title": "Select a Databricks project folder", - "enablement": "databricks.context.activated && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.refreshRemoteState", "icon": "$(refresh)", "title": "Refresh remote state", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.deploy", "icon": "$(cloud-upload)", "title": "Deploy bundle", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.deployAndRunFromInput", "icon": "$(run)", "title": "Deploy the bundle and run a resource", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.deployAndRunJob", "icon": "$(run)", "title": "Deploy the bundle and run the job", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.deployAndRunPipeline", "icon": "$(run-all)", "title": "Deploy the bundle and run the pipeline", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.deployAndRunSelectedTables", "icon": "$(run)", "title": "Deploy the bundle and select pipeline tables for partial update", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks" }, { @@ -266,40 +267,41 @@ "light": "resources/light/check-line-icon.svg" }, "title": "Deploy the bundle and validate the pipeline", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.clearPipelineDiagnostics", "icon": "$(clear-all)", "title": "Clear pipeline diagnostics", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.showPipelineEventDetails", "icon": "$(info)", "title": "Show more information", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.cancelRun", "title": "Cancel run", "icon": "$(stop)", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.initNewProject", "icon": "$(new-folder)", "title": "Initialize new project", - "category": "Databricks" + "category": "Databricks", + "enablement": "!databricks.context.remoteMode" }, { "command": "databricks.run.dbconnect.debug", "title": "Debug current file with Databricks Connect", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "category": "Databricks", "icon": { "dark": "resources/dark/databricks-run-icon.svg", @@ -309,7 +311,7 @@ { "command": "databricks.run.dbconnect.run", "title": "Run current file with Databricks Connect", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "category": "Databricks", "icon": { "dark": "resources/dark/databricks-run-icon.svg", @@ -319,7 +321,7 @@ { "command": "databricks.bundle.showLogs", "title": "Show bundle logs", - "enablement": "databricks.context.activated", + "enablement": "databricks.context.activated && !databricks.context.remoteMode", "category": "Databricks" }, { @@ -332,48 +334,48 @@ "command": "databricks.environment.refresh", "title": "Refresh python environment status", "icon": "$(refresh)", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.environment.setup", "title": "Setup python environment", "icon": "$(gear)", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.environment.selectPythonInterpreter", "title": "Change Python environment", "icon": "$(gear)", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.environment.reinstallDBConnect", "title": "Reinstall Databricks Connect", "icon": "$(gear)", - "enablement": "databricks.context.activated && databricks.context.loggedIn", + "enablement": "databricks.context.activated && databricks.context.loggedIn && !databricks.context.remoteMode", "category": "Databricks" }, { "command": "databricks.bundle.variable.openFile", "title": "Override bundle variables", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks", "icon": "$(gear)" }, { "command": "databricks.bundle.variable.reset", "title": "Reset bundle variables to default values", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks", "icon": "$(discard)" }, { "command": "databricks.bundle.destroy", "title": "Destroy bundle", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle", + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode", "category": "Databricks", "icon": "$(trash)" }, @@ -381,33 +383,33 @@ "command": "databricks.bundle.forceDeploy", "title": "Force deploy bundle", "category": "Databricks", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle" + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode" }, { "command": "databricks.bundle.forceDestroy", "title": "Force destroy bundle", "category": "Databricks", - "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle" + "enablement": "databricks.context.activated && databricks.context.bundle.isTargetSet && databricks.context.bundle.deploymentState == idle && !databricks.context.remoteMode" }, { "command": "databricks.sync.start", "title": "Start synchronization", "category": "Databricks", - "enablement": "databricks.context.activated && databricks.context.loggedIn && databricks.context.bundle.isTargetSet && databricks.context.bundle.isDevTarget", + "enablement": "databricks.context.activated && databricks.context.loggedIn && databricks.context.bundle.isTargetSet && databricks.context.bundle.isDevTarget && !databricks.context.remoteMode", "icon": "$(sync)" }, { "command": "databricks.sync.startFull", "title": "Start synchronization (full sync)", "category": "Databricks", - "enablement": "databricks.context.activated && databricks.context.loggedIn && databricks.context.bundle.isTargetSet && databricks.context.bundle.isDevTarget", + "enablement": "databricks.context.activated && databricks.context.loggedIn && databricks.context.bundle.isTargetSet && databricks.context.bundle.isDevTarget && !databricks.context.remoteMode", "icon": "$(sync)" }, { "command": "databricks.sync.stop", "title": "Stop synchronization", "category": "Databricks", - "enablement": "databricks.context.activated && databricks.context.loggedIn && databricks.context.bundle.isTargetSet && databricks.context.bundle.isDevTarget", + "enablement": "databricks.context.activated && databricks.context.loggedIn && databricks.context.bundle.isTargetSet && databricks.context.bundle.isDevTarget && !databricks.context.remoteMode", "icon": "$(sync-ignored)" } ], @@ -428,29 +430,30 @@ }, { "id": "clusterView", - "when": "databricks.feature.views.cluster", + "when": "databricks.feature.views.cluster && !databricks.context.remoteMode", "name": "Clusters" }, { "id": "dabsResourceExplorerView", "name": "Bundle Resource Explorer", "visibility": "visible", - "when": "databricks.context.bundle.isTargetSet" + "when": "databricks.context.bundle.isTargetSet && !databricks.context.remoteMode" }, { "id": "dabsVariableView", "name": "Bundle Variables", "visibility": "visible", - "when": "databricks.context.bundle.isTargetSet" + "when": "databricks.context.bundle.isTargetSet && !databricks.context.remoteMode" }, { "id": "workspaceFsView", "name": "Workspace explorer", - "when": "databricks.feature.views.workspace" + "when": "databricks.feature.views.workspace && !databricks.context.remoteMode" }, { "id": "databricksDocsView", - "name": "Documentation" + "name": "Documentation", + "when": "!databricks.context.remoteMode" } ] }, @@ -504,12 +507,12 @@ "view/title": [ { "command": "databricks.quickstart.open", - "when": "view == configurationView" + "when": "view == configurationView && !databricks.context.remoteMode" }, { "command": "databricks.bundle.initNewProject", "group": "navigation@1", - "when": "view == configurationView" + "when": "view == configurationView && !databricks.context.remoteMode" }, { "when": "view == clusterView", @@ -788,13 +791,13 @@ { "submenu": "databricks.run", "group": "navigation@0", - "when": "databricks.context.isActiveFileInActiveWorkspace && databricks.context.showRunAsWorkflow || databricks.context.isActiveFileInActiveWorkspace && resourceExtname == .ipynb" + "when": "!databricks.context.remoteMode && databricks.context.isActiveFileInActiveWorkspace && databricks.context.showRunAsWorkflow || !databricks.context.remoteMode && databricks.context.isActiveFileInActiveWorkspace && resourceExtname == .ipynb" } ], "databricks.run": [ { "command": "databricks.connection.configureLogin", - "when": "databricks.context.activated && !databricks.context.loggedIn", + "when": "databricks.context.activated && !databricks.context.loggedIn && !databricks.context.remoteMode", "group": "1_login@0" }, { @@ -879,7 +882,7 @@ "explorer/context": [ { "submenu": "databricks.run", - "when": "resourceLangId == python || resourceExtname == .ipynb || databricks.context.showRunAsWorkflow" + "when": "!databricks.context.remoteMode && (resourceLangId == python || resourceExtname == .ipynb || databricks.context.showRunAsWorkflow)" } ] }, diff --git a/packages/databricks-vscode/src/extension.ts b/packages/databricks-vscode/src/extension.ts index 4713b02eb..ec5f8f5ed 100644 --- a/packages/databricks-vscode/src/extension.ts +++ b/packages/databricks-vscode/src/extension.ts @@ -74,6 +74,7 @@ import {SyncCommands} from "./sync/SyncCommands"; import {CodeSynchronizer} from "./sync"; import {BundlePipelinesManager} from "./bundle/BundlePipelinesManager"; import {DocsViewTreeDataProvider} from "./ui/docs-view/DocsViewTreeDataProvider"; +import {RemoteModeDataProvider} from "./ui/configuration-view/RemoteModeDataProvider"; // eslint-disable-next-line @typescript-eslint/no-var-requires const packageJson = require("../package.json"); @@ -227,6 +228,27 @@ export async function activate( cli.setPythonExtension(pythonExtensionWrapper); + // When running inside a Databricks Remote SSH session, activate only the + // venv and show a placeholder UI. All other features are inapplicable. + const venvPath = process.env["DATABRICKS_VIRTUAL_ENV"]; + if (process.env["DATABRICKS_REMOTE_ENV"] === "1" && venvPath) { + customWhenContext.setRemoteMode(true); + + await pythonExtensionWrapper.api.environments.updateActiveEnvironmentPath( + venvPath + ); + + context.subscriptions.push( + window.registerTreeDataProvider( + "configurationView", + new RemoteModeDataProvider(venvPath) + ) + ); + + customWhenContext.setActivated(true); + return undefined; + } + // manage contexts for experimental features function updateFeatureContexts() { customWhenContext.updateShowClusterView(); diff --git a/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.test.ts b/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.test.ts new file mode 100644 index 000000000..4c42a63db --- /dev/null +++ b/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.test.ts @@ -0,0 +1,40 @@ +import assert from "assert"; +import {RemoteModeDataProvider} from "./RemoteModeDataProvider"; + +describe("RemoteModeDataProvider", () => { + it("returns three root items when venv path is set", () => { + const provider = new RemoteModeDataProvider("/usr/bin/python3"); + const items = provider.getChildren(undefined); + + assert.strictEqual(items.length, 3); + assert.ok( + String(items[0].label).includes("Databricks Remote SSH Mode") + ); + assert.ok(String(items[1].label).includes("Python environment")); + assert.strictEqual(items[1].description, "/usr/bin/python3"); + assert.ok(String(items[2].label).includes("More features")); + }); + + it("shows 'not found' description when venv path is undefined", () => { + const provider = new RemoteModeDataProvider(undefined); + const items = provider.getChildren(undefined); + + assert.strictEqual(items.length, 3); + assert.strictEqual(items[1].description, "not found"); + }); + + it("returns no children for a tree item", () => { + const provider = new RemoteModeDataProvider("/usr/bin/python3"); + const roots = provider.getChildren(undefined); + const children = provider.getChildren(roots[0]); + + assert.deepStrictEqual(children, []); + }); + + it("getTreeItem returns the element unchanged", () => { + const provider = new RemoteModeDataProvider("/usr/bin/python3"); + const items = provider.getChildren(undefined); + const item = items[0]; + assert.strictEqual(provider.getTreeItem(item), item); + }); +}); diff --git a/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.ts b/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.ts new file mode 100644 index 000000000..862296391 --- /dev/null +++ b/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.ts @@ -0,0 +1,36 @@ +import {TreeDataProvider, TreeItem, TreeItemCollapsibleState} from "vscode"; + +export class RemoteModeDataProvider implements TreeDataProvider { + private readonly items: TreeItem[]; + + constructor(venvPath: string | undefined) { + const venvItem = new TreeItem( + "$(check) Python environment activated", + TreeItemCollapsibleState.None + ); + venvItem.description = venvPath ?? "not found"; + + this.items = [ + new TreeItem( + "$(remote-explorer) Databricks Remote SSH Mode", + TreeItemCollapsibleState.None + ), + venvItem, + new TreeItem( + "$(info) More features coming soon...", + TreeItemCollapsibleState.None + ), + ]; + } + + getTreeItem(element: TreeItem): TreeItem { + return element; + } + + getChildren(element?: TreeItem): TreeItem[] { + if (element !== undefined) { + return []; + } + return this.items; + } +} diff --git a/packages/databricks-vscode/src/vscode-objs/CustomWhenContext.ts b/packages/databricks-vscode/src/vscode-objs/CustomWhenContext.ts index 4a6644924..160f62d99 100644 --- a/packages/databricks-vscode/src/vscode-objs/CustomWhenContext.ts +++ b/packages/databricks-vscode/src/vscode-objs/CustomWhenContext.ts @@ -118,4 +118,12 @@ export class CustomWhenContext { value ); } + + setRemoteMode(value: boolean) { + commands.executeCommand( + "setContext", + "databricks.context.remoteMode", + value + ); + } } From 62262893f414806a3f3105865bef7cdb3939f3fb Mon Sep 17 00:00:00 2001 From: Ilia Babanov Date: Tue, 17 Mar 2026 14:56:29 +0100 Subject: [PATCH 2/4] Remove RemoteModeDataProvider and hide configurationView in remote mode Replace the placeholder tree view with simply hiding the entire configuration view panel via a when-condition. This is simpler and avoids unnecessary UI clutter. Co-authored-by: Isaac --- packages/databricks-vscode/package.json | 3 +- packages/databricks-vscode/src/extension.ts | 16 ++++---- .../RemoteModeDataProvider.test.ts | 40 ------------------- .../RemoteModeDataProvider.ts | 36 ----------------- 4 files changed, 10 insertions(+), 85 deletions(-) delete mode 100644 packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.test.ts delete mode 100644 packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.ts diff --git a/packages/databricks-vscode/package.json b/packages/databricks-vscode/package.json index ea448111e..e81f7f574 100644 --- a/packages/databricks-vscode/package.json +++ b/packages/databricks-vscode/package.json @@ -426,7 +426,8 @@ "databricksBar": [ { "id": "configurationView", - "name": "Configuration" + "name": "Configuration", + "when": "!databricks.context.remoteMode" }, { "id": "clusterView", diff --git a/packages/databricks-vscode/src/extension.ts b/packages/databricks-vscode/src/extension.ts index ec5f8f5ed..f96328a92 100644 --- a/packages/databricks-vscode/src/extension.ts +++ b/packages/databricks-vscode/src/extension.ts @@ -74,7 +74,6 @@ import {SyncCommands} from "./sync/SyncCommands"; import {CodeSynchronizer} from "./sync"; import {BundlePipelinesManager} from "./bundle/BundlePipelinesManager"; import {DocsViewTreeDataProvider} from "./ui/docs-view/DocsViewTreeDataProvider"; -import {RemoteModeDataProvider} from "./ui/configuration-view/RemoteModeDataProvider"; // eslint-disable-next-line @typescript-eslint/no-var-requires const packageJson = require("../package.json"); @@ -231,23 +230,24 @@ export async function activate( // When running inside a Databricks Remote SSH session, activate only the // venv and show a placeholder UI. All other features are inapplicable. const venvPath = process.env["DATABRICKS_VIRTUAL_ENV"]; + console.log( + "[Databricks] Remote mode check:", + `DATABRICKS_REMOTE_ENV=${process.env["DATABRICKS_REMOTE_ENV"]}`, + `DATABRICKS_VIRTUAL_ENV=${venvPath ?? "(not set)"}` + ); if (process.env["DATABRICKS_REMOTE_ENV"] === "1" && venvPath) { + console.log("[Databricks] Entering remote mode, venv:", venvPath); customWhenContext.setRemoteMode(true); await pythonExtensionWrapper.api.environments.updateActiveEnvironmentPath( venvPath ); - - context.subscriptions.push( - window.registerTreeDataProvider( - "configurationView", - new RemoteModeDataProvider(venvPath) - ) - ); + console.log("[Databricks] Python environment set to:", venvPath); customWhenContext.setActivated(true); return undefined; } + console.log("[Databricks] Remote mode not activated, continuing normal initialization"); // manage contexts for experimental features function updateFeatureContexts() { diff --git a/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.test.ts b/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.test.ts deleted file mode 100644 index 4c42a63db..000000000 --- a/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import assert from "assert"; -import {RemoteModeDataProvider} from "./RemoteModeDataProvider"; - -describe("RemoteModeDataProvider", () => { - it("returns three root items when venv path is set", () => { - const provider = new RemoteModeDataProvider("/usr/bin/python3"); - const items = provider.getChildren(undefined); - - assert.strictEqual(items.length, 3); - assert.ok( - String(items[0].label).includes("Databricks Remote SSH Mode") - ); - assert.ok(String(items[1].label).includes("Python environment")); - assert.strictEqual(items[1].description, "/usr/bin/python3"); - assert.ok(String(items[2].label).includes("More features")); - }); - - it("shows 'not found' description when venv path is undefined", () => { - const provider = new RemoteModeDataProvider(undefined); - const items = provider.getChildren(undefined); - - assert.strictEqual(items.length, 3); - assert.strictEqual(items[1].description, "not found"); - }); - - it("returns no children for a tree item", () => { - const provider = new RemoteModeDataProvider("/usr/bin/python3"); - const roots = provider.getChildren(undefined); - const children = provider.getChildren(roots[0]); - - assert.deepStrictEqual(children, []); - }); - - it("getTreeItem returns the element unchanged", () => { - const provider = new RemoteModeDataProvider("/usr/bin/python3"); - const items = provider.getChildren(undefined); - const item = items[0]; - assert.strictEqual(provider.getTreeItem(item), item); - }); -}); diff --git a/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.ts b/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.ts deleted file mode 100644 index 862296391..000000000 --- a/packages/databricks-vscode/src/ui/configuration-view/RemoteModeDataProvider.ts +++ /dev/null @@ -1,36 +0,0 @@ -import {TreeDataProvider, TreeItem, TreeItemCollapsibleState} from "vscode"; - -export class RemoteModeDataProvider implements TreeDataProvider { - private readonly items: TreeItem[]; - - constructor(venvPath: string | undefined) { - const venvItem = new TreeItem( - "$(check) Python environment activated", - TreeItemCollapsibleState.None - ); - venvItem.description = venvPath ?? "not found"; - - this.items = [ - new TreeItem( - "$(remote-explorer) Databricks Remote SSH Mode", - TreeItemCollapsibleState.None - ), - venvItem, - new TreeItem( - "$(info) More features coming soon...", - TreeItemCollapsibleState.None - ), - ]; - } - - getTreeItem(element: TreeItem): TreeItem { - return element; - } - - getChildren(element?: TreeItem): TreeItem[] { - if (element !== undefined) { - return []; - } - return this.items; - } -} From 36d66ba18627e38f3275cd8d88a2b7bb61ef691a Mon Sep 17 00:00:00 2001 From: Ilia Babanov Date: Tue, 17 Mar 2026 17:18:18 +0100 Subject: [PATCH 3/4] More robust way of enabling the venv --- packages/databricks-vscode/package.json | 1 + packages/databricks-vscode/src/extension.ts | 22 ++++++++++----------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/databricks-vscode/package.json b/packages/databricks-vscode/package.json index e81f7f574..ace6100bf 100644 --- a/packages/databricks-vscode/package.json +++ b/packages/databricks-vscode/package.json @@ -37,6 +37,7 @@ "url": "https://github.com/databricks/databricks-vscode.git" }, "activationEvents": [ + "onLanguage:python", "onCommand:databricks.*", "onTaskType:databricks", "onDebugResolve:databricks", diff --git a/packages/databricks-vscode/src/extension.ts b/packages/databricks-vscode/src/extension.ts index f96328a92..2de05d1a8 100644 --- a/packages/databricks-vscode/src/extension.ts +++ b/packages/databricks-vscode/src/extension.ts @@ -230,24 +230,24 @@ export async function activate( // When running inside a Databricks Remote SSH session, activate only the // venv and show a placeholder UI. All other features are inapplicable. const venvPath = process.env["DATABRICKS_VIRTUAL_ENV"]; - console.log( - "[Databricks] Remote mode check:", - `DATABRICKS_REMOTE_ENV=${process.env["DATABRICKS_REMOTE_ENV"]}`, - `DATABRICKS_VIRTUAL_ENV=${venvPath ?? "(not set)"}` - ); + logging.NamedLogger.getOrCreate(Loggers.Extension).debug("Remote mode check", { + DATABRICKS_REMOTE_ENV: process.env["DATABRICKS_REMOTE_ENV"], + DATABRICKS_VIRTUAL_ENV: venvPath ?? "(not set)", + }); if (process.env["DATABRICKS_REMOTE_ENV"] === "1" && venvPath) { - console.log("[Databricks] Entering remote mode, venv:", venvPath); + logging.NamedLogger.getOrCreate(Loggers.Extension).debug("Entering remote mode", {venvPath}); customWhenContext.setRemoteMode(true); - await pythonExtensionWrapper.api.environments.updateActiveEnvironmentPath( - venvPath - ); - console.log("[Databricks] Python environment set to:", venvPath); + try { + await pythonExtensionWrapper.api.environments.updateActiveEnvironmentPath(venvPath); + } catch(e) { + logging.NamedLogger.getOrCreate(Loggers.Extension).error("Failed to update active python environment", e); + } customWhenContext.setActivated(true); return undefined; } - console.log("[Databricks] Remote mode not activated, continuing normal initialization"); + logging.NamedLogger.getOrCreate(Loggers.Extension).debug("Remote mode not activated, continuing normal initialization"); // manage contexts for experimental features function updateFeatureContexts() { From 8ca490d87af7a6a1f54d4746aafe82d2d0b87752 Mon Sep 17 00:00:00 2001 From: Ilia Babanov Date: Tue, 17 Mar 2026 17:41:01 +0100 Subject: [PATCH 4/4] Style fixes --- packages/databricks-vscode/src/extension.ts | 31 +++++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/packages/databricks-vscode/src/extension.ts b/packages/databricks-vscode/src/extension.ts index 2de05d1a8..35f247535 100644 --- a/packages/databricks-vscode/src/extension.ts +++ b/packages/databricks-vscode/src/extension.ts @@ -230,24 +230,37 @@ export async function activate( // When running inside a Databricks Remote SSH session, activate only the // venv and show a placeholder UI. All other features are inapplicable. const venvPath = process.env["DATABRICKS_VIRTUAL_ENV"]; - logging.NamedLogger.getOrCreate(Loggers.Extension).debug("Remote mode check", { - DATABRICKS_REMOTE_ENV: process.env["DATABRICKS_REMOTE_ENV"], - DATABRICKS_VIRTUAL_ENV: venvPath ?? "(not set)", - }); + logging.NamedLogger.getOrCreate(Loggers.Extension).debug( + "Remote mode check", + { + databricksRemoteEnv: process.env["DATABRICKS_REMOTE_ENV"], + databricksVirtualEnv: venvPath ?? "(not set)", + } + ); if (process.env["DATABRICKS_REMOTE_ENV"] === "1" && venvPath) { - logging.NamedLogger.getOrCreate(Loggers.Extension).debug("Entering remote mode", {venvPath}); + logging.NamedLogger.getOrCreate(Loggers.Extension).debug( + "Entering remote mode", + {venvPath} + ); customWhenContext.setRemoteMode(true); try { - await pythonExtensionWrapper.api.environments.updateActiveEnvironmentPath(venvPath); - } catch(e) { - logging.NamedLogger.getOrCreate(Loggers.Extension).error("Failed to update active python environment", e); + await pythonExtensionWrapper.api.environments.updateActiveEnvironmentPath( + venvPath + ); + } catch (e) { + logging.NamedLogger.getOrCreate(Loggers.Extension).error( + "Failed to update active python environment", + e + ); } customWhenContext.setActivated(true); return undefined; } - logging.NamedLogger.getOrCreate(Loggers.Extension).debug("Remote mode not activated, continuing normal initialization"); + logging.NamedLogger.getOrCreate(Loggers.Extension).debug( + "Remote mode not activated, continuing normal initialization" + ); // manage contexts for experimental features function updateFeatureContexts() {