Feature/html config (#231)
* added select all event to context menu; added events for save as and select all * added shortcuts to context menu when present * fixed build errors * fixed select all * added refresh (#195) * fixed null values in grid (#218) * added config
This commit is contained in:
Родитель
d1624968a9
Коммит
7760ed16db
20
package.json
20
package.json
|
@ -359,6 +359,26 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"mssql.shortcuts": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Shortcuts related to the results window",
|
||||||
|
"default": {
|
||||||
|
"_comment": "Short cuts must follow the format (ctrl)+(shift)+(alt)+[key]",
|
||||||
|
"event.toggleResultPane": "ctrl+alt+r",
|
||||||
|
"event.toggleMessagePane": "ctrl+alt+y",
|
||||||
|
"event.prevGrid": "ctrl+up",
|
||||||
|
"event.nextGrid": "ctrl+down",
|
||||||
|
"event.copySelection": "ctrl+c",
|
||||||
|
"event.toggleMagnify": "",
|
||||||
|
"event.selectAll": "",
|
||||||
|
"event.saveAsJSON": "",
|
||||||
|
"event.saveAsCSV": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"mssql.messagesDefaultOpen": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "true for the messages pane to be open by default; false for closed"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,11 @@ class QueryRunnerState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ResultsConfig implements Interfaces.IResultsConfig {
|
||||||
|
shortcuts: { [key: string]: string };
|
||||||
|
messagesDefaultOpen: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export class SqlOutputContentProvider implements vscode.TextDocumentContentProvider {
|
export class SqlOutputContentProvider implements vscode.TextDocumentContentProvider {
|
||||||
// CONSTANTS ///////////////////////////////////////////////////////////
|
// CONSTANTS ///////////////////////////////////////////////////////////
|
||||||
public static providerName = 'tsqloutput';
|
public static providerName = 'tsqloutput';
|
||||||
|
@ -46,7 +51,7 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
|
||||||
this._service = new LocalWebService(context.extensionPath);
|
this._service = new LocalWebService(context.extensionPath);
|
||||||
|
|
||||||
// add http handler for '/root'
|
// add http handler for '/root'
|
||||||
this._service.addHandler(Interfaces.ContentType.Root, function(req, res): void {
|
this._service.addHandler(Interfaces.ContentType.Root, (req, res): void => {
|
||||||
let uri: string = req.query.uri;
|
let uri: string = req.query.uri;
|
||||||
if (self._queryResultsMap.has(uri)) {
|
if (self._queryResultsMap.has(uri)) {
|
||||||
clearTimeout(self._queryResultsMap.get(uri).timeout);
|
clearTimeout(self._queryResultsMap.get(uri).timeout);
|
||||||
|
@ -71,7 +76,7 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
|
||||||
});
|
});
|
||||||
|
|
||||||
// add http handler for '/resultsetsMeta' - return metadata about columns & rows in multiple resultsets
|
// add http handler for '/resultsetsMeta' - return metadata about columns & rows in multiple resultsets
|
||||||
this._service.addHandler(Interfaces.ContentType.ResultsetsMeta, function(req, res): void {
|
this._service.addHandler(Interfaces.ContentType.ResultsetsMeta, (req, res): void => {
|
||||||
let tempBatchSets: Interfaces.IGridBatchMetaData[] = [];
|
let tempBatchSets: Interfaces.IGridBatchMetaData[] = [];
|
||||||
let uri: string = req.query.uri;
|
let uri: string = req.query.uri;
|
||||||
if (self._queryResultsMap.has(uri)) {
|
if (self._queryResultsMap.has(uri)) {
|
||||||
|
@ -122,7 +127,7 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
|
||||||
});
|
});
|
||||||
|
|
||||||
// add http handler for '/columns' - return column metadata as a JSON string
|
// add http handler for '/columns' - return column metadata as a JSON string
|
||||||
this._service.addHandler(Interfaces.ContentType.Columns, function(req, res): void {
|
this._service.addHandler(Interfaces.ContentType.Columns, (req, res): void => {
|
||||||
let resultId = req.query.resultId;
|
let resultId = req.query.resultId;
|
||||||
let batchId = req.query.batchId;
|
let batchId = req.query.batchId;
|
||||||
let uri: string = req.query.uri;
|
let uri: string = req.query.uri;
|
||||||
|
@ -134,7 +139,7 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
|
||||||
});
|
});
|
||||||
|
|
||||||
// add http handler for '/rows' - return rows end-point for a specific resultset
|
// add http handler for '/rows' - return rows end-point for a specific resultset
|
||||||
this._service.addHandler(Interfaces.ContentType.Rows, function(req, res): void {
|
this._service.addHandler(Interfaces.ContentType.Rows, (req, res): void => {
|
||||||
let resultId = req.query.resultId;
|
let resultId = req.query.resultId;
|
||||||
let batchId = req.query.batchId;
|
let batchId = req.query.batchId;
|
||||||
let rowStart = req.query.rowStart;
|
let rowStart = req.query.rowStart;
|
||||||
|
@ -146,8 +151,18 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this._service.addHandler(Interfaces.ContentType.Config, (req, res): void => {
|
||||||
|
let extConfig = this._vscodeWrapper.getConfiguration(Constants.extensionConfigSectionName);
|
||||||
|
let config = new ResultsConfig();
|
||||||
|
for (let key of Constants.extConfigResultKeys) {
|
||||||
|
config[key] = extConfig[key];
|
||||||
|
}
|
||||||
|
let json = JSON.stringify(config);
|
||||||
|
res.send(json);
|
||||||
|
});
|
||||||
|
|
||||||
// add http handler for '/saveResults' - return success message as JSON
|
// add http handler for '/saveResults' - return success message as JSON
|
||||||
this._service.addPostHandler(Interfaces.ContentType.SaveResults, function(req, res): void {
|
this._service.addPostHandler(Interfaces.ContentType.SaveResults, (req, res): void => {
|
||||||
let uri: string = req.query.uri;
|
let uri: string = req.query.uri;
|
||||||
let queryUri = self._queryResultsMap.get(uri).queryRunner.uri;
|
let queryUri = self._queryResultsMap.get(uri).queryRunner.uri;
|
||||||
let selectedResultSetNo: number = Number(req.query.resultSetNo);
|
let selectedResultSetNo: number = Number(req.query.resultSetNo);
|
||||||
|
@ -161,7 +176,7 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
|
||||||
});
|
});
|
||||||
|
|
||||||
// add http handler for '/openLink' - open content in a new vscode editor pane
|
// add http handler for '/openLink' - open content in a new vscode editor pane
|
||||||
this._service.addPostHandler(Interfaces.ContentType.OpenLink, function(req, res): void {
|
this._service.addPostHandler(Interfaces.ContentType.OpenLink, (req, res): void => {
|
||||||
let content: string = req.body.content;
|
let content: string = req.body.content;
|
||||||
let columnName: string = req.body.columnName;
|
let columnName: string = req.body.columnName;
|
||||||
let linkType: string = req.body.type;
|
let linkType: string = req.body.type;
|
||||||
|
@ -171,7 +186,7 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
|
||||||
});
|
});
|
||||||
|
|
||||||
// add http post handler for copying results
|
// add http post handler for copying results
|
||||||
this._service.addPostHandler(Interfaces.ContentType.Copy, function(req, res): void {
|
this._service.addPostHandler(Interfaces.ContentType.Copy, (req, res): void => {
|
||||||
let uri = req.query.uri;
|
let uri = req.query.uri;
|
||||||
let resultId = req.query.resultId;
|
let resultId = req.query.resultId;
|
||||||
let batchId = req.query.batchId;
|
let batchId = req.query.batchId;
|
||||||
|
@ -183,7 +198,7 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
|
||||||
});
|
});
|
||||||
|
|
||||||
// add http post handler for setting the selection in the editor
|
// add http post handler for setting the selection in the editor
|
||||||
this._service.addPostHandler(Interfaces.ContentType.EditorSelection, function(req, res): void {
|
this._service.addPostHandler(Interfaces.ContentType.EditorSelection, (req, res): void => {
|
||||||
let uri = req.query.uri;
|
let uri = req.query.uri;
|
||||||
let selection: ISelectionData = req.body;
|
let selection: ISelectionData = req.body;
|
||||||
self._queryResultsMap.get(uri).queryRunner.setEditorSelection(selection).then(() => {
|
self._queryResultsMap.get(uri).queryRunner.setEditorSelection(selection).then(() => {
|
||||||
|
@ -193,7 +208,7 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
|
||||||
});
|
});
|
||||||
|
|
||||||
// add http post handler for showing errors to user
|
// add http post handler for showing errors to user
|
||||||
this._service.addPostHandler(Interfaces.ContentType.ShowError, function(req, res): void {
|
this._service.addPostHandler(Interfaces.ContentType.ShowError, (req, res): void => {
|
||||||
let message: string = req.body.message;
|
let message: string = req.body.message;
|
||||||
self._vscodeWrapper.showErrorMessage(message);
|
self._vscodeWrapper.showErrorMessage(message);
|
||||||
// not attached to show function callback, since callback returns only after user closes message
|
// not attached to show function callback, since callback returns only after user closes message
|
||||||
|
@ -202,7 +217,7 @@ export class SqlOutputContentProvider implements vscode.TextDocumentContentProvi
|
||||||
});
|
});
|
||||||
|
|
||||||
// add http post handler for showing warning to user
|
// add http post handler for showing warning to user
|
||||||
this._service.addPostHandler(Interfaces.ContentType.ShowWarning, function(req, res): void {
|
this._service.addPostHandler(Interfaces.ContentType.ShowWarning, (req, res): void => {
|
||||||
let message: string = req.body.message;
|
let message: string = req.body.message;
|
||||||
self._vscodeWrapper.showWarningMessage(message);
|
self._vscodeWrapper.showWarningMessage(message);
|
||||||
// not attached to show function callback, since callback returns only after user closes message
|
// not attached to show function callback, since callback returns only after user closes message
|
||||||
|
|
|
@ -33,6 +33,7 @@ export const outputContentTypeMessages = 'messages';
|
||||||
export const outputContentTypeResultsetMeta = 'resultsetsMeta';
|
export const outputContentTypeResultsetMeta = 'resultsetsMeta';
|
||||||
export const outputContentTypeColumns = 'columns';
|
export const outputContentTypeColumns = 'columns';
|
||||||
export const outputContentTypeRows = 'rows';
|
export const outputContentTypeRows = 'rows';
|
||||||
|
export const outputContentTypeConfig = 'config';
|
||||||
export const outputContentTypeSaveResults = 'saveResults';
|
export const outputContentTypeSaveResults = 'saveResults';
|
||||||
export const outputContentTypeOpenLink = 'openLink';
|
export const outputContentTypeOpenLink = 'openLink';
|
||||||
export const outputContentTypeCopy = 'copyResults';
|
export const outputContentTypeCopy = 'copyResults';
|
||||||
|
@ -208,6 +209,8 @@ export const sqlToolsServiceExecutableFilesConfigKey = 'executableFiles';
|
||||||
export const sqlToolsServiceVersionConfigKey = 'version';
|
export const sqlToolsServiceVersionConfigKey = 'version';
|
||||||
export const sqlToolsServiceDownloadUrlConfigKey = 'downloadUrl';
|
export const sqlToolsServiceDownloadUrlConfigKey = 'downloadUrl';
|
||||||
|
|
||||||
|
export const extConfigResultKeys = ['shortcuts', 'messagesDefaultOpen'];
|
||||||
|
|
||||||
export const titleResultsPane = 'Results: {0}';
|
export const titleResultsPane = 'Results: {0}';
|
||||||
|
|
||||||
export const macOpenSslErrorMessage = `OpenSSL version >=1.0.1 is required to connect.`;
|
export const macOpenSslErrorMessage = `OpenSSL version >=1.0.1 is required to connect.`;
|
||||||
|
|
|
@ -14,7 +14,8 @@ export enum ContentType {
|
||||||
EditorSelection = 7,
|
EditorSelection = 7,
|
||||||
OpenLink = 8,
|
OpenLink = 8,
|
||||||
ShowError = 9,
|
ShowError = 9,
|
||||||
ShowWarning = 10
|
ShowWarning = 10,
|
||||||
|
Config = 11
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface ISlickRange {
|
export interface ISlickRange {
|
||||||
|
@ -41,7 +42,8 @@ export const ContentTypes = [
|
||||||
Constants.outputContentTypeEditorSelection,
|
Constants.outputContentTypeEditorSelection,
|
||||||
Constants.outputContentTypeOpenLink,
|
Constants.outputContentTypeOpenLink,
|
||||||
Constants.outputContentTypeShowError,
|
Constants.outputContentTypeShowError,
|
||||||
Constants.outputContentTypeShowWarning
|
Constants.outputContentTypeShowWarning,
|
||||||
|
Constants.outputContentTypeConfig
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -264,3 +266,7 @@ export interface IGridBatchMetaData {
|
||||||
totalTime: string;
|
totalTime: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IResultsConfig {
|
||||||
|
shortcuts: { [key: string]: string };
|
||||||
|
messagesDefaultOpen: boolean;
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<div class="fullsize vertBox">
|
<div class="fullsize vertBox">
|
||||||
<div *ngIf="dataSets.length > 0" class="boxRow header collapsible" [class.collapsed]="!resultActive" (click)="resultActive = !resultActive">
|
<div *ngIf="dataSets.length > 0" class="boxRow header collapsible" [class.collapsed]="!resultActive" (click)="resultActive = !resultActive">
|
||||||
<span> {{Constants.resultPaneLabel}} </span>
|
<span> {{Constants.resultPaneLabel}} </span>
|
||||||
<span class="shortCut"> {{Utils.stringCodeFor('event.toggleResultPane')}} </span>
|
<span class="shortCut"> {{resultShortcut}} </span>
|
||||||
</div>
|
</div>
|
||||||
<div id="results" *ngIf="renderedDataSets.length > 0" class="results vertBox scrollable"
|
<div id="results" *ngIf="renderedDataSets.length > 0" class="results vertBox scrollable"
|
||||||
(onScroll)="onScroll($event)" [scrollEnabled]="scrollEnabled" [class.hidden]="!resultActive">
|
(onScroll)="onScroll($event)" [scrollEnabled]="scrollEnabled" [class.hidden]="!resultActive">
|
||||||
|
@ -34,7 +34,7 @@
|
||||||
<div class="boxRow header collapsible" [class.collapsed]="!messageActive" (click)="messageActive = !messageActive" style="position: relative">
|
<div class="boxRow header collapsible" [class.collapsed]="!messageActive" (click)="messageActive = !messageActive" style="position: relative">
|
||||||
<div id="messageResizeHandle" class="resizableHandle"></div>
|
<div id="messageResizeHandle" class="resizableHandle"></div>
|
||||||
<span> {{Constants.messagePaneLabel}} </span>
|
<span> {{Constants.messagePaneLabel}} </span>
|
||||||
<span class="shortCut"> {{Utils.stringCodeFor('event.toggleMessagePane')}} </span>
|
<span class="shortCut"> {{messageShortcut}} </span>
|
||||||
</div>
|
</div>
|
||||||
<div id="messages" class="scrollable messages" [class.hidden]="!messageActive">
|
<div id="messages" class="scrollable messages" [class.hidden]="!messageActive">
|
||||||
<br>
|
<br>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
<ul class="contextMenu" style="display:none;position:absolute">
|
<ul class="contextMenu" style="display:none;position:absolute">
|
||||||
<li id="savecsv" (click)="handleContextActionClick('savecsv')" [class.disabled]="isDisabled"> {{Constants.saveCSVLabel}}
|
<li id="savecsv" (click)="handleContextActionClick('savecsv')" [class.disabled]="isDisabled"> {{Constants.saveCSVLabel}}
|
||||||
<span style="float: right; color: lightgrey; padding-left: 10px">{{Utils.stringCodeFor('event.saveAsCSV')}}</span></li>
|
<span style="float: right; color: lightgrey; padding-left: 10px">{{keys['event.saveAsCSV']}}</span></li>
|
||||||
<li id="savejson" (click)="handleContextActionClick('savejson')" [class.disabled]="isDisabled"> {{Constants.saveJSONLabel}}
|
<li id="savejson" (click)="handleContextActionClick('savejson')" [class.disabled]="isDisabled"> {{Constants.saveJSONLabel}}
|
||||||
<span style="float: right; color: lightgrey; padding-left: 10px">{{Utils.stringCodeFor('event.saveAsJSON')}}</span></li>
|
<span style="float: right; color: lightgrey; padding-left: 10px">{{keys['event.saveAsJSON']}}</span></li>
|
||||||
<li id="selectall" (click)="handleContextActionClick('selectall')" [class.disabled]="isDisabled"> {{Constants.selectAll}}
|
<li id="selectall" (click)="handleContextActionClick('selectall')" [class.disabled]="isDisabled"> {{Constants.selectAll}}
|
||||||
<span style="float: right; color: lightgrey; padding-left: 10px">{{Utils.stringCodeFor('event.selectAll')}}</span></li>
|
<span style="float: right; color: lightgrey; padding-left: 10px">{{keys['event.selectAll']}}</span></li>
|
||||||
</ul>
|
</ul>
|
|
@ -15,6 +15,7 @@ import {VirtualizedCollection} from './../slickgrid/VirtualizedCollection';
|
||||||
import { FieldType } from './../slickgrid/EngineAPI';
|
import { FieldType } from './../slickgrid/EngineAPI';
|
||||||
|
|
||||||
import {DataService} from './../services/data.service';
|
import {DataService} from './../services/data.service';
|
||||||
|
import {ShortcutService} from './../services/shortcuts.service';
|
||||||
import { ContextMenu } from './contextmenu.component';
|
import { ContextMenu } from './contextmenu.component';
|
||||||
import { IGridIcon, IGridBatchMetaData, ISelectionData, IResultMessage } from './../interfaces';
|
import { IGridIcon, IGridBatchMetaData, ISelectionData, IResultMessage } from './../interfaces';
|
||||||
|
|
||||||
|
@ -25,17 +26,6 @@ import * as Utils from './../utils';
|
||||||
import {enableProdMode} from '@angular/core';
|
import {enableProdMode} from '@angular/core';
|
||||||
enableProdMode();
|
enableProdMode();
|
||||||
|
|
||||||
const shortcuts = {
|
|
||||||
'_comment': 'Short cuts must follow the format (ctrl)+(shift)+(alt)+(key)',
|
|
||||||
'ctrl+alt+r': 'event.toggleResultPane',
|
|
||||||
'ctrl+alt+y': 'event.toggleMessagePane',
|
|
||||||
'ctrl+up': 'event.prevGrid',
|
|
||||||
'ctrl+down': 'event.nextGrid',
|
|
||||||
'ctrl+c': 'event.copySelection',
|
|
||||||
'undefined': 'event.toggleMagnifyCurrent'
|
|
||||||
};
|
|
||||||
const keycodes = require('./../keycodes.json!');
|
|
||||||
|
|
||||||
enum SelectedTab {
|
enum SelectedTab {
|
||||||
Results = 0,
|
Results = 0,
|
||||||
Messages = 1,
|
Messages = 1,
|
||||||
|
@ -68,7 +58,7 @@ interface IMessages {
|
||||||
host: { '(window:keydown)': 'keyEvent($event)', '(window:gridnav)': 'keyEvent($event)' },
|
host: { '(window:keydown)': 'keyEvent($event)', '(window:gridnav)': 'keyEvent($event)' },
|
||||||
templateUrl: 'dist/html/app.html',
|
templateUrl: 'dist/html/app.html',
|
||||||
directives: [ContextMenu, SlickGrid],
|
directives: [ContextMenu, SlickGrid],
|
||||||
providers: [DataService],
|
providers: [DataService, ShortcutService],
|
||||||
styles: [`
|
styles: [`
|
||||||
.errorMessage {
|
.errorMessage {
|
||||||
color: var(--color-error);
|
color: var(--color-error);
|
||||||
|
@ -176,6 +166,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
|
||||||
];
|
];
|
||||||
// tslint:disable-next-line:no-unused-variable
|
// tslint:disable-next-line:no-unused-variable
|
||||||
private startString = new Date().toLocaleTimeString();
|
private startString = new Date().toLocaleTimeString();
|
||||||
|
private config;
|
||||||
|
|
||||||
// FIELDS
|
// FIELDS
|
||||||
// All datasets
|
// All datasets
|
||||||
|
@ -199,6 +190,8 @@ export class AppComponent implements OnInit, AfterViewChecked {
|
||||||
private resultsScrollTop = 0;
|
private resultsScrollTop = 0;
|
||||||
// tslint:disable-next-line:no-unused-variable
|
// tslint:disable-next-line:no-unused-variable
|
||||||
private activeGrid = 0;
|
private activeGrid = 0;
|
||||||
|
private messageShortcut;
|
||||||
|
private resultShortcut;
|
||||||
private totalElapseExecution: number;
|
private totalElapseExecution: number;
|
||||||
@ViewChild(ContextMenu) contextMenu: ContextMenu;
|
@ViewChild(ContextMenu) contextMenu: ContextMenu;
|
||||||
@ViewChildren(SlickGrid) slickgrids: QueryList<SlickGrid>;
|
@ViewChildren(SlickGrid) slickgrids: QueryList<SlickGrid>;
|
||||||
|
@ -217,6 +210,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(@Inject(forwardRef(() => DataService)) private dataService: DataService,
|
constructor(@Inject(forwardRef(() => DataService)) private dataService: DataService,
|
||||||
|
@Inject(forwardRef(() => ShortcutService)) private shortcuts: ShortcutService,
|
||||||
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
||||||
@Inject(forwardRef(() => ChangeDetectorRef)) private cd: ChangeDetectorRef) {}
|
@Inject(forwardRef(() => ChangeDetectorRef)) private cd: ChangeDetectorRef) {}
|
||||||
|
|
||||||
|
@ -227,8 +221,18 @@ export class AppComponent implements OnInit, AfterViewChecked {
|
||||||
const self = this;
|
const self = this;
|
||||||
this.totalElapseExecution = 0;
|
this.totalElapseExecution = 0;
|
||||||
this.setupResizeBind();
|
this.setupResizeBind();
|
||||||
|
this.dataService.config.then((config) => {
|
||||||
|
this.config = config;
|
||||||
|
this.shortcuts.stringCodeFor('event.toggleMessagePane').then((result) => {
|
||||||
|
self.messageShortcut = result;
|
||||||
|
});
|
||||||
|
this.shortcuts.stringCodeFor('event.toggleResultPane').then((result) => {
|
||||||
|
self.resultShortcut = result;
|
||||||
|
});
|
||||||
|
});
|
||||||
this.dataService.getBatches().then((batchs: IGridBatchMetaData[]) => {
|
this.dataService.getBatches().then((batchs: IGridBatchMetaData[]) => {
|
||||||
self.messages = [];
|
self.messages = [];
|
||||||
|
self._messageActive = self.config.showMessagesDefault;
|
||||||
for (let [batchId, batch] of batchs.entries()) {
|
for (let [batchId, batch] of batchs.entries()) {
|
||||||
let exeTime = Utils.parseTimeString(batch.totalTime);
|
let exeTime = Utils.parseTimeString(batch.totalTime);
|
||||||
if (exeTime) {
|
if (exeTime) {
|
||||||
|
@ -241,6 +245,9 @@ export class AppComponent implements OnInit, AfterViewChecked {
|
||||||
startTime: new Date(batch.startTime).toLocaleTimeString(),
|
startTime: new Date(batch.startTime).toLocaleTimeString(),
|
||||||
endTime: new Date(batch.endTime).toLocaleTimeString()
|
endTime: new Date(batch.endTime).toLocaleTimeString()
|
||||||
};
|
};
|
||||||
|
if (batch.hasError) {
|
||||||
|
self._messageActive = true;
|
||||||
|
}
|
||||||
for (let message of batch.messages) {
|
for (let message of batch.messages) {
|
||||||
let date = new Date(message.time);
|
let date = new Date(message.time);
|
||||||
let timeString = date.toLocaleTimeString();
|
let timeString = date.toLocaleTimeString();
|
||||||
|
@ -557,6 +564,7 @@ export class AppComponent implements OnInit, AfterViewChecked {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
keyEvent(e): void {
|
keyEvent(e): void {
|
||||||
|
const self = this;
|
||||||
if (e.detail) {
|
if (e.detail) {
|
||||||
e.which = e.detail.which;
|
e.which = e.detail.which;
|
||||||
e.ctrlKey = e.detail.ctrlKey;
|
e.ctrlKey = e.detail.ctrlKey;
|
||||||
|
@ -564,25 +572,13 @@ export class AppComponent implements OnInit, AfterViewChecked {
|
||||||
e.altKey = e.detail.altKey;
|
e.altKey = e.detail.altKey;
|
||||||
e.shiftKey = e.detail.shiftKey;
|
e.shiftKey = e.detail.shiftKey;
|
||||||
}
|
}
|
||||||
let eString = this.buildEventString(e);
|
let eString = this.shortcuts.buildEventString(e);
|
||||||
if (shortcuts[eString]) {
|
this.shortcuts.getEvent(eString).then((result) => {
|
||||||
this.shortcutfunc[shortcuts[eString]]();
|
if (result) {
|
||||||
e.stopImmediatePropagation();
|
self.shortcutfunc[<string> result]();
|
||||||
}
|
e.stopImmediatePropagation();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
/**
|
|
||||||
* Builds a event string of ctrl, shift, alt, and a-z + up, down, left, right
|
|
||||||
* based on a passed Jquery event object, i.e 'ctrl+alt+t'
|
|
||||||
* @param e The Jquery event object to build the string from
|
|
||||||
*/
|
|
||||||
buildEventString(e): string {
|
|
||||||
let resString = '';
|
|
||||||
resString += (e.ctrlKey || e.metaKey) ? 'ctrl+' : '';
|
|
||||||
resString += e.altKey ? 'alt+' : '';
|
|
||||||
resString += e.shiftKey ? 'shift+' : '';
|
|
||||||
resString += e.which >= 65 && e.which <= 90 ? String.fromCharCode(e.which).toLowerCase() : keycodes[e.which];
|
|
||||||
return resString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,9 +2,10 @@
|
||||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
* ------------------------------------------------------------------------------------------ */
|
* ------------------------------------------------------------------------------------------ */
|
||||||
import { Component, Output, EventEmitter } from '@angular/core';
|
import { Component, Output, EventEmitter, Inject, forwardRef } from '@angular/core';
|
||||||
|
|
||||||
import {ISlickRange} from './../slickgrid/SelectionModel';
|
import {ISlickRange} from './../slickgrid/SelectionModel';
|
||||||
|
import {ShortcutService} from './../services/shortcuts.service';
|
||||||
|
|
||||||
import * as Constants from './../constants';
|
import * as Constants from './../constants';
|
||||||
import * as Utils from './../utils';
|
import * as Utils from './../utils';
|
||||||
|
@ -14,6 +15,7 @@ import * as Utils from './../utils';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'context-menu',
|
selector: 'context-menu',
|
||||||
|
providers: [ShortcutService],
|
||||||
templateUrl: 'dist/html/contextmenu.component.html'
|
templateUrl: 'dist/html/contextmenu.component.html'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -30,6 +32,22 @@ export class ContextMenu {
|
||||||
private index: number;
|
private index: number;
|
||||||
private selection: ISlickRange[];
|
private selection: ISlickRange[];
|
||||||
private isDisabled: boolean;
|
private isDisabled: boolean;
|
||||||
|
private keys = {
|
||||||
|
'event.saveAsCSV': '',
|
||||||
|
'event.saveAsJSON': '',
|
||||||
|
'event.selectAll': ''
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(@Inject(forwardRef(() => ShortcutService)) private shortcuts: ShortcutService) {
|
||||||
|
const self = this;
|
||||||
|
for (let key in this.keys) {
|
||||||
|
if (this.keys.hasOwnProperty(key)) {
|
||||||
|
this.shortcuts.stringCodeFor(key).then((result) => {
|
||||||
|
self.keys[key] = result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
show(x: number, y: number, batchId: number, resultId: number, index: number, selection: ISlickRange[]): void {
|
show(x: number, y: number, batchId: number, resultId: number, index: number, selection: ISlickRange[]): void {
|
||||||
this.batchId = batchId;
|
this.batchId = batchId;
|
||||||
|
|
|
@ -73,3 +73,8 @@ export interface IGridIcon {
|
||||||
hoverText: () => string;
|
hoverText: () => string;
|
||||||
functionality: (batchId: number, resultId: number, index: number) => void;
|
functionality: (batchId: number, resultId: number, index: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IResultsConfig {
|
||||||
|
shortcuts: { [key: string]: string };
|
||||||
|
messagesDefaultOpen: boolean;
|
||||||
|
}
|
||||||
|
|
|
@ -8,7 +8,8 @@ import {Observable} from 'rxjs/Rx';
|
||||||
|
|
||||||
import { ISlickRange } from './../slickGrid/SelectionModel';
|
import { ISlickRange } from './../slickGrid/SelectionModel';
|
||||||
|
|
||||||
import { IDbColumn, ResultSetSubset, IGridBatchMetaData, ISelectionData, IResultMessage } from './../interfaces';
|
import { IDbColumn, ResultSetSubset, IGridBatchMetaData, ISelectionData,
|
||||||
|
IResultMessage, IResultsConfig } from './../interfaces';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service which performs the http requests to get the data resultsets from the server.
|
* Service which performs the http requests to get the data resultsets from the server.
|
||||||
|
@ -18,6 +19,8 @@ import { IDbColumn, ResultSetSubset, IGridBatchMetaData, ISelectionData, IResult
|
||||||
export class DataService {
|
export class DataService {
|
||||||
uri: string;
|
uri: string;
|
||||||
private batchSets: IGridBatchMetaData[];
|
private batchSets: IGridBatchMetaData[];
|
||||||
|
private _shortcuts;
|
||||||
|
private _config;
|
||||||
|
|
||||||
constructor(@Inject(forwardRef(() => Http)) private http) {
|
constructor(@Inject(forwardRef(() => Http)) private http) {
|
||||||
// grab the uri from the document for requests
|
// grab the uri from the document for requests
|
||||||
|
@ -305,4 +308,40 @@ export class DataService {
|
||||||
headers.append('Content-Type', 'application/json');
|
headers.append('Content-Type', 'application/json');
|
||||||
self.http.post(url, JSON.stringify({ 'message': message }), { headers: headers }).subscribe();
|
self.http.post(url, JSON.stringify({ 'message': message }), { headers: headers }).subscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get config(): Promise<{[key: string]: string}> {
|
||||||
|
const self = this;
|
||||||
|
if (this._config) {
|
||||||
|
return Promise.resolve(this._config);
|
||||||
|
} else {
|
||||||
|
return new Promise<{[key: string]: string}>((resolve, reject) => {
|
||||||
|
self.http.get('/config').map((res): IResultsConfig => {
|
||||||
|
return res.json();
|
||||||
|
}).subscribe((result) => {
|
||||||
|
self._shortcuts = result.resultShortcuts;
|
||||||
|
delete result.resultShortcuts;
|
||||||
|
self._config = result;
|
||||||
|
resolve(self._config);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get shortcuts(): Promise<any> {
|
||||||
|
const self = this;
|
||||||
|
if (this._shortcuts) {
|
||||||
|
return Promise.resolve(this._shortcuts);
|
||||||
|
} else {
|
||||||
|
return new Promise<any>((resolve, reject) => {
|
||||||
|
self.http.get('/config').map((res): IResultsConfig => {
|
||||||
|
return res.json();
|
||||||
|
}).subscribe((result) => {
|
||||||
|
self._shortcuts = result.shortcuts;
|
||||||
|
delete result.resultShortcuts;
|
||||||
|
self._config = result;
|
||||||
|
resolve(self._shortcuts);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
/* --------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||||
|
* ------------------------------------------------------------------------------------------ */
|
||||||
|
import {Injectable, Inject, forwardRef} from '@angular/core';
|
||||||
|
|
||||||
|
import { DataService } from './data.service';
|
||||||
|
|
||||||
|
const keycodes = require('./../keycodes.json!');
|
||||||
|
const displayCodes = require('./../displayCodes.json!');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service which performs the http requests to get the data resultsets from the server.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ShortcutService {
|
||||||
|
shortcuts: { [key: string]: string };
|
||||||
|
private waitPromise: Promise<void>;
|
||||||
|
|
||||||
|
constructor(@Inject(forwardRef(() => DataService)) private dataService: DataService) {
|
||||||
|
this.waitPromise = this.dataService.shortcuts.then((result) => {
|
||||||
|
this.shortcuts = result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* determines the platform aware shortcut string for an event for display purposes
|
||||||
|
* @param eventString The exact event string of the keycode you require (e.g event.toggleMessagePane)
|
||||||
|
*/
|
||||||
|
stringCodeFor(eventString: string): Promise<string> {
|
||||||
|
const self = this;
|
||||||
|
if (this.shortcuts) {
|
||||||
|
return Promise.resolve(this.stringCodeForInternal(eventString));
|
||||||
|
} else {
|
||||||
|
return new Promise<string>((resolve, reject) => {
|
||||||
|
self.waitPromise.then(() => {
|
||||||
|
resolve(self.stringCodeForInternal(eventString));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private stringCodeForInternal(eventString: string): string {
|
||||||
|
let keyString = this.shortcuts[eventString];
|
||||||
|
if (keyString) {
|
||||||
|
let platString = window.navigator.platform;
|
||||||
|
|
||||||
|
// find the current platform
|
||||||
|
if (platString.match(/win/i)) {
|
||||||
|
// iterate through the display replacement that are defined
|
||||||
|
for (let key in displayCodes['windows']) {
|
||||||
|
if (displayCodes['windows'].hasOwnProperty(key)) {
|
||||||
|
keyString = keyString.replace(key, displayCodes['windows'][key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (platString.match(/linux/i)) {
|
||||||
|
for (let key in displayCodes['linux']) {
|
||||||
|
if (displayCodes['linux'].hasOwnProperty(key)) {
|
||||||
|
keyString = keyString.replace(key, displayCodes['linux'][key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (platString.match(/mac/i)) {
|
||||||
|
for (let key in displayCodes['mac']) {
|
||||||
|
if (displayCodes['mac'].hasOwnProperty(key)) {
|
||||||
|
keyString = keyString.replace(key, displayCodes['mac'][key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keyString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getEvent(shortcut: string): Promise<string | boolean> {
|
||||||
|
const self = this;
|
||||||
|
if (this.shortcuts) {
|
||||||
|
return Promise.resolve(this.getEventInternal(shortcut));
|
||||||
|
} else {
|
||||||
|
return new Promise<string | boolean>((resolve, reject) => {
|
||||||
|
self.waitPromise.then(() => {
|
||||||
|
resolve(self.getEventInternal(shortcut));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getEventInternal(shortcut: string): string | boolean {
|
||||||
|
for (let event in this.shortcuts) {
|
||||||
|
if (this.shortcuts.hasOwnProperty(event)) {
|
||||||
|
if (this.shortcuts[event] === shortcut) {
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Builds a event string of ctrl, shift, alt, and a-z + up, down, left, right
|
||||||
|
* based on a passed Jquery event object, i.e 'ctrl+alt+t'
|
||||||
|
* @param e The Jquery event object to build the string from
|
||||||
|
*/
|
||||||
|
buildEventString(e): string {
|
||||||
|
let resString = '';
|
||||||
|
resString += (e.ctrlKey || e.metaKey) ? 'ctrl+' : '';
|
||||||
|
resString += e.altKey ? 'alt+' : '';
|
||||||
|
resString += e.shiftKey ? 'shift+' : '';
|
||||||
|
resString += e.which >= 65 && e.which <= 90 ? String.fromCharCode(e.which).toLowerCase() : keycodes[e.which];
|
||||||
|
return resString;
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче