SQL Operations Studio Public Preview 1 (0.23) release source code
381
src/sql/base/browser/ui/taskbar/actionbar.ts
Normal file
@@ -0,0 +1,381 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!vs/base/browser/ui/actionbar/actionbar';
|
||||
|
||||
import { Promise } from 'vs/base/common/winjs.base';
|
||||
import { Builder, $ } from 'vs/base/browser/builder';
|
||||
import { IAction, IActionRunner, ActionRunner } from 'vs/base/common/actions';
|
||||
import { EventType as CommonEventType } from 'vs/base/common/events';
|
||||
import { EventEmitter } from 'vs/base/common/eventEmitter';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import {
|
||||
IActionBarOptions, ActionsOrientation, IActionItem,
|
||||
IActionOptions, ActionItem, BaseActionItem
|
||||
} from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import * as lifecycle from 'vs/base/common/lifecycle';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as types from 'vs/base/common/types';
|
||||
|
||||
let defaultOptions: IActionBarOptions = {
|
||||
orientation: ActionsOrientation.HORIZONTAL,
|
||||
context: null
|
||||
};
|
||||
|
||||
/**
|
||||
* Contains logic for displaying and handling callbacks for clickable icons. Based on
|
||||
* ActionBar vs/base/browser/ui/actionbar/actionbar. This class was needed because we
|
||||
* want the ability to display content other than Action icons in the QueryTaskbar.
|
||||
*/
|
||||
export class ActionBar extends EventEmitter implements IActionRunner {
|
||||
|
||||
private _options: IActionBarOptions;
|
||||
private _actionRunner: IActionRunner;
|
||||
private _context: any;
|
||||
|
||||
// Items
|
||||
private _items: IActionItem[];
|
||||
private _focusedItem: number;
|
||||
private _focusTracker: DOM.IFocusTracker;
|
||||
private _toDispose: lifecycle.IDisposable[];
|
||||
|
||||
// Elements
|
||||
private _domNode: HTMLElement;
|
||||
private _actionsList: HTMLElement;
|
||||
|
||||
constructor(container: HTMLElement | Builder, options: IActionBarOptions = defaultOptions) {
|
||||
super();
|
||||
this._options = options;
|
||||
this._context = options.context;
|
||||
this._toDispose = [];
|
||||
this._actionRunner = this._options.actionRunner;
|
||||
|
||||
if (!this._actionRunner) {
|
||||
this._actionRunner = new ActionRunner();
|
||||
this._toDispose.push(this._actionRunner);
|
||||
}
|
||||
|
||||
this._toDispose.push(this.addEmitter(this._actionRunner));
|
||||
|
||||
this._items = [];
|
||||
this._focusedItem = undefined;
|
||||
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.className = 'monaco-action-bar';
|
||||
|
||||
if (options.animated !== false) {
|
||||
DOM.addClass(this._domNode, 'animated');
|
||||
}
|
||||
|
||||
let isVertical = this._options.orientation === ActionsOrientation.VERTICAL;
|
||||
if (isVertical) {
|
||||
this._domNode.className += ' vertical';
|
||||
}
|
||||
|
||||
$(this._domNode).on(DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => {
|
||||
let event = new StandardKeyboardEvent(e);
|
||||
let eventHandled = true;
|
||||
|
||||
if (event.equals(isVertical ? KeyCode.UpArrow : KeyCode.LeftArrow)) {
|
||||
this.focusPrevious();
|
||||
} else if (event.equals(isVertical ? KeyCode.DownArrow : KeyCode.RightArrow)) {
|
||||
this.focusNext();
|
||||
} else if (event.equals(KeyCode.Escape)) {
|
||||
this.cancel();
|
||||
} else if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
|
||||
// Nothing, just staying out of the else branch
|
||||
} else {
|
||||
eventHandled = false;
|
||||
}
|
||||
|
||||
if (eventHandled) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
// Prevent native context menu on actions
|
||||
$(this._domNode).on(DOM.EventType.CONTEXT_MENU, (e: Event) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
$(this._domNode).on(DOM.EventType.KEY_UP, (e: KeyboardEvent) => {
|
||||
let event = new StandardKeyboardEvent(e);
|
||||
|
||||
// Run action on Enter/Space
|
||||
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
|
||||
this.doTrigger(event);
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
// Recompute focused item
|
||||
else if (event.equals(KeyCode.Tab) || event.equals(KeyMod.Shift | KeyCode.Tab)) {
|
||||
this.updateFocusedItem();
|
||||
}
|
||||
});
|
||||
|
||||
this._focusTracker = DOM.trackFocus(this._domNode);
|
||||
this._focusTracker.addBlurListener(() => {
|
||||
if (document.activeElement === this._domNode || !DOM.isAncestor(document.activeElement, this._domNode)) {
|
||||
this.emit(DOM.EventType.BLUR, {});
|
||||
this._focusedItem = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
this._focusTracker.addFocusListener(() => this.updateFocusedItem());
|
||||
|
||||
this._actionsList = document.createElement('ul');
|
||||
this._actionsList.className = 'actions-container';
|
||||
this._actionsList.setAttribute('role', 'toolbar');
|
||||
if (this._options.ariaLabel) {
|
||||
this._actionsList.setAttribute('aria-label', this._options.ariaLabel);
|
||||
}
|
||||
|
||||
this._domNode.appendChild(this._actionsList);
|
||||
|
||||
((container instanceof Builder) ? container.getHTMLElement() : container).appendChild(this._domNode);
|
||||
}
|
||||
|
||||
public setAriaLabel(label: string): void {
|
||||
if (label) {
|
||||
this._actionsList.setAttribute('aria-label', label);
|
||||
} else {
|
||||
this._actionsList.removeAttribute('aria-label');
|
||||
}
|
||||
}
|
||||
|
||||
private updateFocusedItem(): void {
|
||||
for (let i = 0; i < this._actionsList.children.length; i++) {
|
||||
let elem = this._actionsList.children[i];
|
||||
if (DOM.isAncestor(document.activeElement, elem)) {
|
||||
this._focusedItem = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public get context(): any {
|
||||
return this._context;
|
||||
}
|
||||
|
||||
public set context(context: any) {
|
||||
this._context = context;
|
||||
this._items.forEach(i => i.setActionContext(context));
|
||||
}
|
||||
|
||||
public get actionRunner(): IActionRunner {
|
||||
return this._actionRunner;
|
||||
}
|
||||
|
||||
public set actionRunner(actionRunner: IActionRunner) {
|
||||
if (actionRunner) {
|
||||
this._actionRunner = actionRunner;
|
||||
this._items.forEach(item => item.actionRunner = actionRunner);
|
||||
}
|
||||
}
|
||||
|
||||
public getContainer(): Builder {
|
||||
return $(this._domNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an HTML Element onto the action bar UI in the position specified by options.
|
||||
* Pushes to the last position if no options are provided.
|
||||
*/
|
||||
public pushElement(element: HTMLElement, options: IActionOptions = {}): void {
|
||||
let index = types.isNumber(options.index) ? options.index : null;
|
||||
|
||||
if (index === null || index < 0 || index >= this._actionsList.children.length) {
|
||||
this._actionsList.appendChild(element);
|
||||
} else {
|
||||
this._actionsList.insertBefore(element, this._actionsList.children[index++]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Push an action onto the action bar UI in the position specified by options.
|
||||
* Pushes to the last position if no options are provided.
|
||||
*/
|
||||
public pushAction(arg: IAction | IAction[], options: IActionOptions = {}): void {
|
||||
|
||||
const actions: IAction[] = !Array.isArray(arg) ? [arg] : arg;
|
||||
|
||||
let index = types.isNumber(options.index) ? options.index : null;
|
||||
|
||||
actions.forEach((action: IAction) => {
|
||||
const actionItemElement = document.createElement('li');
|
||||
actionItemElement.className = 'action-item';
|
||||
actionItemElement.setAttribute('role', 'presentation');
|
||||
|
||||
let item: IActionItem = null;
|
||||
|
||||
if (this._options.actionItemProvider) {
|
||||
item = this._options.actionItemProvider(action);
|
||||
}
|
||||
|
||||
if (!item) {
|
||||
item = new ActionItem(this.context, action, options);
|
||||
}
|
||||
|
||||
item.actionRunner = this._actionRunner;
|
||||
item.setActionContext(this.context);
|
||||
this.addEmitter(item);
|
||||
item.render(actionItemElement);
|
||||
|
||||
if (index === null || index < 0 || index >= this._actionsList.children.length) {
|
||||
this._actionsList.appendChild(actionItemElement);
|
||||
} else {
|
||||
this._actionsList.insertBefore(actionItemElement, this._actionsList.children[index++]);
|
||||
}
|
||||
|
||||
this._items.push(item);
|
||||
});
|
||||
}
|
||||
|
||||
public pull(index: number): void {
|
||||
if (index >= 0 && index < this._items.length) {
|
||||
this._items.splice(index, 1);
|
||||
this._actionsList.removeChild(this._actionsList.childNodes[index]);
|
||||
}
|
||||
}
|
||||
|
||||
public clear(): void {
|
||||
// Do not dispose action items if they were provided from outside
|
||||
this._items = this._options.actionItemProvider ? [] : lifecycle.dispose(this._items);
|
||||
$(this._actionsList).empty();
|
||||
}
|
||||
|
||||
public length(): number {
|
||||
return this._items.length;
|
||||
}
|
||||
|
||||
public isEmpty(): boolean {
|
||||
return this._items.length === 0;
|
||||
}
|
||||
|
||||
public focus(selectFirst?: boolean): void {
|
||||
if (selectFirst && typeof this._focusedItem === 'undefined') {
|
||||
this._focusedItem = 0;
|
||||
}
|
||||
|
||||
this.updateFocus();
|
||||
}
|
||||
|
||||
private focusNext(): void {
|
||||
if (typeof this._focusedItem === 'undefined') {
|
||||
this._focusedItem = this._items.length - 1;
|
||||
}
|
||||
|
||||
let startIndex = this._focusedItem;
|
||||
let item: IActionItem;
|
||||
|
||||
do {
|
||||
this._focusedItem = (this._focusedItem + 1) % this._items.length;
|
||||
item = this._items[this._focusedItem];
|
||||
} while (this._focusedItem !== startIndex && !item.isEnabled());
|
||||
|
||||
if (this._focusedItem === startIndex && !item.isEnabled()) {
|
||||
this._focusedItem = undefined;
|
||||
}
|
||||
|
||||
this.updateFocus();
|
||||
}
|
||||
|
||||
private focusPrevious(): void {
|
||||
if (typeof this._focusedItem === 'undefined') {
|
||||
this._focusedItem = 0;
|
||||
}
|
||||
|
||||
let startIndex = this._focusedItem;
|
||||
let item: IActionItem;
|
||||
|
||||
do {
|
||||
this._focusedItem = this._focusedItem - 1;
|
||||
|
||||
if (this._focusedItem < 0) {
|
||||
this._focusedItem = this._items.length - 1;
|
||||
}
|
||||
|
||||
item = this._items[this._focusedItem];
|
||||
} while (this._focusedItem !== startIndex && !item.isEnabled());
|
||||
|
||||
if (this._focusedItem === startIndex && !item.isEnabled()) {
|
||||
this._focusedItem = undefined;
|
||||
}
|
||||
|
||||
this.updateFocus();
|
||||
}
|
||||
|
||||
private updateFocus(): void {
|
||||
if (typeof this._focusedItem === 'undefined') {
|
||||
this._domNode.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this._items.length; i++) {
|
||||
let item = this._items[i];
|
||||
|
||||
let actionItem = <any>item;
|
||||
|
||||
if (i === this._focusedItem) {
|
||||
if (types.isFunction(actionItem.focus)) {
|
||||
actionItem.focus();
|
||||
}
|
||||
} else {
|
||||
if (types.isFunction(actionItem.blur)) {
|
||||
actionItem.blur();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private doTrigger(event: StandardKeyboardEvent): void {
|
||||
if (typeof this._focusedItem === 'undefined') {
|
||||
return; //nothing to focus
|
||||
}
|
||||
|
||||
// trigger action
|
||||
let actionItem = this._items[this._focusedItem];
|
||||
if (actionItem instanceof BaseActionItem) {
|
||||
const context = (actionItem._context === null || actionItem._context === undefined) ? event : actionItem._context;
|
||||
this.run(actionItem._action, context).done();
|
||||
}
|
||||
}
|
||||
|
||||
private cancel(): void {
|
||||
if (document.activeElement instanceof HTMLElement) {
|
||||
(<HTMLElement>document.activeElement).blur(); // remove focus from focussed action
|
||||
}
|
||||
|
||||
this.emit(CommonEventType.CANCEL);
|
||||
}
|
||||
|
||||
public run(action: IAction, context?: any): Promise {
|
||||
return this._actionRunner.run(action, context);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
if (this._items !== null) {
|
||||
lifecycle.dispose(this._items);
|
||||
}
|
||||
this._items = null;
|
||||
|
||||
if (this._focusTracker) {
|
||||
this._focusTracker.dispose();
|
||||
this._focusTracker = null;
|
||||
}
|
||||
|
||||
this._toDispose = lifecycle.dispose(this._toDispose);
|
||||
|
||||
this.getContainer().destroy();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#212121;}</style></defs><title>change_connection</title><g id="path1"><path class="cls-1" d="M7.7,6.72h.83l0,2.85H7.68ZM5.51,8.61h.73v1.52A2,2,0,0,0,8,12.3h.19A2,2,0,0,0,10,10.16V8.64h.73v1.52a2.81,2.81,0,0,1-2.52,3H8A2.81,2.81,0,0,1,5.5,10.13ZM6.46,3.8A2.23,2.23,0,0,1,8,3.11h.19a2.81,2.81,0,0,1,2.47,3.06V7.7H10V6.17A2,2,0,0,0,8.24,4H8A2,2,0,0,0,6.26,6.14V7.67H5.52V6.14A3.33,3.33,0,0,1,6.46,3.8Z"/></g><path class="cls-1" d="M8,14.83a7,7,0,0,0,6.76-5l.93.29a7.75,7.75,0,0,1-1.14,2.32,8.11,8.11,0,0,1-4,3A7.88,7.88,0,0,1,8,15.8a8,8,0,0,1-3.9-1,8.14,8.14,0,0,1-1.63-1.2A7.82,7.82,0,0,1,1.18,12v1.85H.2V10H4.1v1H1.69a7.05,7.05,0,0,0,2.6,2.84,7.29,7.29,0,0,0,1.76.79A6.8,6.8,0,0,0,8,14.83ZM15.8,2.15V6H11.9v-1h2.41a7,7,0,0,0-1.12-1.61A7.08,7.08,0,0,0,11.7,2.24a7.28,7.28,0,0,0-1.76-.78A6.8,6.8,0,0,0,8,1.17a7,7,0,0,0-6.76,5L.31,5.91A7.79,7.79,0,0,1,1.44,3.59a8.08,8.08,0,0,1,4-3A7.85,7.85,0,0,1,8,.2a8,8,0,0,1,3.9,1,8.14,8.14,0,0,1,1.63,1.2A7.81,7.81,0,0,1,14.82,4V2.15Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>change_connection_inverse</title><g id="path1"><path class="cls-1" d="M7.7,6.72h.83l0,2.85H7.68ZM5.51,8.61h.73v1.52A2,2,0,0,0,8,12.3h.19A2,2,0,0,0,10,10.16V8.64h.73v1.52a2.81,2.81,0,0,1-2.52,3H8A2.81,2.81,0,0,1,5.5,10.13ZM6.46,3.8A2.23,2.23,0,0,1,8,3.11h.19a2.81,2.81,0,0,1,2.47,3.06V7.7H10V6.17A2,2,0,0,0,8.24,4H8A2,2,0,0,0,6.26,6.14V7.67H5.52V6.14A3.33,3.33,0,0,1,6.46,3.8Z"/></g><path class="cls-1" d="M8,14.83a7,7,0,0,0,6.76-5l.93.29a7.75,7.75,0,0,1-1.14,2.32,8.11,8.11,0,0,1-4,3A7.88,7.88,0,0,1,8,15.8a8,8,0,0,1-3.9-1,8.14,8.14,0,0,1-1.63-1.2A7.82,7.82,0,0,1,1.18,12v1.85H.2V10H4.1v1H1.69a7.05,7.05,0,0,0,2.6,2.84,7.29,7.29,0,0,0,1.76.79A6.8,6.8,0,0,0,8,14.83ZM15.8,2.15V6H11.9v-1h2.41a7,7,0,0,0-1.12-1.61A7.08,7.08,0,0,0,11.7,2.24a7.28,7.28,0,0,0-1.76-.78A6.8,6.8,0,0,0,8,1.17a7,7,0,0,0-6.76,5L.31,5.91A7.79,7.79,0,0,1,1.44,3.59a8.08,8.08,0,0,1,4-3A7.85,7.85,0,0,1,8,.2a8,8,0,0,1,3.9,1,8.14,8.14,0,0,1,1.63,1.2A7.81,7.81,0,0,1,14.82,4V2.15Z"/></svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
1
src/sql/base/browser/ui/taskbar/media/connect.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#212121;}</style></defs><title>connect</title><path id="path1" class="cls-1" d="M7.67,5.75H9l0,4.51H7.64Zm-3.47,3H5.36l0,2.41c0,1.88,1.23,3.42,2.76,3.43h.31c1.54,0,2.8-1.51,2.82-3.38l0-2.41h1.16l0,2.41c0,2.66-1.8,4.8-4,4.78H8.1c-2.18,0-3.93-2.19-3.91-4.84ZM5.7,1.12A3.53,3.53,0,0,1,8.22,0h.31c2.18,0,3.93,2.19,3.91,4.85l0,2.41H11.26l0-2.41c0-1.88-1.23-3.41-2.76-3.43H8.21C6.67,1.44,5.41,3,5.39,4.84l0,2.41H4.22l0-2.41A5.28,5.28,0,0,1,5.7,1.12Z"/></svg>
|
||||
|
After Width: | Height: | Size: 570 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>connect_inverse</title><path id="path1" class="cls-1" d="M7.67,5.75H9l0,4.51H7.64Zm-3.47,3H5.36l0,2.41c0,1.88,1.23,3.42,2.76,3.43h.31c1.54,0,2.8-1.51,2.82-3.38l0-2.41h1.16l0,2.41c0,2.66-1.8,4.8-4,4.78H8.1c-2.18,0-3.93-2.19-3.91-4.84ZM5.7,1.12A3.53,3.53,0,0,1,8.22,0h.31c2.18,0,3.93,2.19,3.91,4.85l0,2.41H11.26l0-2.41c0-1.88-1.23-3.41-2.76-3.43H8.21C6.67,1.44,5.41,3,5.39,4.84l0,2.41H4.22l0-2.41A5.28,5.28,0,0,1,5.7,1.12Z"/></svg>
|
||||
|
After Width: | Height: | Size: 575 B |
1
src/sql/base/browser/ui/taskbar/media/copy_image.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>copy_image_16x16</title><path d="M16,4.09v10H2v-2H0v-10H14v2Zm-15-1V7.38L3.5,4.89l4,4,2-2L13,10.38V3.09Zm7.29,8L3.5,6.3,1,8.81v2.29Zm6.71-6H14v7H3v1H15Zm-2.71,6L9.5,8.3,8.2,9.59l1.51,1.5Zm-.79-6a.51.51,0,1,1,.35-.15A.48.48,0,0,1,11.5,5.09Z"/></svg>
|
||||
|
After Width: | Height: | Size: 348 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>copy_image_inverse_16x16</title><path class="cls-1" d="M16,4.78v10H2v-2H0v-10H14v2Zm-15-1V8.07L3.5,5.58l4,4,2-2L13,11.07V3.78Zm7.29,8L3.5,7,1,9.49v2.29Zm6.71-6H14v7H3v1H15Zm-2.71,6L9.5,9l-1.3,1.3,1.51,1.5Zm-.79-6a.51.51,0,1,1,.35-.15A.48.48,0,0,1,11.5,5.78Z"/></svg>
|
||||
|
After Width: | Height: | Size: 412 B |
1
src/sql/base/browser/ui/taskbar/media/create_insight.svg
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 6.1 KiB |
1
src/sql/base/browser/ui/taskbar/media/disconnect.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#212121;}</style></defs><title>disconnect</title><g id="path1"><path class="cls-1" d="M5.2,5.27V3a3,3,0,0,1,3-3,3,3,0,0,1,3,3V7h-1V3a2,2,0,0,0-4,0V5.74ZM5.2,13V9h1v4a2,2,0,1,0,4,0V10.72l1,.47V13a3,3,0,0,1-3,3A3,3,0,0,1,5.2,13Zm-2-6.54V5.35l4,1.86V5h2V8.15L13.14,10V11.1L9.2,9.26V11h-2V8.32Z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 421 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>disconnect_inverse</title><g id="path1"><path class="cls-1" d="M5.2,5.27V3a3,3,0,0,1,3-3,3,3,0,0,1,3,3V7h-1V3a2,2,0,0,0-4,0V5.74ZM5.2,13V9h1v4a2,2,0,1,0,4,0V10.72l1,.47V13a3,3,0,0,1-3,3A3,3,0,0,1,5.2,13Zm-2-6.54V5.35l4,1.86V5h2V8.15L13.14,10V11.1L9.2,9.26V11h-2V8.32Z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 426 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#262626"><circle cx="3.5" cy="7.5" r="2.5"/><circle cx="8.5" cy="7.5" r="2.5"/><circle cx="13.5" cy="7.5" r="2.5"/></g><g fill="#C5C5C5"><circle cx="3.5" cy="7.5" r="1.5"/><circle cx="8.5" cy="7.5" r="1.5"/><circle cx="13.5" cy="7.5" r="1.5"/></g></svg>
|
||||
|
After Width: | Height: | Size: 325 B |
1
src/sql/base/browser/ui/taskbar/media/ellipsis.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><g fill="#F6F6F6"><circle cx="3.5" cy="7.5" r="2.5"/><circle cx="8.5" cy="7.5" r="2.5"/><circle cx="13.5" cy="7.5" r="2.5"/></g><g fill="#424242"><circle cx="3.5" cy="7.5" r="1.5"/><circle cx="8.5" cy="7.5" r="1.5"/><circle cx="13.5" cy="7.5" r="1.5"/></g></svg>
|
||||
|
After Width: | Height: | Size: 325 B |
91
src/sql/base/browser/ui/taskbar/media/icons.css
Normal file
@@ -0,0 +1,91 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
.vs .monaco-toolbar .action-label.toolbar-toggle-more {
|
||||
background-image: url('ellipsis.svg');
|
||||
}
|
||||
|
||||
.hc-black .monaco-toolbar .action-label.toolbar-toggle-more,
|
||||
.vs-dark .monaco-toolbar .action-label.toolbar-toggle-more {
|
||||
background-image: url('ellipsis-inverse.svg');
|
||||
}
|
||||
|
||||
.vs .icon.start,
|
||||
.vs-dark .icon.start,
|
||||
.hc-black .icon.start {
|
||||
background-image: url('start.svg');
|
||||
}
|
||||
|
||||
.vs .icon.stop,
|
||||
.vs-dark .icon.stop,
|
||||
.hc-black .icon.stop {
|
||||
background-image: url('stop.svg');
|
||||
}
|
||||
|
||||
.vs .icon.disconnect {
|
||||
background-image: url('disconnect.svg');
|
||||
}
|
||||
|
||||
.vs-dark .icon.disconnect,
|
||||
.hc-black .icon.disconnect {
|
||||
background-image: url('disconnect_inverse.svg');
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.vs .icon.connect {
|
||||
background-image: url('connect.svg');
|
||||
}
|
||||
|
||||
.vs-dark .icon.connect,
|
||||
.hc-black .icon.connect {
|
||||
background-image: url('connect_inverse.svg');
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.vs .icon.changeConnection {
|
||||
background-image: url('change_connection.svg');
|
||||
}
|
||||
|
||||
.vs-dark .icon.changeConnection,
|
||||
.hc-black .icon.changeConnection {
|
||||
background-image: url('change_connection_inverse.svg');
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.vs .icon.estimatedQueryPlan {
|
||||
background-image: url('query-plan.svg');
|
||||
}
|
||||
|
||||
.vs-dark .icon.estimatedQueryPlan,
|
||||
.hc-black .icon.estimatedQueryPlan {
|
||||
background-image: url('query-plan-inverse.svg');
|
||||
}
|
||||
|
||||
.vs .icon.createInsight {
|
||||
background-image: url('create_insight.svg');
|
||||
}
|
||||
|
||||
.vs-dark .icon.createInsight,
|
||||
.hc-black .icon.createInsight {
|
||||
background-image: url('create_insight_inverse.svg');
|
||||
}
|
||||
|
||||
.vs .icon.copyImage {
|
||||
background-image: url('copy_image.svg');
|
||||
}
|
||||
|
||||
.vs-dark .icon.copyImage,
|
||||
.hc-black .icon.copyImage {
|
||||
background-image: url('copy_image_inverse.svg');
|
||||
}
|
||||
|
||||
.vs .icon.saveAsImage {
|
||||
background-image: url('save_as_image.svg');
|
||||
}
|
||||
|
||||
.vs-dark .icon.saveAsImage,
|
||||
.hc-black .icon.saveAsImage {
|
||||
background-image: url('save_as_image_inverse.svg');
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>query_plan_inverse_16x16</title><path class="cls-1" d="M13.06,10.49H15v5H10.22v-5h1.89v-2H3.59v2H5.48v5H.75v-5h1.9v-3H7.38v-2H5.48v-5h4.74v5H8.33v2h4.74Zm-8.53,4v-3H1.69v3Zm1.9-13v3H9.27v-3Zm7.58,13v-3H11.17v3Z"/></svg>
|
||||
|
After Width: | Height: | Size: 365 B |
1
src/sql/base/browser/ui/taskbar/media/query-plan.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>query_plan_16x16</title><path d="M13.16,10.59h1.9v5H10.32v-5h1.89v-2H3.68v2H5.58v5H.84v-5h1.9v-3H7.47v-2H5.58v-5h4.74v5H8.42v2h4.74Zm-8.53,4v-3H1.79v3Zm1.9-13v3H9.37v-3Zm7.58,13v-3H11.26v3Z"/></svg>
|
||||
|
After Width: | Height: | Size: 298 B |
1
src/sql/base/browser/ui/taskbar/media/save_as_image.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>save_as_image_16x16</title><path d="M12.22.54a.9.9,0,0,0-.47-.47A.94.94,0,0,0,11.41,0H.88A1,1,0,0,0,.54.07,1.07,1.07,0,0,0,.26.26.93.93,0,0,0,.07.54.93.93,0,0,0,0,.88v9.83l1.57,1.57H7.86v-.87H5.27V9.65H4.39v1.76H3.51V8.77H7.86V7.9H2.64v3.51h-.7L.88,10.34V.88h.88V6.14h8.77V.88h.88v7h.88v-7A.94.94,0,0,0,12.22.54ZM9.66,5.27h-7V.88h7Z"/><path d="M9,9h7v7H9Zm6.56,4.81V9.44H9.42v3.94l2-2.63,3.69,4.73-1.72-3.2.66-.66Z"/></svg>
|
||||
|
After Width: | Height: | Size: 523 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#fff;}</style></defs><title>save_as_image_inverse_16x16</title><path class="cls-1" d="M12.22.54a.9.9,0,0,0-.47-.47A.94.94,0,0,0,11.41,0H.88A1,1,0,0,0,.54.07,1.07,1.07,0,0,0,.26.26.93.93,0,0,0,.07.54.93.93,0,0,0,0,.88v9.83l1.57,1.57H7.86v-.87H5.27V9.65H4.39v1.76H3.51V8.77H7.86V7.9H2.64v3.51h-.7L.88,10.34V.88h.88V6.14h8.77V.88h.88v7h.88v-7A.94.94,0,0,0,12.22.54ZM9.66,5.27h-7V.88h7Z"/><path class="cls-1" d="M9,9h7v7H9Zm6.56,4.81V9.44H9.42v3.94l2-2.63,3.69,4.73-1.72-3.2.66-.66Z"/></svg>
|
||||
|
After Width: | Height: | Size: 605 B |
1
src/sql/base/browser/ui/taskbar/media/start.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#3bb44a;}</style></defs><title>run</title><path class="cls-1" d="M3.24,0,14.61,8,3.24,16Zm2,12.07L11.13,8,5.24,3.88Z"/><path class="cls-1" d="M3.74,1l10,7-10,7Zm1,1.92V13.07L12,8Z"/></svg>
|
||||
|
After Width: | Height: | Size: 306 B |
1
src/sql/base/browser/ui/taskbar/media/stop.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><defs><style>.cls-1{fill:#d02e00;}</style></defs><title>stop</title><path class="cls-1" d="M.5,15.3V.3h15v15Zm13-2V2.3H2.5v11Z"/><path class="cls-1" d="M1,.8H15v14H1Zm13,13V1.8H2v12Z"/></svg>
|
||||
|
After Width: | Height: | Size: 284 B |
85
src/sql/base/browser/ui/taskbar/media/taskbar.css
Normal file
@@ -0,0 +1,85 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
/* CSS Properties ported from taskbar.css */
|
||||
|
||||
.monaco-toolbar .dropdown > .dropdown-label:not(:empty):not(.tick) {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.monaco-toolbar .toolbar-toggle-more {
|
||||
display: inline-block;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Taskbar */
|
||||
|
||||
.carbon-taskbar {
|
||||
width: 100%;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.carbon-taskbar.monaco-toolbar .monaco-action-bar.animated .actions-container {
|
||||
justify-content: flex-start;
|
||||
padding-left: 15px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.taskbar-progress {
|
||||
padding-left: 5px;
|
||||
padding-top: 5px;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
}
|
||||
|
||||
.carbon-taskbar .monaco-action-bar li {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.carbon-taskbar {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.carbon-taskbar .action-item {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.carbon-taskbar .action-label {
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0% 50%;
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.listDatabasesSelectBox {
|
||||
padding-left: 2px;
|
||||
min-width: 100px;
|
||||
}
|
||||
|
||||
.carbon-taskbar.monaco-toolbar .monaco-action-bar.animated .actions-container .action-item
|
||||
.configuration.select-container .select-box {
|
||||
margin-top: 4px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.taskbarSeparator {
|
||||
width: 1px;
|
||||
background-color:#555;
|
||||
margin-right: 6px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
.taskbarTextSeparator {
|
||||
margin-left: 3px;
|
||||
margin-right: 3px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
/* Taskbar Icons */
|
||||
|
||||
.carbon-taskbar .icon {
|
||||
background-size: 11px;
|
||||
}
|
||||
141
src/sql/base/browser/ui/taskbar/taskbar.ts
Normal file
@@ -0,0 +1,141 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./media/taskbar';
|
||||
import 'vs/css!./media/icons';
|
||||
import 'vs/css!sql/media/icons/common-icons';
|
||||
|
||||
import { ActionBar } from './actionbar';
|
||||
|
||||
import { Builder, $ } from 'vs/base/browser/builder';
|
||||
import { Action, IActionRunner, IAction } from 'vs/base/common/actions';
|
||||
import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IContextMenuProvider } from 'vs/base/browser/ui/dropdown/dropdown';
|
||||
import { IToolBarOptions } from 'vs/base/browser/ui/toolbar/toolbar';
|
||||
|
||||
/**
|
||||
* A wrapper for the different types of content a QueryTaskbar can display
|
||||
*/
|
||||
export interface ITaskbarContent {
|
||||
|
||||
// Display the element created by this IAction
|
||||
action?: IAction;
|
||||
|
||||
// Display a pre-created element
|
||||
element?: HTMLElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* A widget that combines an action bar for actions. This class was needed because we
|
||||
* want the ability to use the custom QueryActionBar in order to display other HTML
|
||||
* in our taskbar. Based off import ToolBar from vs/base/browser/ui/toolbar/toolbar.
|
||||
*/
|
||||
export class Taskbar {
|
||||
private options: IToolBarOptions;
|
||||
private actionBar: ActionBar;
|
||||
private lookupKeybindings: boolean;
|
||||
|
||||
constructor(container: HTMLElement, contextMenuProvider: IContextMenuProvider, options: IToolBarOptions = { orientation: ActionsOrientation.HORIZONTAL }) {
|
||||
this.options = options;
|
||||
this.lookupKeybindings = typeof this.options.getKeyBinding === 'function' && typeof this.options.getKeyBinding === 'function';
|
||||
|
||||
let element = document.createElement('div');
|
||||
element.className = 'monaco-toolbar carbon-taskbar';
|
||||
container.appendChild(element);
|
||||
|
||||
this.actionBar = new ActionBar($(element), {
|
||||
orientation: options.orientation,
|
||||
ariaLabel: options.ariaLabel,
|
||||
actionItemProvider: (action: Action) => {
|
||||
return options.actionItemProvider ? options.actionItemProvider(action) : null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an HTML vertical separator.
|
||||
*/
|
||||
public static createTaskbarSeparator(): HTMLElement {
|
||||
let element = document.createElement('div');
|
||||
element.className = 'taskbarSeparator';
|
||||
element.innerHTML = ' ';
|
||||
return element;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an HTML spinner.
|
||||
*/
|
||||
public static createTaskbarSpinner(): HTMLElement {
|
||||
let spinnerContainer = document.createElement('div');
|
||||
spinnerContainer.className = 'taskbar-progress icon in-progress ';
|
||||
spinnerContainer.style.visibility = 'hidden';
|
||||
return spinnerContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an HTML text separator.
|
||||
*/
|
||||
public static createTaskbarText(inputText: string): HTMLElement {
|
||||
let element = document.createElement('div');
|
||||
element.className = 'taskbarTextSeparator';
|
||||
element.innerHTML = inputText;
|
||||
return element;
|
||||
}
|
||||
|
||||
public set actionRunner(actionRunner: IActionRunner) {
|
||||
this.actionBar.actionRunner = actionRunner;
|
||||
}
|
||||
|
||||
public get actionRunner(): IActionRunner {
|
||||
return this.actionBar.actionRunner;
|
||||
}
|
||||
|
||||
public set context(context: any) {
|
||||
this.actionBar.context = context;
|
||||
}
|
||||
|
||||
public getContainer(): Builder {
|
||||
return this.actionBar.getContainer();
|
||||
}
|
||||
|
||||
public setAriaLabel(label: string): void {
|
||||
this.actionBar.setAriaLabel(label);
|
||||
}
|
||||
|
||||
/**
|
||||
* Push HTMLElements and icons for IActions into the ActionBar UI. Push IActions into ActionBar's private collection.
|
||||
*/
|
||||
public setContent(content: ITaskbarContent[]): void {
|
||||
let contentToSet: ITaskbarContent[] = content ? content.slice(0) : [];
|
||||
this.actionBar.clear();
|
||||
|
||||
for (let item of contentToSet) {
|
||||
if (item.action) {
|
||||
this.actionBar.pushAction(item.action, { icon: true, label: true, keybinding: this.getKeybindingLabel(item.action) });
|
||||
} else if (item.element) {
|
||||
this.actionBar.pushElement(item.element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getKeybindingLabel(action: IAction): string {
|
||||
const key = this.lookupKeybindings ? this.options.getKeyBinding(action) : void 0;
|
||||
return key ? key.getLabel() : '';
|
||||
}
|
||||
|
||||
public addAction(primaryAction: IAction): void {
|
||||
this.actionBar.pushAction(primaryAction, { icon: true, label: false, keybinding: this.getKeybindingLabel(primaryAction) });
|
||||
}
|
||||
|
||||
public addElement(element: HTMLElement): void {
|
||||
this.actionBar.pushElement(element);
|
||||
}
|
||||
|
||||
public dispose(): void {
|
||||
this.actionBar.dispose();
|
||||
}
|
||||
}
|
||||