Drag and drop support for sql projects tree (#21956)

* Drag and drop working

* update comment

* move to projectController

* remove registerTreeDataProvider

* add tests

* fix dragging to project root

* cleanup

* addressing comments
This commit is contained in:
Kim Santiago
2023-02-21 15:45:25 -08:00
committed by GitHub
parent effdf4f538
commit a7f68ebd33
8 changed files with 260 additions and 7 deletions

View File

@@ -21,6 +21,8 @@ export const noPreviousData = (tableName: string): string => { return localize('
export const gitCloneMessage = (url: string): string => { return localize('gitCloneMessage', "Cloning git repository '{0}'...", url); };
export const gitCloneError = localize('gitCloneError', "Error during git clone. View git output for more details");
export const openedProjectsUndefinedAfterRefresh = localize('openedProjectsUndefinedAfterRefresh', "List of opened projects should not be undefined after refresh from disk.");
export const dragAndDropNotSupported = localize('dragAndDropNotSupported', "This project type does not support drag and drop.");
export const onlyMovingOneFileIsSupported = localize('onlyMovingOneFileIsSupported', "Only moving one file at a time is supported.");
// UI
export const OkButtonText = localize('dataworkspace.ok', "OK");

View File

@@ -6,7 +6,7 @@
import * as vscode from 'vscode';
import * as path from 'path';
import { IWorkspaceService } from './interfaces';
import { ProjectsFailedToLoad, UnknownProjectsError } from './constants';
import { dragAndDropNotSupported, onlyMovingOneFileIsSupported, ProjectsFailedToLoad, UnknownProjectsError } from './constants';
import { WorkspaceTreeItem } from 'dataworkspace';
import { TelemetryReporter } from './telemetry';
import Logger from './logger';
@@ -14,11 +14,16 @@ import Logger from './logger';
/**
* Tree data provider for the workspace main view
*/
export class WorkspaceTreeDataProvider implements vscode.TreeDataProvider<WorkspaceTreeItem>{
export class WorkspaceTreeDataProvider implements vscode.TreeDataProvider<WorkspaceTreeItem>, vscode.TreeDragAndDropController<WorkspaceTreeItem> {
dropMimeTypes = ['application/vnd.code.tree.WorkspaceTreeDataProvider'];
dragMimeTypes = []; // The recommended mime type of the tree (`application/vnd.code.tree.WorkspaceTreeDataProvider`) is automatically added.
constructor(private _workspaceService: IWorkspaceService) {
this._workspaceService.onDidWorkspaceProjectsChange(() => {
return this.refresh();
});
vscode.window.createTreeView('dataworkspace.views.main', { canSelectMany: false, treeDataProvider: this, dragAndDropController: this });
}
private _onDidChangeTreeData: vscode.EventEmitter<void | WorkspaceTreeItem | null | undefined> | undefined = new vscode.EventEmitter<WorkspaceTreeItem | undefined | void>();
@@ -108,4 +113,42 @@ export class WorkspaceTreeDataProvider implements vscode.TreeDataProvider<Worksp
typeMetric[ext]++;
}
handleDrag(treeItems: readonly WorkspaceTreeItem[], dataTransfer: vscode.DataTransfer): void | Thenable<void> {
dataTransfer.set('application/vnd.code.tree.WorkspaceTreeDataProvider', new vscode.DataTransferItem(treeItems.map(t => t.element)));
}
async handleDrop(target: WorkspaceTreeItem | undefined, sources: vscode.DataTransfer): Promise<void> {
if (!target) {
return;
}
const transferItem = sources.get('application/vnd.code.tree.WorkspaceTreeDataProvider');
// Only support moving one file at a time
// canSelectMany is set to false for the WorkspaceTreeDataProvider, so this condition should never be true
if (transferItem?.value.length > 1) {
void vscode.window.showErrorMessage(onlyMovingOneFileIsSupported);
return;
}
const projectUri = transferItem?.value[0].projectFileUri;
if (!projectUri) {
return;
}
const projectProvider = await this._workspaceService.getProjectProvider(projectUri);
if (!projectProvider) {
return;
}
if (!projectProvider?.supportsDragAndDrop || !projectProvider.moveFile) {
void vscode.window.showErrorMessage(dragAndDropNotSupported);
return;
}
// Move the file
await projectProvider!.moveFile(projectUri, transferItem?.value[0], target);
void this.refresh();
}
}

View File

@@ -121,6 +121,19 @@ declare module 'dataworkspace' {
* Gets the project image to be used as background in dashboard container
*/
readonly image?: azdata.ThemedIconPath;
/**
* Whether or not the tree data provider supports drag and drop
*/
readonly supportsDragAndDrop?: boolean;
/**
* Moves a file from the source to target location. Must be implemented if supportsDragAndDrop is true
* @param projectUri
* @param source
* @param target
*/
moveFile?(projectUri: vscode.Uri, source: any, target: WorkspaceTreeItem): Promise<void>;
}
/**

View File

@@ -42,10 +42,6 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
const dataWorkspaceExtension = new DataWorkspaceExtension(workspaceService);
Logger.log(`DataWorkspaceExtension constructor took ${new Date().getTime() - dataWorkspaceExtensionStartTime}ms`);
const registerTreeDataProvidertartTime = new Date().getTime();
context.subscriptions.push(vscode.window.registerTreeDataProvider('dataworkspace.views.main', workspaceTreeDataProvider));
Logger.log(`registerTreeDataProvider took ${new Date().getTime() - registerTreeDataProvidertartTime}ms`);
const settingProjectProviderContextStartTime = new Date().getTime();
context.subscriptions.push(vscode.extensions.onDidChange(() => {
setProjectProviderContextValue(workspaceService);
@@ -91,7 +87,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
}));
context.subscriptions.push(vscode.commands.registerCommand('projects.removeProject', async (treeItem: WorkspaceTreeItem) => {
await workspaceService.removeProject(vscode.Uri.file(treeItem.element.project.projectFilePath));
await workspaceService.removeProject(treeItem.element.projectFileUri);
}));
context.subscriptions.push(vscode.commands.registerCommand('projects.manageProject', async (treeItem: WorkspaceTreeItem) => {