diff --git a/CHANGELOG.md b/CHANGELOG.md index 08a728c..13a1aad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,15 @@ # Release Notes +**v2.5.0:** +- added a new config setting `databricks.workspace.root` to set the root from where the [Workspace Manager](README.md/#workspace-manager) starts ([205](/../../issues/205)) +- fixed issues where refresh of treeviews was not working properly + **v2.4.2:** -- fix issues with widgets. Support for Spark-connect clusters and Scala -- fix issue with driverpath that is when using the notebook experience +- fixed issues with widgets. Support for Spark-connect clusters and Scala +- fixed issue with driverpath that is when using the notebook experience **v2.4.1:** -- fix issue with notebook serialization not working properly for markdown +- fixed issue with notebook serialization not working properly for markdown **v2.4.0:** - added interactive kernel again ([202](/../../issues/202)) diff --git a/package.json b/package.json index 05ff843..bb6e2c3 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "databricks-vscode", "displayName": "Databricks Power Tools", "description": "Run notebooks cell-by-cell, browse and edit your Databricks Workspace, DBFS, Clusters, Jobs, Secrets, Repos and SQL. Supports Azure Databricks, Databricks on AWS and Databricks on GCP.", - "version": "2.4.2", + "version": "2.5.0", "publisher": "paiqo", "icon": "resources/databricks_extension.png", "author": { @@ -402,6 +402,12 @@ }, "description": "An Azure Resource ID (GUID)." } + }, + "databricks.workspace.root": { + "type": "string", + "markdownDescription": "(Optional) The root path when browsing the Databricks Workspace. If not specified, the root path is the root of the workspace.", + "scope": "window", + "default": "/" } } } diff --git a/src/ThisExtension.ts b/src/ThisExtension.ts index cf9c473..2cd2710 100644 --- a/src/ThisExtension.ts +++ b/src/ThisExtension.ts @@ -214,6 +214,12 @@ export abstract class ThisExtension { return this._sqlClusterId; } + static get WorkspaceRootPath(): string { + const workspaceRootFolder = ThisExtension.getConfigurationSetting("databricks.workspace.root", ThisExtension.SettingScope, true).value; + + return workspaceRootFolder; + } + static set SQLClusterID(value: string) { if (value != undefined) { ThisExtension.log(`Using cluster with id '${value}' for SQL Browser!`); diff --git a/src/extension.ts b/src/extension.ts index 0422f59..740cac7 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -79,7 +79,16 @@ export async function activate(context: vscode.ExtensionContext) { } vscode.commands.registerCommand('databricksConnectionItem.activate', (connection: DatabricksConnectionTreeItem) => connection.activate()); - // register DatabricksWorkspaceTreeProvider + // register DatabricksWorkspaceTreeProvider and FileSystemProvider + // Workspace File System Provider + const workspaceFsProvider = new DatabricksWorkspaceProvider(context); + vscode.commands.registerCommand('databricksWorkspace.addToWorkspace', (showMessage: boolean) => { + FSHelper.addToWorkspace( + vscode.Uri.parse(ThisExtension.WORKSPACE_SCHEME + ':' + ThisExtension.WorkspaceRootPath), + "Databricks - Workspace - " + ThisExtension.WorkspaceRootPath, + showMessage); + }); + if (!ThisExtension.isInBrowser) { let databricksWorkspaceTreeProvider = new DatabricksWorkspaceTreeProvider(context); //vscode.window.registerTreeDataProvider('databricksWorkspace', databricksWorkspaceTreeProvider); @@ -95,13 +104,7 @@ export async function activate(context: vscode.ExtensionContext) { vscode.commands.registerCommand('databricksWorkspaceItem.openExplorer', (workspaceItem: DatabricksWorkspaceTreeItem) => workspaceItem.openExplorer()); vscode.commands.registerCommand('databricksWorkspaceItem.delete', (workspaceItem: DatabricksWorkspaceNotebook | DatabricksWorkspaceDirectory) => workspaceItem.delete()); } - // Workspace File System Provider - const workspaceProvider = new DatabricksWorkspaceProvider(context); - vscode.commands.registerCommand('databricksWorkspace.addToWorkspace', (showMessage: boolean) => { - FSHelper.addToWorkspace(vscode.Uri.parse(ThisExtension.WORKSPACE_SCHEME + ':/'), "Databricks - Workspace", showMessage); - }); - - if (ThisExtension.isInBrowser) { + else { // in a virtual workspace we always want to add the WSFS/DBWS mount to the workspace vscode.commands.executeCommand('databricksWorkspace.addToWorkspace', false); } diff --git a/src/vscode/treeviews/dbfs/DatabricksFSTreeProvider.ts b/src/vscode/treeviews/dbfs/DatabricksFSTreeProvider.ts index c7c47e3..407db58 100644 --- a/src/vscode/treeviews/dbfs/DatabricksFSTreeProvider.ts +++ b/src/vscode/treeviews/dbfs/DatabricksFSTreeProvider.ts @@ -40,10 +40,21 @@ export class DatabricksFSTreeProvider implements vscode.TreeDataProvider { } async refresh(showInfoMessage: boolean = false, item: DatabricksFSTreeItem = null): Promise { - if(showInfoMessage){ - Helper.showTemporaryInformationMessage('Refreshing DBFS ...'); - } - this._onDidChangeTreeData.fire(item); + // as tree_item is not always accurate, we refresh based on the actual selection + if (this._treeView.selection.length == 0) { + this._onDidChangeTreeData.fire(undefined); + return; + } + if (showInfoMessage) { + Helper.showTemporaryInformationMessage('Refreshing DBFS ...'); + } + for (let item of this._treeView.selection) { + // on leaves, we refresh the parent instead + if (item && item.collapsibleState == vscode.TreeItemCollapsibleState.None) { + item = item.parent; + } + this._onDidChangeTreeData.fire(item); + } } async getTreeItem(element: DatabricksFSTreeItem): Promise { diff --git a/src/vscode/treeviews/workspaces/DatabricksWorkspaceDirectory.ts b/src/vscode/treeviews/workspaces/DatabricksWorkspaceDirectory.ts index 8f1995e..f171c4d 100644 --- a/src/vscode/treeviews/workspaces/DatabricksWorkspaceDirectory.ts +++ b/src/vscode/treeviews/workspaces/DatabricksWorkspaceDirectory.ts @@ -34,10 +34,10 @@ export class DatabricksWorkspaceDirectory extends DatabricksWorkspaceTreeItem { // we can only run initialize for this class after all values had been set in the constructor // but we must not run it as part of the call to super() if (this._isInitialized) { - super.label = this.path.split('/').pop(); - super.tooltip = this._tooltip; - super.contextValue = this._contextValue; - super.iconPath = { + this.label = this.path.split('/').pop(); + this.tooltip = this._tooltip; + this.contextValue = this._contextValue; + this.iconPath = { light: this.getIconPath("light"), dark: this.getIconPath("dark") }; @@ -124,7 +124,7 @@ export class DatabricksWorkspaceDirectory extends DatabricksWorkspaceTreeItem { if(!this.localPathExists) { // check again for the local path as it might have been created since this Directory object was created - let localPathProbe: vscode.Uri = await FSHelper.joinPath(ThisExtension.ActiveConnection.localSyncFolder, ThisExtension.ConnectionManager.SubfolderConfiguration().Workspace, this.path); + let localPathProbe: vscode.Uri = await FSHelper.joinPath(ThisExtension.ActiveConnection.localSyncFolder, ThisExtension.ConnectionManager.SubfolderConfiguration().Workspace, this.pathRelativeToWorkspaceRoot); if(await FSHelper.pathExists(localPathProbe)) { this.localPath = localPathProbe; @@ -202,7 +202,7 @@ export class DatabricksWorkspaceDirectory extends DatabricksWorkspaceTreeItem { async download(refreshParent: boolean = true): Promise { if(!this.localPath) // if we try to download a subfolder of a folder that has not yet been synced this.localPath is not populated! { - this.localPath = vscode.Uri.joinPath(ThisExtension.ActiveConnection.localSyncFolder, ThisExtension.ConnectionManager.SubfolderConfiguration().Workspace, this.path); + this.localPath = vscode.Uri.joinPath(ThisExtension.ActiveConnection.localSyncFolder, ThisExtension.ConnectionManager.SubfolderConfiguration().Workspace, this.pathRelativeToWorkspaceRoot); } FSHelper.ensureFolder(this.localPath); let items: DatabricksWorkspaceTreeItem[] = await this.getChildren() as DatabricksWorkspaceTreeItem[]; diff --git a/src/vscode/treeviews/workspaces/DatabricksWorkspaceFile.ts b/src/vscode/treeviews/workspaces/DatabricksWorkspaceFile.ts index aba1253..463d0bf 100644 --- a/src/vscode/treeviews/workspaces/DatabricksWorkspaceFile.ts +++ b/src/vscode/treeviews/workspaces/DatabricksWorkspaceFile.ts @@ -31,15 +31,15 @@ export class DatabricksWorkspaceFile extends DatabricksWorkspaceTreeItem { // but we must not run it as part of the call to super() if(this._isInitialized) { - super.label = this.path.split('/').pop(); - super.tooltip = this._tooltip; - super.description = this._description; - super.contextValue = this._contextValue; - super.iconPath = { + this.label = this.path.split('/').pop(); + this.tooltip = this._tooltip; + this.description = this._description; + this.contextValue = this._contextValue; + this.iconPath = { light: this.getIconPath("light"), dark: this.getIconPath("dark") }; - super.command = this._command; + this.command = this._command; } } @@ -106,7 +106,7 @@ export class DatabricksWorkspaceFile extends DatabricksWorkspaceTreeItem { }; get localFolderPath(): vscode.Uri { - return FSHelper.parent(FSHelper.joinPathSync(ThisExtension.ActiveConnection.localSyncFolder, ThisExtension.ConnectionManager.SubfolderConfiguration().Workspace, this.path)); + return FSHelper.parent(FSHelper.joinPathSync(ThisExtension.ActiveConnection.localSyncFolder, ThisExtension.ConnectionManager.SubfolderConfiguration().Workspace, this.pathRelativeToWorkspaceRoot)); } public static fromInterface(item: iDatabricksWorkspaceItem, parent: DatabricksWorkspaceTreeItem = null): DatabricksWorkspaceFile { diff --git a/src/vscode/treeviews/workspaces/DatabricksWorkspaceLibrary.ts b/src/vscode/treeviews/workspaces/DatabricksWorkspaceLibrary.ts index 9818c50..bb15877 100644 --- a/src/vscode/treeviews/workspaces/DatabricksWorkspaceLibrary.ts +++ b/src/vscode/treeviews/workspaces/DatabricksWorkspaceLibrary.ts @@ -15,7 +15,7 @@ export class DatabricksWorkspaceLibrary extends DatabricksWorkspaceTreeItem { ) { super(path, "LIBRARY", object_id, parent, undefined, vscode.TreeItemCollapsibleState.None); - super.tooltip = this._tooltip; + this.tooltip = this._tooltip; } get _tooltip(): string { diff --git a/src/vscode/treeviews/workspaces/DatabricksWorkspaceNotebook.ts b/src/vscode/treeviews/workspaces/DatabricksWorkspaceNotebook.ts index 9aab4cc..0020345 100644 --- a/src/vscode/treeviews/workspaces/DatabricksWorkspaceNotebook.ts +++ b/src/vscode/treeviews/workspaces/DatabricksWorkspaceNotebook.ts @@ -46,15 +46,15 @@ export class DatabricksWorkspaceNotebook extends DatabricksWorkspaceTreeItem { // but we must not run it as part of the call to super() if(this._isInitialized) { - super.label = this.path.split('/').pop(); - super.tooltip = this._tooltip; - super.description = this._description; - super.contextValue = this._contextValue; - super.iconPath = { + this.label = this.path.split('/').pop(); + this.tooltip = this._tooltip; + this.description = this._description; + this.contextValue = this._contextValue; + this.iconPath = { light: this.getIconPath("light"), dark: this.getIconPath("dark") }; - super.command = this._command; + this.command = this._command; } } @@ -139,7 +139,7 @@ export class DatabricksWorkspaceNotebook extends DatabricksWorkspaceTreeItem { }; get localFolderPath(): vscode.Uri { - return FSHelper.parent(FSHelper.joinPathSync(ThisExtension.ActiveConnection.localSyncFolder, ThisExtension.ConnectionManager.SubfolderConfiguration().Workspace, this.path)); + return FSHelper.parent(FSHelper.joinPathSync(ThisExtension.ActiveConnection.localSyncFolder, ThisExtension.ConnectionManager.SubfolderConfiguration().Workspace, this.pathRelativeToWorkspaceRoot)); } get localFileExtension(): string { diff --git a/src/vscode/treeviews/workspaces/DatabricksWorkspaceTreeItem.ts b/src/vscode/treeviews/workspaces/DatabricksWorkspaceTreeItem.ts index 44eaa9f..5b5fdd8 100644 --- a/src/vscode/treeviews/workspaces/DatabricksWorkspaceTreeItem.ts +++ b/src/vscode/treeviews/workspaces/DatabricksWorkspaceTreeItem.ts @@ -91,6 +91,10 @@ export class DatabricksWorkspaceTreeItem extends vscode.TreeItem implements iDat return DatabricksWorkspaceTreeItem.fromInterface(item, parent); } + get pathRelativeToWorkspaceRoot(): string { + return this.path.substring(ThisExtension.WorkspaceRootPath.length); + } + get localPath(): vscode.Uri { return this._localPath; } diff --git a/src/vscode/treeviews/workspaces/DatabricksWorkspaceTreeProvider.ts b/src/vscode/treeviews/workspaces/DatabricksWorkspaceTreeProvider.ts index 09508e5..32a700e 100644 --- a/src/vscode/treeviews/workspaces/DatabricksWorkspaceTreeProvider.ts +++ b/src/vscode/treeviews/workspaces/DatabricksWorkspaceTreeProvider.ts @@ -14,6 +14,7 @@ export class DatabricksWorkspaceTreeProvider implements vscode.TreeDataProvider< readonly onDidChangeTreeData: vscode.Event = this._onDidChangeTreeData.event; private _treeView: vscode.TreeView; + private _rootPath: string; constructor(context: vscode.ExtensionContext) { const treeView = vscode.window.createTreeView('databricksWorkspace', { @@ -42,11 +43,21 @@ export class DatabricksWorkspaceTreeProvider implements vscode.TreeDataProvider< private async _onDidChangeVisibility(visible: boolean): Promise { } async refresh(item: DatabricksWorkspaceTreeItem = null, showInfoMessage: boolean = false): Promise { + // as tree_item is not always accurate, we refresh based on the actual selection + if (this._treeView.selection.length == 0) { + this._onDidChangeTreeData.fire(undefined); + return; + } if (showInfoMessage) { Helper.showTemporaryInformationMessage('Refreshing Workspace ...'); } - - this._onDidChangeTreeData.fire(item); + for (let item of this._treeView.selection) { + // on leaves, we refresh the parent instead + if (item && item.collapsibleState == vscode.TreeItemCollapsibleState.None) { + item = item.parent; + } + this._onDidChangeTreeData.fire(item); + } } async getTreeItem(element: DatabricksWorkspaceTreeItem): Promise { @@ -62,6 +73,8 @@ export class DatabricksWorkspaceTreeProvider implements vscode.TreeDataProvider< return Promise.resolve([]); } + this._rootPath = ThisExtension.WorkspaceRootPath; + if (element != null && element != undefined) { return element.getChildren(); } @@ -73,15 +86,19 @@ export class DatabricksWorkspaceTreeProvider implements vscode.TreeDataProvider< FSHelper.ensureFolder(workspaceRootFolder); } - return new DatabricksWorkspaceDirectory("/", 0, workspaceRootFolder).getChildren(); + return new DatabricksWorkspaceDirectory(this._rootPath, 0, workspaceRootFolder).getChildren(); } } + public get rootPath(): string { + return this._rootPath; + } + async download(): Promise { - await new DatabricksWorkspaceDirectory("/", 0).download(); + await new DatabricksWorkspaceDirectory(this._rootPath, 0).download(); } async upload(): Promise { - await new DatabricksWorkspaceDirectory("/", 0).upload(); + await new DatabricksWorkspaceDirectory(this._rootPath, 0).upload(); } }