Files
azuredatastudio/src/sql/workbench/contrib/charts/browser/actions.ts
2019-11-14 12:23:11 -08:00

197 lines
6.4 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IInsight } from 'sql/workbench/contrib/charts/browser/interfaces';
import { Graph } from 'sql/workbench/contrib/charts/browser/graphInsight';
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
import { localize } from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { URI } from 'vs/base/common/uri';
import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { QueryInput } from 'sql/workbench/contrib/query/common/queryInput';
import { IInsightsConfig } from 'sql/platform/dashboard/browser/insightRegistry';
import { IInsightOptions } from 'sql/workbench/contrib/charts/common/interfaces';
import { IFileService } from 'vs/platform/files/common/files';
import { IFileDialogService, FileFilter } from 'vs/platform/dialogs/common/dialogs';
import { VSBuffer } from 'vs/base/common/buffer';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { assign } from 'vs/base/common/objects';
export interface IChartActionContext {
options: IInsightOptions;
insight: IInsight;
}
export class CreateInsightAction extends Action {
public static ID = 'chartview.createInsight';
public static LABEL = localize('createInsightLabel', "Create Insight");
public static ICON = 'createInsight';
constructor(
@IEditorService private editorService: IEditorService,
@INotificationService private notificationService: INotificationService,
@IUntitledEditorService private untitledEditorService: IUntitledEditorService
) {
super(CreateInsightAction.ID, CreateInsightAction.LABEL, CreateInsightAction.ICON);
}
public run(context: IChartActionContext): Promise<boolean> {
let uriString: string = this.getActiveUriString();
if (!uriString) {
this.showError(localize('createInsightNoEditor', "Cannot create insight as the active editor is not a SQL Editor"));
return Promise.resolve(false);
}
let uri: URI = URI.parse(uriString);
let queryFile: string = uri.fsPath;
let query: string = undefined;
let type = {};
let options = assign({}, context.options);
delete options.type;
type[context.options.type] = options;
// create JSON
let config: IInsightsConfig = {
type,
query,
queryFile
};
let widgetConfig = {
name: localize('myWidgetName', "My-Widget"),
gridItemConfig: {
sizex: 2,
sizey: 1
},
widget: {
'insights-widget': config
}
};
let input = this.untitledEditorService.createOrGet(undefined, 'json', JSON.stringify(widgetConfig));
return this.editorService.openEditor(input, { pinned: true })
.then(
() => true,
error => {
this.notificationService.notify({
severity: Severity.Error,
message: error
});
return false;
}
);
}
private getActiveUriString(): string {
let editor = this.editorService.activeEditor;
if (editor instanceof QueryInput) {
return editor.uri;
}
return undefined;
}
private showError(errorMsg: string) {
this.notificationService.notify({
severity: Severity.Error,
message: errorMsg
});
}
}
export class CopyAction extends Action {
public static ID = 'chartview.copy';
public static LABEL = localize('copyChartLabel', "Copy as image");
public static ICON = 'copyImage';
constructor(
@IClipboardService private clipboardService: IClipboardService,
@INotificationService private notificationService: INotificationService
) {
super(CopyAction.ID, CopyAction.LABEL, CopyAction.ICON);
}
public run(context: IChartActionContext): Promise<boolean> {
if (context.insight instanceof Graph) {
let data = context.insight.getCanvasData();
if (!data) {
this.showError(localize('chartNotFound', "Could not find chart to save"));
return Promise.resolve(false);
}
this.clipboardService.writeImageDataUrl(data);
return Promise.resolve(true);
}
return Promise.resolve(false);
}
private showError(errorMsg: string) {
this.notificationService.notify({
severity: Severity.Error,
message: errorMsg
});
}
}
export class SaveImageAction extends Action {
public static ID = 'chartview.saveImage';
public static LABEL = localize('saveImageLabel', "Save as image");
public static ICON = 'saveAsImage';
constructor(
@INotificationService private readonly notificationService: INotificationService,
@IFileService private readonly fileService: IFileService,
@IFileDialogService private readonly fileDialogService: IFileDialogService,
@IOpenerService private readonly openerService: IOpenerService
) {
super(SaveImageAction.ID, SaveImageAction.LABEL, SaveImageAction.ICON);
}
public async run(context: IChartActionContext): Promise<boolean> {
if (context.insight instanceof Graph) {
let fileFilters = new Array<FileFilter>({ extensions: ['png'], name: localize('resultsSerializer.saveAsFileExtensionPNGTitle', "PNG") });
const filePath = await this.fileDialogService.pickFileToSave({ filters: fileFilters });
const data = (<Graph>context.insight).getCanvasData();
if (!data) {
this.notificationService.error(localize('chartNotFound', "Could not find chart to save"));
return false;
}
if (filePath) {
let buffer = this.decodeBase64Image(data);
try {
await this.fileService.writeFile(filePath, buffer);
} catch (err) {
if (err) {
this.notificationService.error(err.message);
} else {
this.openerService.open(filePath, { openExternal: true });
this.notificationService.notify({
severity: Severity.Error,
message: localize('chartSaved', "Saved Chart to path: {0}", filePath.toString())
});
}
}
}
return true;
}
return Promise.resolve(false);
}
private decodeBase64Image(data: string): VSBuffer {
const marker = ';base64,';
const raw = atob(data.substring(data.indexOf(marker) + marker.length));
const n = raw.length;
const a = new Uint8Array(new ArrayBuffer(n));
for (let i = 0; i < n; i++) {
a[i] = raw.charCodeAt(i);
}
return VSBuffer.wrap(a);
}
}