Merge branch 'master' into feature/nativeNotebook
1
src/sql/base/browser/ui/modal/media/close.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>close</title><path d="M8.82,8.1,15,14.29l-.81.81L8,8.91,1.81,15.1,1,14.29,7.18,8.1,1,1.9l.81-.81L8,7.28,14.19,1.1,15,1.9Z"/></svg>
|
||||
|
After Width: | Height: | Size: 230 B |
1
src/sql/base/browser/ui/modal/media/close_inverse.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:#fff;}</style></defs><title>close copy</title><path class="cls-1" d="M8.82,8.1,15,14.29l-.81.81L8,8.91,1.81,15.1,1,14.29,7.18,8.1,1,1.9l.81-.81L8,7.28,14.19,1.1,15,1.9Z"/></svg>
|
||||
|
After Width: | Height: | Size: 295 B |
1
src/sql/base/browser/ui/modal/media/copy.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</title><path d="M3-.15V3.21H0V15.95H13V12.58h3V-.15ZM12,15H1.08V4.12H12Zm3-3.36H13V3.21h-9V.75H15Z"/></svg>
|
||||
|
After Width: | Height: | Size: 212 B |
1
src/sql/base/browser/ui/modal/media/copy_inverse.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:#fff;}</style></defs><title>copy_inverse</title><path class="cls-1" d="M3,0V3.36H0V16.1H13V12.73h3V0Zm9,15.19H1.08V4.27H12Zm3-3.36H13V3.36H4V.9H15Z"/></svg>
|
||||
|
After Width: | Height: | Size: 274 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>error_notification</title><path d="M8,0a7.92,7.92,0,0,1,4,1.09A8.15,8.15,0,0,1,14.91,4a8,8,0,0,1,.81,1.91,8,8,0,0,1-.81,6.16A8.15,8.15,0,0,1,12,14.92a8,8,0,0,1-8.07,0,8.15,8.15,0,0,1-2.87-2.87A8,8,0,0,1,1.09,4,8.15,8.15,0,0,1,4,1.11,7.92,7.92,0,0,1,8,0ZM8,15a6.88,6.88,0,0,0,1.86-.25,7,7,0,0,0,4.89-4.89,7.07,7.07,0,0,0,0-3.73A7,7,0,0,0,9.86,1.27a7.07,7.07,0,0,0-3.73,0A7,7,0,0,0,1.25,6.15a7.07,7.07,0,0,0,0,3.73,7,7,0,0,0,4.89,4.89A6.88,6.88,0,0,0,8,15Zm3.46-9.76L8.71,8l2.75,2.76-.7.7L8,8.73,5.24,11.48l-.7-.7L7.29,8,4.54,5.26l.7-.7L8,7.31l2.76-2.75Z"/></svg>
|
||||
|
After Width: | Height: | Size: 661 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>error_notification_inverse</title><path class="cls-1" d="M8,0a7.92,7.92,0,0,1,4,1.09A8.15,8.15,0,0,1,14.91,4a8,8,0,0,1,.81,1.91,8,8,0,0,1-.81,6.16A8.15,8.15,0,0,1,12,14.92a8,8,0,0,1-8.07,0,8.15,8.15,0,0,1-2.87-2.87A8,8,0,0,1,1.09,4,8.15,8.15,0,0,1,4,1.11,7.92,7.92,0,0,1,8,0ZM8,15a6.88,6.88,0,0,0,1.86-.25,7,7,0,0,0,4.89-4.89,7.07,7.07,0,0,0,0-3.73A7,7,0,0,0,9.86,1.27a7.07,7.07,0,0,0-3.73,0A7,7,0,0,0,1.25,6.15a7.07,7.07,0,0,0,0,3.73,7,7,0,0,0,4.89,4.89A6.88,6.88,0,0,0,8,15Zm3.46-9.76L8.71,8l2.75,2.76-.7.7L8,8.73,5.24,11.48l-.7-.7L7.29,8,4.54,5.26l.7-.7L8,7.31l2.76-2.75Z"/></svg>
|
||||
|
After Width: | Height: | Size: 729 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>info_notification</title><path d="M8,16a7.93,7.93,0,0,1-2.13-.28A8,8,0,0,1,4,14.91,8,8,0,0,1,0,8,7.94,7.94,0,0,1,.28,5.88,8,8,0,0,1,1.09,4,8,8,0,0,1,4,1.1,8.08,8.08,0,0,1,5.86.3a8.13,8.13,0,0,1,4.25,0,8,8,0,0,1,3.53,2.05A8,8,0,0,1,14.9,4a8,8,0,0,1,.8,1.91,8,8,0,0,1-2.05,7.78A7.93,7.93,0,0,1,12,14.91a8,8,0,0,1-1.91.8A7.93,7.93,0,0,1,8,16ZM8,1.08a6.72,6.72,0,0,0-1.84.25A7.09,7.09,0,0,0,4.5,2,6.92,6.92,0,0,0,2,4.52a7.09,7.09,0,0,0-.7,1.66,6.87,6.87,0,0,0,0,3.67A7.07,7.07,0,0,0,2,11.5,6.92,6.92,0,0,0,4.5,14a7.09,7.09,0,0,0,1.65.7,6.89,6.89,0,0,0,3.68,0,7.07,7.07,0,0,0,1.66-.7A6.92,6.92,0,0,0,14,11.5a7.08,7.08,0,0,0,.7-1.65,6.89,6.89,0,0,0,0-3.68A7.09,7.09,0,0,0,14,4.52,6.92,6.92,0,0,0,11.48,2a7.07,7.07,0,0,0-1.66-.7A6.74,6.74,0,0,0,8,1.08Zm-.53,3.2H8.52V5.34H7.46Zm0,2.13H8.52v5.33H7.46Z"/></svg>
|
||||
|
After Width: | Height: | Size: 902 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>info_notification_inverse</title><path class="cls-1" d="M8,16a7.93,7.93,0,0,1-2.13-.28A8,8,0,0,1,4,14.91,8,8,0,0,1,0,8,7.94,7.94,0,0,1,.28,5.88,8,8,0,0,1,1.09,4,8,8,0,0,1,4,1.1,8.08,8.08,0,0,1,5.86.3a8.13,8.13,0,0,1,4.25,0,8,8,0,0,1,3.53,2.05A8,8,0,0,1,14.9,4a8,8,0,0,1,.8,1.91,8,8,0,0,1-2.05,7.78A7.93,7.93,0,0,1,12,14.91a8,8,0,0,1-1.91.8A7.93,7.93,0,0,1,8,16ZM8,1.08a6.72,6.72,0,0,0-1.84.25A7.09,7.09,0,0,0,4.5,2,6.92,6.92,0,0,0,2,4.52a7.09,7.09,0,0,0-.7,1.66,6.87,6.87,0,0,0,0,3.67A7.07,7.07,0,0,0,2,11.5,6.92,6.92,0,0,0,4.5,14a7.09,7.09,0,0,0,1.65.7,6.89,6.89,0,0,0,3.68,0,7.07,7.07,0,0,0,1.66-.7A6.92,6.92,0,0,0,14,11.5a7.08,7.08,0,0,0,.7-1.65,6.89,6.89,0,0,0,0-3.68A7.09,7.09,0,0,0,14,4.52,6.92,6.92,0,0,0,11.48,2a7.07,7.07,0,0,0-1.66-.7A6.74,6.74,0,0,0,8,1.08Zm-.53,3.2H8.52V5.34H7.46Zm0,2.13H8.52v5.33H7.46Z"/></svg>
|
||||
|
After Width: | Height: | Size: 970 B |
@@ -50,6 +50,8 @@
|
||||
.monaco-shell .modal.flyout-dialog .modal-content {
|
||||
height: 100%;
|
||||
font-size: 11px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal .modal-title {
|
||||
@@ -63,13 +65,10 @@
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.monaco-shell .modal.flyout-dialog .modal-body {
|
||||
height: calc(100% - 105px);
|
||||
}
|
||||
|
||||
/* modal body for angular component dialog */
|
||||
.monaco-shell .modal.flyout-dialog .modal-body,
|
||||
.monaco-shell .modal.flyout-dialog .angular-modal-body {
|
||||
height: calc(100% - 90px);
|
||||
margin-bottom: auto;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Style for body and footer in modal dialog. This should be applied to dialog created with angular component. */
|
||||
@@ -128,13 +127,6 @@
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .dialogErrorMessage {
|
||||
overflow: hidden;
|
||||
padding-left: 10px;
|
||||
overflow-y: auto;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.modal .modal-footer {
|
||||
display: flex;
|
||||
}
|
||||
@@ -167,27 +159,122 @@
|
||||
margin-right: none;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .icon.error {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
.modal.flyout-dialog .dialog-message {
|
||||
padding: 6px 10px 10px 10px;
|
||||
font-size: 13px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal .modal-footer .dialogErrorMessage {
|
||||
align-items: center;
|
||||
max-height: 30px;
|
||||
margin-right: 5px;
|
||||
.modal.flyout-dialog .dialog-message.error {
|
||||
background-color:#B62E00 !important;
|
||||
color:#FFFFFF !important;
|
||||
}
|
||||
|
||||
.modal .dialogErrorMessage .icon {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
width: auto;
|
||||
height: 20px;
|
||||
.modal.flyout-dialog .dialog-message.warning {
|
||||
background-color:#F9E385 !important;
|
||||
color:#4A4A4A !important;
|
||||
}
|
||||
|
||||
.modal .modal-footer .dialogErrorMessage .errorMessage {
|
||||
max-height: 100%;
|
||||
.modal.flyout-dialog .dialog-message.info {
|
||||
background-color:#0078D7 !important;
|
||||
color:#FFFFFF !important;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .dialog-message-header {
|
||||
overflow: hidden;
|
||||
overflow-y: hidden;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .dialog-message-body {
|
||||
margin-left: 26px;
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
max-height: 90px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .dialog-message-icon {
|
||||
margin-right: 10px;
|
||||
margin-top: 5px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
min-width: 16px;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .dialog-message-severity {
|
||||
margin-right: auto;
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .dialog-message-button {
|
||||
min-width: 60px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .dialog-message-button > a {
|
||||
background-position-x: 2px !important;
|
||||
background-color: inherit !important;
|
||||
color:inherit !important;
|
||||
padding-left: 22px !important;
|
||||
background-size: 16px 16px !important;
|
||||
text-align: left !important;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .dialog-message-summary {
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .dialog-message-summary.expanded {
|
||||
white-space: normal;
|
||||
overflow-x: unset;
|
||||
}
|
||||
|
||||
.modal.flyout-dialog .dialog-message-detail {
|
||||
margin-top: 5px;
|
||||
white-space: normal;
|
||||
-webkit-user-select: text;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.close-message-icon {
|
||||
background: url('close_inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.dialog-message.warning .close-message-icon {
|
||||
background: url('close.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.copy-message-icon {
|
||||
background: url('copy_inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.dialog-message.warning .copy-message-icon {
|
||||
background: url('copy.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.message-details-icon {
|
||||
background: url('show_details_inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.dialog-message.warning .message-details-icon {
|
||||
background: url('show_details.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.dialog-message.info .dialog-message-icon {
|
||||
background: url('info_notification_inverse.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.dialog-message.warning .dialog-message-icon {
|
||||
background: url('warning_notification.svg') center center no-repeat;
|
||||
}
|
||||
|
||||
.dialog-message.error .dialog-message-icon {
|
||||
background: url('error_notification_inverse.svg') center center no-repeat;
|
||||
}
|
||||
1
src/sql/base/browser/ui/modal/media/show_details.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>show_details</title><path d="M1,0H15V16H1ZM14,15V1H2V15ZM13,3V4H3V3Zm0,2V6H3V5Zm0,2V8H3V7Zm0,2v1H3V9Zm0,2v1H3V11Z"/></svg>
|
||||
|
After Width: | Height: | Size: 222 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>show_details_inverse</title><path class="cls-1" d="M1,0H15V16H1ZM14,15V1H2V15ZM13,3V4H3V3Zm0,2V6H3V5Zm0,2V8H3V7Zm0,2v1H3V9Zm0,2v1H3V11Z"/></svg>
|
||||
|
After Width: | Height: | Size: 290 B |
@@ -0,0 +1 @@
|
||||
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><title>warning_notification</title><path d="M8,0l8,16H0ZM8,2.4,1.73,15H14.28Zm-.53,4H8.53v5.33H7.47Zm0,7.47V12.82H8.53v1.07Z"/></svg>
|
||||
|
After Width: | Height: | Size: 226 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>warning_notification_inverse</title><path class="cls-1" d="M8,0l8,16H0ZM8,2.4,1.73,15H14.28Zm-.53,4H8.53v5.33H7.47Zm0,7.47V12.82H8.53v1.07Z"/></svg>
|
||||
|
After Width: | Height: | Size: 294 B |
@@ -2,7 +2,6 @@
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import 'vs/css!sql/media/icons/common-icons';
|
||||
import 'vs/css!./media/modal';
|
||||
import { IThemable } from 'vs/platform/theme/common/styler';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
@@ -16,18 +15,25 @@ import * as DOM from 'vs/base/browser/dom';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
import { Button } from 'sql/base/browser/ui/button/button';
|
||||
import * as TelemetryUtils from 'sql/common/telemetryUtilities';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { localize } from 'vs/nls';
|
||||
import { MessageLevel } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import * as os from 'os';
|
||||
|
||||
export const MODAL_SHOWING_KEY = 'modalShowing';
|
||||
export const MODAL_SHOWING_CONTEXT = new RawContextKey<Array<string>>(MODAL_SHOWING_KEY, []);
|
||||
const INFO_ALT_TEXT = localize('infoAltText', 'Info');
|
||||
const INFO_ALT_TEXT = localize('infoAltText', 'Infomation');
|
||||
const WARNING_ALT_TEXT = localize('warningAltText', 'Warning');
|
||||
const ERROR_ALT_TEXT = localize('errorAltText', 'Error');
|
||||
const SHOW_DETAILS_TEXT = localize('showMessageDetails', 'Show Details');
|
||||
const HIDE_DETAILS_TEXT = localize('hideMessageDetails', 'Hide Details');
|
||||
const COPY_TEXT = localize('copyMessage', 'Copy');
|
||||
const CLOSE_TEXT = localize('closeMessage', 'Close');
|
||||
const MESSAGE_EXPANDED_MODE_CLASS = 'expanded';
|
||||
|
||||
export interface IModalDialogStyles {
|
||||
dialogForeground?: Color;
|
||||
@@ -66,10 +72,20 @@ const defaultOptions: IModalOptions = {
|
||||
|
||||
export abstract class Modal extends Disposable implements IThemable {
|
||||
|
||||
private _errorMessage: Builder;
|
||||
private _spinnerElement: HTMLElement;
|
||||
private _errorIconElement: HTMLElement;
|
||||
private _messageElement: HTMLElement;
|
||||
private _messageIcon: HTMLElement;
|
||||
private _messageSeverity: Builder;
|
||||
private _messageSummary: Builder;
|
||||
private _messageSummaryElement: HTMLElement;
|
||||
private _messageDetail: Builder;
|
||||
private _messageDetailElement: HTMLElement;
|
||||
private _toggleMessageDetailButton: Button;
|
||||
private _copyMessageButton: Button;
|
||||
private _closeMessageButton: Button;
|
||||
private _messageSummaryText: string;
|
||||
private _messageDetailText: string;
|
||||
|
||||
private _spinnerElement: HTMLElement;
|
||||
private _focusableElements: NodeListOf<Element>;
|
||||
private _firstFocusableElement: HTMLElement;
|
||||
private _lastFocusableElement: HTMLElement;
|
||||
@@ -82,6 +98,7 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
|
||||
private _modalDialog: Builder;
|
||||
private _modalHeaderSection: Builder;
|
||||
private _modalMessageSection: Builder;
|
||||
private _modalBodySection: HTMLElement;
|
||||
private _modalFooterSection: Builder;
|
||||
private _closeButtonInHeader: Builder;
|
||||
@@ -135,6 +152,7 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
private _name: string,
|
||||
private _partService: IPartService,
|
||||
private _telemetryService: ITelemetryService,
|
||||
protected _clipboardService: IClipboardService,
|
||||
_contextKeyService: IContextKeyService,
|
||||
options?: IModalOptions
|
||||
) {
|
||||
@@ -149,7 +167,7 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
/**
|
||||
* Build and render the modal, will call {@link Modal#renderBody}
|
||||
*/
|
||||
public render(errorMessagesInFooter: boolean = false) {
|
||||
public render() {
|
||||
let modalBodyClass = (this._modalOptions.isAngular === false ? 'modal-body' : 'modal-body-and-footer');
|
||||
let parts: Array<HTMLElement> = [];
|
||||
// This modal header section refers to the header of of the dialog
|
||||
@@ -176,11 +194,68 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
parts.push(this._modalHeaderSection.getHTMLElement());
|
||||
}
|
||||
|
||||
if (this._modalOptions.isAngular === false && this._modalOptions.hasErrors) {
|
||||
|
||||
this._modalMessageSection = $().div({ class: 'dialog-message error' }, (messageContainer) => {
|
||||
messageContainer.div({ class: 'dialog-message-header' }, (headerContainer) => {
|
||||
headerContainer.div({ class: 'dialog-message-icon' }, (iconContainer) => {
|
||||
this._messageIcon = iconContainer.getHTMLElement();
|
||||
});
|
||||
headerContainer.div({ class: 'dialog-message-severity' }, (messageSeverityContainer) => {
|
||||
this._messageSeverity = messageSeverityContainer;
|
||||
});
|
||||
headerContainer.div({ class: 'dialog-message-button' }, (buttonContainer) => {
|
||||
this._toggleMessageDetailButton = new Button(buttonContainer);
|
||||
this._toggleMessageDetailButton.icon = 'message-details-icon';
|
||||
this._toggleMessageDetailButton.label = SHOW_DETAILS_TEXT;
|
||||
this._toggleMessageDetailButton.onDidClick((e) => {
|
||||
this.toggleMessageDetail();
|
||||
});
|
||||
});
|
||||
headerContainer.div({ class: 'dialog-message-button' }, (buttonContainer) => {
|
||||
this._copyMessageButton = new Button(buttonContainer);
|
||||
this._copyMessageButton.icon = 'copy-message-icon';
|
||||
this._copyMessageButton.label = COPY_TEXT;
|
||||
this._copyMessageButton.onDidClick((e) => {
|
||||
this._clipboardService.writeText(this.getTextForClipboard());
|
||||
});
|
||||
});
|
||||
headerContainer.div({ class: 'dialog-message-button' }, (buttonContainer) => {
|
||||
this._closeMessageButton = new Button(buttonContainer);
|
||||
this._closeMessageButton.icon = 'close-message-icon';
|
||||
this._closeMessageButton.label = CLOSE_TEXT;
|
||||
this._closeMessageButton.onDidClick((e) => {
|
||||
this.setError(undefined);
|
||||
});
|
||||
});
|
||||
});
|
||||
messageContainer.div({ class: 'dialog-message-body' }, (messageBody) => {
|
||||
messageBody.div({ class: 'dialog-message-summary' }, (summaryContainer) => {
|
||||
this._messageSummary = summaryContainer;
|
||||
this._messageSummaryElement = summaryContainer.getHTMLElement();
|
||||
this._messageSummaryElement.onclick = (e) => {
|
||||
this.toggleMessageDetail();
|
||||
};
|
||||
});
|
||||
messageBody.div({ class: 'dialog-message-detail' }, (detailContainer) => {
|
||||
this._messageDetail = detailContainer;
|
||||
this._messageDetailElement = detailContainer.getHTMLElement();
|
||||
this._messageDetailElement.style.display = 'none';
|
||||
});
|
||||
});
|
||||
});
|
||||
this._messageElement = this._modalMessageSection.getHTMLElement();
|
||||
this.updateElementVisibility(this._messageElement, false);
|
||||
|
||||
parts.push(this._messageElement);
|
||||
}
|
||||
|
||||
// This modal body section refers to the body of of the dialog
|
||||
let body: Builder;
|
||||
$().div({ class: modalBodyClass }, (builder) => {
|
||||
body = builder;
|
||||
});
|
||||
|
||||
this._modalBodySection = body.getHTMLElement();
|
||||
parts.push(body.getHTMLElement());
|
||||
|
||||
@@ -214,19 +289,6 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
builderClass += ' wide';
|
||||
}
|
||||
|
||||
if (this._modalOptions.isAngular === false && this._modalOptions.hasErrors) {
|
||||
let builder = errorMessagesInFooter ? this._leftFooter : body;
|
||||
builder.div({ class: 'dialogErrorMessage', id: 'dialogErrorMessage' }, (errorMessageContainer) => {
|
||||
errorMessageContainer.div({ class: 'sql icon error' }, (iconContainer) => {
|
||||
this._errorIconElement = iconContainer.getHTMLElement();
|
||||
this._errorIconElement.style.visibility = 'hidden';
|
||||
});
|
||||
errorMessageContainer.div({ class: 'errorMessage' }, (messageContainer) => {
|
||||
this._errorMessage = messageContainer;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// The builder builds the dialog. It append header, body and footer sections.
|
||||
this._builder = $().div({ class: builderClass, 'role': 'dialog', 'aria-label': this._title }, (dialogContainer) => {
|
||||
this._modalDialog = dialogContainer.div({ class: 'modal-dialog ', role: 'document' }, (modalDialog) => {
|
||||
@@ -273,6 +335,39 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
}
|
||||
}
|
||||
|
||||
private getTextForClipboard(): string {
|
||||
return this._messageDetailText === '' ? this._messageSummaryText : `${this._messageSummaryText}${os.EOL}========================${os.EOL}${this._messageDetailText}`;
|
||||
}
|
||||
|
||||
private updateElementVisibility(element: HTMLElement, visible: boolean) {
|
||||
element.style.display = visible ? 'block' : 'none';
|
||||
}
|
||||
|
||||
private updateExpandMessageState() {
|
||||
this._messageSummaryElement.style.cursor = this.shouldShowExpandMessageButton ? 'pointer' : 'default';
|
||||
this._messageSummaryElement.classList.remove(MESSAGE_EXPANDED_MODE_CLASS);
|
||||
this.updateElementVisibility(this._toggleMessageDetailButton.element, this.shouldShowExpandMessageButton);
|
||||
}
|
||||
|
||||
private toggleMessageDetail() {
|
||||
let isExpanded = this._messageSummaryElement.classList.contains(MESSAGE_EXPANDED_MODE_CLASS);
|
||||
if (isExpanded) {
|
||||
this._messageSummaryElement.classList.remove(MESSAGE_EXPANDED_MODE_CLASS);
|
||||
this._toggleMessageDetailButton.label = SHOW_DETAILS_TEXT;
|
||||
} else {
|
||||
this._messageSummaryElement.classList.add(MESSAGE_EXPANDED_MODE_CLASS);
|
||||
this._toggleMessageDetailButton.label = HIDE_DETAILS_TEXT;
|
||||
}
|
||||
|
||||
if (this._messageDetailText !== '') {
|
||||
this.updateElementVisibility(this._messageDetailElement, !isExpanded);
|
||||
}
|
||||
}
|
||||
|
||||
private get shouldShowExpandMessageButton(): boolean {
|
||||
return this._messageDetailText !== '' || this._messageSummaryElement.scrollWidth > this._messageSummaryElement.offsetWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set focusable elements in the modal dialog
|
||||
*/
|
||||
@@ -374,35 +469,45 @@ export abstract class Modal extends Disposable implements IThemable {
|
||||
|
||||
/**
|
||||
* Show an error in the error message element
|
||||
* @param err Text to show in the error message
|
||||
* @param message Text to show in the message
|
||||
* @param level Severity level of the message
|
||||
* @param description Description of the message
|
||||
*/
|
||||
protected setError(err: string, level: MessageLevel = MessageLevel.Error) {
|
||||
protected setError(message: string, level: MessageLevel = MessageLevel.Error, description: string = '') {
|
||||
if (this._modalOptions.hasErrors) {
|
||||
if (err === '') {
|
||||
this._errorIconElement.style.visibility = 'hidden';
|
||||
} else {
|
||||
this._messageSummaryText = message ? message : '';
|
||||
this._messageDetailText = description ? description : '';
|
||||
|
||||
if (this._messageSummaryText !== '') {
|
||||
const levelClasses = ['info', 'warning', 'error'];
|
||||
let selectedLevel = levelClasses[2];
|
||||
let altText = ERROR_ALT_TEXT;
|
||||
let severityText = ERROR_ALT_TEXT;
|
||||
if (level === MessageLevel.Information) {
|
||||
selectedLevel = levelClasses[0];
|
||||
altText = INFO_ALT_TEXT;
|
||||
severityText = INFO_ALT_TEXT;
|
||||
} else if (level === MessageLevel.Warning) {
|
||||
selectedLevel = levelClasses[1];
|
||||
altText = WARNING_ALT_TEXT;
|
||||
severityText = WARNING_ALT_TEXT;
|
||||
}
|
||||
levelClasses.forEach(level => {
|
||||
if (selectedLevel === level) {
|
||||
this._errorIconElement.classList.add(level);
|
||||
this._messageIcon.classList.add(level);
|
||||
this._messageElement.classList.add(level);
|
||||
} else {
|
||||
this._errorIconElement.classList.remove(level);
|
||||
this._messageIcon.classList.remove(level);
|
||||
this._messageElement.classList.remove(level);
|
||||
}
|
||||
});
|
||||
|
||||
this._errorIconElement.title = altText;
|
||||
this._errorIconElement.style.visibility = 'visible';
|
||||
this._messageIcon.title = severityText;
|
||||
this._messageSeverity.text(severityText);
|
||||
this._messageSummary.text(message);
|
||||
this._messageSummary.title(message);
|
||||
this._messageDetail.text(description);
|
||||
}
|
||||
this._errorMessage.text(err);
|
||||
this.updateElementVisibility(this._messageDetailElement, false);
|
||||
this.updateElementVisibility(this._messageElement, this._messageSummaryText !== '');
|
||||
this.updateExpandMessageState();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ import { SplitView, CollapsibleState } from 'sql/base/browser/ui/splitview/split
|
||||
import { Builder, $ } from 'vs/base/browser/builder';
|
||||
import { Widget } from 'vs/base/browser/ui/widget';
|
||||
import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
export class CategoryView extends FixedCollapsibleView {
|
||||
private _treecontainer: HTMLElement;
|
||||
@@ -95,9 +96,10 @@ export class OptionsDialog extends Modal {
|
||||
@IWorkbenchThemeService private _themeService: IWorkbenchThemeService,
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(title, name, partService, telemetryService, contextKeyService, options);
|
||||
super(title, name, partService, telemetryService, clipboardService, contextKeyService, options);
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
||||
@@ -46,7 +46,7 @@ export class WebViewDialog extends Modal {
|
||||
|
||||
constructor(
|
||||
@IThemeService private _themeService: IThemeService,
|
||||
@IClipboardService private _clipboardService: IClipboardService,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@IPartService private _webViewPartService: IPartService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@@ -54,7 +54,7 @@ export class WebViewDialog extends Modal {
|
||||
@IEnvironmentService private _environmentService: IEnvironmentService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
) {
|
||||
super('', TelemetryKeys.WebView, _webViewPartService, telemetryService, contextKeyService, { isFlyout: false, hasTitleIcon: true });
|
||||
super('', TelemetryKeys.WebView, _webViewPartService, telemetryService, clipboardService, contextKeyService, { isFlyout: false, hasTitleIcon: true });
|
||||
this._okLabel = localize('webViewDialog.ok', 'OK');
|
||||
this._closeLabel = localize('webViewDialog.close', 'Close');
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { IThemable } from 'vs/platform/theme/common/styler';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Dimension, EventType, $, addDisposableListener } from 'vs/base/browser/dom';
|
||||
import { $ as quickBuilder } from 'vs/base/browser/builder';
|
||||
import { $ as qb } from 'vs/base/browser/builder';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { IActionOptions, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
@@ -146,18 +146,18 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
}
|
||||
|
||||
if (this._shownTab) {
|
||||
this._tabMap.get(this._shownTab).label.classList.remove('active');
|
||||
this._tabMap.get(this._shownTab).header.classList.remove('active');
|
||||
qb(this._tabMap.get(this._shownTab).label).removeClass('active');
|
||||
qb(this._tabMap.get(this._shownTab).header).removeClass('active');
|
||||
this._tabMap.get(this._shownTab).header.setAttribute('aria-selected', 'false');
|
||||
}
|
||||
|
||||
this._shownTab = id;
|
||||
this.tabHistory.push(id);
|
||||
quickBuilder(this.body).empty();
|
||||
qb(this.body).empty();
|
||||
let tab = this._tabMap.get(this._shownTab);
|
||||
this.body.setAttribute('aria-labelledby', tab.identifier);
|
||||
tab.label.classList.add('active');
|
||||
tab.header.classList.add('active');
|
||||
qb(tab.label).addClass('active');
|
||||
qb(tab.header).addClass('active');
|
||||
tab.header.setAttribute('aria-selected', 'true');
|
||||
tab.view.render(this.body);
|
||||
this._onTabChange.fire(id);
|
||||
@@ -168,11 +168,11 @@ export class TabbedPanel extends Disposable implements IThemable {
|
||||
|
||||
public removeTab(tab: PanelTabIdentifier) {
|
||||
let actualTab = this._tabMap.get(tab);
|
||||
quickBuilder(actualTab.header).destroy();
|
||||
qb(actualTab.header).destroy();
|
||||
if (actualTab.view.remove) {
|
||||
actualTab.view.remove();
|
||||
}
|
||||
quickBuilder(this._tabMap.get(tab).header).destroy();
|
||||
qb(this._tabMap.get(tab).header).destroy();
|
||||
this._tabMap.delete(tab);
|
||||
if (this._shownTab === tab) {
|
||||
this._shownTab = undefined;
|
||||
|
||||
@@ -33,6 +33,7 @@ import { AccountListRenderer, AccountListDelegate } from 'sql/parts/accountManag
|
||||
import { AccountProviderAddedEventParams, UpdateAccountListEventParams } from 'sql/services/accountManagement/eventTypes';
|
||||
import { FixedListView } from 'sql/platform/views/fixedListView';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
|
||||
export interface IProviderViewUiComponent {
|
||||
view: FixedListView<sqlops.Account>;
|
||||
@@ -72,13 +73,15 @@ export class AccountDialog extends Modal {
|
||||
@IContextMenuService private _contextMenuService: IContextMenuService,
|
||||
@IKeybindingService private _keybindingService: IKeybindingService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(
|
||||
localize('linkedAccounts', 'Linked accounts'),
|
||||
TelemetryKeys.Accounts,
|
||||
partService,
|
||||
telemetryService,
|
||||
clipboardService,
|
||||
contextKeyService,
|
||||
{ hasSpinner: true }
|
||||
);
|
||||
|
||||
@@ -21,6 +21,7 @@ import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
||||
import { attachModalDialogStyler, attachButtonStyler } from 'sql/common/theme/styler';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
export class AutoOAuthDialog extends Modal {
|
||||
private _copyAndOpenButton: Button;
|
||||
@@ -45,13 +46,15 @@ export class AutoOAuthDialog extends Modal {
|
||||
@IThemeService private _themeService: IThemeService,
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(
|
||||
'',
|
||||
TelemetryKeys.AutoOAuth,
|
||||
partService,
|
||||
telemetryService,
|
||||
clipboardService,
|
||||
contextKeyService,
|
||||
{
|
||||
isFlyout: true,
|
||||
|
||||
@@ -29,6 +29,7 @@ import { attachModalDialogStyler, attachButtonStyler } from 'sql/common/theme/st
|
||||
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
||||
import { IAccountPickerService } from 'sql/parts/accountManagement/common/interfaces';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
// TODO: Make the help link 1) extensible (01/08/2018, https://github.com/Microsoft/azuredatastudio/issues/450)
|
||||
// in case that other non-Azure sign in is to be used
|
||||
@@ -70,12 +71,14 @@ export class FirewallRuleDialog extends Modal {
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IWindowsService private _windowsService: IWindowsService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(
|
||||
localize('createNewFirewallRule', 'Create new firewall rule'),
|
||||
TelemetryKeys.FireWallRule,
|
||||
partService,
|
||||
telemetryService,
|
||||
clipboardService,
|
||||
contextKeyService,
|
||||
{
|
||||
isFlyout: true,
|
||||
|
||||
@@ -36,6 +36,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import * as styler from 'vs/platform/theme/common/styler';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
export interface OnShowUIResponse {
|
||||
selectedProviderType: string;
|
||||
@@ -92,9 +93,10 @@ export class ConnectionDialogWidget extends Modal {
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IContextMenuService private _contextMenuService: IContextMenuService,
|
||||
@IContextViewService private _contextViewService: IContextViewService
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(localize('connection', 'Connection'), TelemetryKeys.Connection, _partService, telemetryService, contextKeyService, { hasSpinner: true, hasErrors: true });
|
||||
super(localize('connection', 'Connection'), TelemetryKeys.Connection, _partService, telemetryService, clipboardService, contextKeyService, { hasSpinner: true, hasErrors: true });
|
||||
}
|
||||
|
||||
public refresh(): void {
|
||||
|
||||
@@ -32,6 +32,7 @@ import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { Orientation } from 'sql/base/browser/ui/splitview/splitview';
|
||||
import { NewDashboardTabViewModel, IDashboardUITab } from 'sql/parts/dashboard/newDashboardTabDialog/newDashboardTabViewModel';
|
||||
import { IDashboardTab } from 'sql/platform/dashboard/common/dashboardRegistry';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
|
||||
class ExtensionListDelegate implements IVirtualDelegate<IDashboardUITab> {
|
||||
|
||||
@@ -125,13 +126,15 @@ export class NewDashboardTabDialog extends Modal {
|
||||
@IContextMenuService private _contextMenuService: IContextMenuService,
|
||||
@IKeybindingService private _keybindingService: IKeybindingService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(
|
||||
localize('newDashboardTab.openDashboardExtensions', 'Open dashboard extensions'),
|
||||
TelemetryKeys.AddNewDashboardTab,
|
||||
partService,
|
||||
telemetryService,
|
||||
clipboardService,
|
||||
contextKeyService,
|
||||
{ hasSpinner: true }
|
||||
);
|
||||
|
||||
@@ -18,6 +18,7 @@ import { Builder } from 'vs/base/browser/builder';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { bootstrapAngular } from 'sql/services/bootstrap/bootstrapService';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
export class BackupDialog extends Modal {
|
||||
private _bodyBuilder: Builder;
|
||||
@@ -31,9 +32,10 @@ export class BackupDialog extends Modal {
|
||||
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super('', TelemetryKeys.Backup, partService, telemetryService, contextKeyService, { isAngular: true, hasErrors: true });
|
||||
super('', TelemetryKeys.Backup, partService, telemetryService, clipboardService, contextKeyService, { isAngular: true, hasErrors: true });
|
||||
}
|
||||
|
||||
protected renderBody(container: HTMLElement) {
|
||||
|
||||
@@ -42,6 +42,7 @@ import { Dropdown } from 'sql/base/browser/ui/editableDropdown/dropdown';
|
||||
import { TabbedPanel, PanelTabIdentifier } from 'sql/base/browser/ui/panel/panel';
|
||||
import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
import { IFileBrowserDialogController } from 'sql/parts/fileBrowser/common/interfaces';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
|
||||
interface FileListElement {
|
||||
logicalFileName: string;
|
||||
@@ -133,9 +134,10 @@ export class RestoreDialog extends Modal {
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IFileBrowserDialogController private fileBrowserDialogService: IFileBrowserDialogController
|
||||
@IFileBrowserDialogController private fileBrowserDialogService: IFileBrowserDialogController,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(localize('RestoreDialogTitle', 'Restore database'), TelemetryKeys.Restore, partService, telemetryService, contextKeyService, { hasErrors: true, isWide: true, hasSpinner: true });
|
||||
super(localize('RestoreDialogTitle', 'Restore database'), TelemetryKeys.Restore, partService, telemetryService, clipboardService, contextKeyService, { hasErrors: true, isWide: true, hasSpinner: true });
|
||||
this._restoreTitle = localize('restoreDialog.restoreTitle', 'Restore database');
|
||||
this._databaseTitle = localize('restoreDialog.database', 'Database');
|
||||
this._backupFileTitle = localize('restoreDialog.backupFile', 'Backup file');
|
||||
|
||||
@@ -34,6 +34,7 @@ import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import * as strings from 'vs/base/common/strings';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
|
||||
export class FileBrowserDialog extends Modal {
|
||||
private _viewModel: FileBrowserViewModel;
|
||||
@@ -56,9 +57,10 @@ export class FileBrowserDialog extends Modal {
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(title, TelemetryKeys.Backup, partService, telemetryService, contextKeyService, { isFlyout: true, hasTitleIcon: false, hasBackButton: true, hasSpinner: true });
|
||||
super(title, TelemetryKeys.Backup, partService, telemetryService, clipboardService, contextKeyService, { isFlyout: true, hasTitleIcon: false, hasBackButton: true, hasSpinner: true });
|
||||
this._viewModel = this._instantiationService.createInstance(FileBrowserViewModel);
|
||||
this._viewModel.onAddFileTree(args => this.handleOnAddFileTree(args.rootNode, args.selectedNode, args.expandedNodes));
|
||||
this._viewModel.onPathValidate(args => this.handleOnValidate(args.succeeded, args.message));
|
||||
|
||||
@@ -39,6 +39,7 @@ import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { MenuRegistry, ExecuteCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
|
||||
const labelDisplay = nls.localize("insights.item", "Item");
|
||||
const valueDisplay = nls.localize("insights.value", "Value");
|
||||
@@ -131,9 +132,10 @@ export class InsightsDialogView extends Modal {
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@ICommandService private _commandService: ICommandService,
|
||||
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService
|
||||
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(nls.localize("InsightsDialogTitle", "Insights"), TelemetryKeys.Insights, partService, telemetryService, contextKeyService);
|
||||
super(nls.localize("InsightsDialogTitle", "Insights"), TelemetryKeys.Insights, partService, telemetryService, clipboardService, contextKeyService);
|
||||
this._model.onDataChange(e => this.build());
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,13 @@ export class TreeDataTemplate extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
public set enableCheckbox(value: boolean) {
|
||||
if (value === undefined) {
|
||||
value = true;
|
||||
}
|
||||
this._checkbox.disabled = !value;
|
||||
}
|
||||
|
||||
public get checkbox(): HTMLInputElement {
|
||||
return this._checkbox;
|
||||
}
|
||||
@@ -155,6 +162,7 @@ export class TreeComponentRenderer extends Disposable implements IRenderer {
|
||||
templateData.label.textContent = label;
|
||||
templateData.root.title = label;
|
||||
templateData.checkboxState = this.getCheckboxState(treeNode);
|
||||
templateData.enableCheckbox = treeNode.enabled;
|
||||
}
|
||||
|
||||
private getCheckboxState(treeNode: ITreeComponentItem): TreeCheckboxState {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { ServerGroupViewModel } from 'sql/parts/objectExplorer/serverGroupDialog
|
||||
import { attachButtonStyler, attachModalDialogStyler } from 'sql/common/theme/styler';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import * as TelemetryKeys from 'sql/common/telemetryKeys';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
|
||||
export class ServerGroupDialog extends Modal {
|
||||
private _bodyBuilder: Builder;
|
||||
@@ -53,9 +54,10 @@ export class ServerGroupDialog extends Modal {
|
||||
@IThemeService private _themeService: IThemeService,
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(localize('ServerGroupsDialogTitle', 'Server Groups'), TelemetryKeys.ServerGroups, partService, telemetryService, contextKeyService);
|
||||
super(localize('ServerGroupsDialogTitle', 'Server Groups'), TelemetryKeys.ServerGroups, partService, telemetryService, clipboardService, contextKeyService);
|
||||
}
|
||||
|
||||
public render() {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { IClipboardService } from 'sql/platform/clipboard/common/clipboardService';
|
||||
|
||||
class EventItem {
|
||||
|
||||
@@ -316,9 +317,10 @@ export class ProfilerColumnEditorDialog extends Modal {
|
||||
@IThemeService private _themeService: IThemeService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IContextViewService private _contextViewService: IContextViewService
|
||||
@IContextViewService private _contextViewService: IContextViewService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(nls.localize('profilerColumnDialog.profiler', 'Profiler'), TelemetryKeys.Profiler, _partService, telemetryService, contextKeyService);
|
||||
super(nls.localize('profilerColumnDialog.profiler', 'Profiler'), TelemetryKeys.Profiler, _partService, telemetryService, clipboardService, contextKeyService);
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
|
||||
@@ -74,8 +74,9 @@ export class MessagePanelState {
|
||||
}
|
||||
|
||||
export class MessagePanel extends ViewletPanel {
|
||||
private messageLineCountMap = new Map<IResultMessage, number>();
|
||||
private ds = new MessageDataSource();
|
||||
private renderer = new MessageRenderer();
|
||||
private renderer = new MessageRenderer(this.messageLineCountMap);
|
||||
private model = new Model();
|
||||
private controller: MessageController;
|
||||
private container = $('div message-tree').getHTMLElement();
|
||||
@@ -143,29 +144,40 @@ export class MessagePanel extends ViewletPanel {
|
||||
|
||||
private onMessage(message: IResultMessage | IResultMessage[]) {
|
||||
let hasError = false;
|
||||
let lines: number;
|
||||
if (isArray(message)) {
|
||||
hasError = message.find(e => e.isError) ? true : false;
|
||||
lines = message.reduce((currentTotal, resultMessage) => currentTotal + this.countMessageLines(resultMessage), 0);
|
||||
this.model.messages.push(...message);
|
||||
} else {
|
||||
hasError = message.isError;
|
||||
lines = this.countMessageLines(message);
|
||||
this.model.messages.push(message);
|
||||
}
|
||||
this.maximumBodySize += lines * 22;
|
||||
if (hasError) {
|
||||
this.setExpanded(true);
|
||||
}
|
||||
if (this.state.scrollPosition) {
|
||||
this.tree.refresh(this.model).then(() => {
|
||||
this.tree.setScrollPosition(1);
|
||||
// Restore the previous scroll position when switching between tabs
|
||||
this.tree.setScrollPosition(this.state.scrollPosition);
|
||||
});
|
||||
} else {
|
||||
const previousScrollPosition = this.tree.getScrollPosition();
|
||||
this.tree.refresh(this.model).then(() => {
|
||||
// Scroll to the end if the user was already at the end otherwise leave the current scroll position
|
||||
if (previousScrollPosition === 1) {
|
||||
this.tree.setScrollPosition(1);
|
||||
}
|
||||
});
|
||||
}
|
||||
this.maximumBodySize = this.model.messages.length * 22;
|
||||
}
|
||||
|
||||
private countMessageLines(resultMessage: IResultMessage): number {
|
||||
let lines = resultMessage.message.split('\n').length;
|
||||
this.messageLineCountMap.set(resultMessage, lines);
|
||||
return lines;
|
||||
}
|
||||
|
||||
private reset() {
|
||||
@@ -220,8 +232,15 @@ class MessageDataSource implements IDataSource {
|
||||
}
|
||||
|
||||
class MessageRenderer implements IRenderer {
|
||||
constructor(private messageLineCountMap: Map<IResultMessage, number>) {
|
||||
}
|
||||
|
||||
getHeight(tree: ITree, element: any): number {
|
||||
return 22;
|
||||
const lineHeight = 22;
|
||||
if (this.messageLineCountMap.has(element)) {
|
||||
return lineHeight * this.messageLineCountMap.get(element);
|
||||
}
|
||||
return lineHeight;
|
||||
}
|
||||
|
||||
getTemplateId(tree: ITree, element: any): string {
|
||||
@@ -258,7 +277,7 @@ class MessageRenderer implements IRenderer {
|
||||
renderElement(tree: ITree, element: IResultMessage, templateId: string, templateData: IMessageTemplate | IBatchTemplate): void {
|
||||
if (templateId === TemplateIds.MESSAGE || templateId === TemplateIds.ERROR) {
|
||||
let data: IMessageTemplate = templateData;
|
||||
data.message.innerText = element.message.replace(/(\r\n|\n|\r)/g, ' ');
|
||||
data.message.innerText = element.message;
|
||||
} else if (templateId === TemplateIds.BATCH) {
|
||||
let data = templateData as IBatchTemplate;
|
||||
data.timeStamp.innerText = element.time;
|
||||
|
||||
@@ -124,7 +124,7 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
try {
|
||||
// Create file path and file URI
|
||||
let objectName = schemaName ? schemaName + '.' + tableName : tableName;
|
||||
let filePath = this.createEditDataFileName(objectName);
|
||||
let filePath = this.createPrefixedSqlFilePath(objectName);
|
||||
let docUri: URI = URI.from({ scheme: Schemas.untitled, path: filePath });
|
||||
|
||||
// Create a sql document pane with accoutrements
|
||||
@@ -265,45 +265,26 @@ export class QueryEditorService implements IQueryEditorService {
|
||||
////// Private functions
|
||||
|
||||
private createUntitledSqlFilePath(): string {
|
||||
let sqlFileName = (counter: number): string => {
|
||||
return `${untitledFilePrefix}${counter}`;
|
||||
};
|
||||
|
||||
let counter = 1;
|
||||
// Get document name and check if it exists
|
||||
let filePath = sqlFileName(counter);
|
||||
while (fs.existsSync(filePath)) {
|
||||
counter++;
|
||||
filePath = sqlFileName(counter);
|
||||
}
|
||||
|
||||
// check if this document name already exists in any open documents
|
||||
let untitledEditors = this._untitledEditorService.getAll();
|
||||
while (untitledEditors.find(x => x.getName().toUpperCase() === filePath.toUpperCase())) {
|
||||
counter++;
|
||||
filePath = sqlFileName(counter);
|
||||
}
|
||||
|
||||
return filePath;
|
||||
return this.createPrefixedSqlFilePath(untitledFilePrefix);
|
||||
}
|
||||
|
||||
private createEditDataFileName(tableName: string): string {
|
||||
let editDataFileName = (counter: number): string => {
|
||||
return encodeURIComponent(`${tableName}_${counter}`);
|
||||
private createPrefixedSqlFilePath(prefix: string): string {
|
||||
let prefixFileName = (counter: number): string => {
|
||||
return `${prefix}_${counter}`;
|
||||
};
|
||||
|
||||
let counter = 1;
|
||||
// Get document name and check if it exists
|
||||
let filePath = editDataFileName(counter);
|
||||
let filePath = prefixFileName(counter);
|
||||
while (fs.existsSync(filePath)) {
|
||||
counter++;
|
||||
filePath = editDataFileName(counter);
|
||||
filePath = prefixFileName(counter);
|
||||
}
|
||||
|
||||
let untitledEditors = this._untitledEditorService.getAll();
|
||||
while (untitledEditors.find(x => x.getName().toUpperCase() === filePath.toUpperCase())) {
|
||||
counter++;
|
||||
filePath = editDataFileName(counter);
|
||||
filePath = prefixFileName(counter);
|
||||
}
|
||||
|
||||
return filePath;
|
||||
|
||||
@@ -45,6 +45,8 @@ export class QueryPlanView implements IPanelView {
|
||||
}
|
||||
|
||||
public layout(dimension: Dimension): void {
|
||||
this.container.style.width = dimension.width + 'px';
|
||||
this.container.style.height = dimension.height + 'px';
|
||||
}
|
||||
|
||||
public showPlan(xml: string) {
|
||||
|
||||
@@ -25,6 +25,7 @@ import { Emitter } from 'vs/base/common/event';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { DialogMessage, MessageLevel } from '../../workbench/api/common/sqlExtHostTypes';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
export class DialogModal extends Modal {
|
||||
private _dialogPane: DialogPane;
|
||||
@@ -43,9 +44,10 @@ export class DialogModal extends Modal {
|
||||
@IWorkbenchThemeService private _themeService: IWorkbenchThemeService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
) {
|
||||
super(_dialog.title, name, partService, telemetryService, contextKeyService, options);
|
||||
super(_dialog.title, name, partService, telemetryService, clipboardService, contextKeyService, options);
|
||||
}
|
||||
|
||||
public layout(): void {
|
||||
@@ -53,7 +55,7 @@ export class DialogModal extends Modal {
|
||||
}
|
||||
|
||||
public render() {
|
||||
super.render(true);
|
||||
super.render();
|
||||
attachModalDialogStyler(this, this._themeService);
|
||||
|
||||
if (this.backButton) {
|
||||
@@ -78,7 +80,7 @@ export class DialogModal extends Modal {
|
||||
|
||||
let messageChangeHandler = (message: DialogMessage) => {
|
||||
if (message && message.text) {
|
||||
this.setError(message.text, message.level);
|
||||
this.setError(message.text, message.level, message.description);
|
||||
} else {
|
||||
this.setError('');
|
||||
}
|
||||
|
||||
@@ -63,10 +63,8 @@ export class Dialog extends ModelViewPane {
|
||||
}
|
||||
|
||||
public set message(value: DialogMessage) {
|
||||
if (this._message && !value || !this._message && value || this._message && value && (this._message.level !== value.level || this._message.text !== value.text)) {
|
||||
this._message = value;
|
||||
this._onMessageChange.fire(this._message);
|
||||
}
|
||||
this._message = value;
|
||||
this._onMessageChange.fire(this._message);
|
||||
}
|
||||
|
||||
public registerCloseValidator(validator: () => boolean | Thenable<boolean>): void {
|
||||
@@ -255,9 +253,7 @@ export class Wizard {
|
||||
}
|
||||
|
||||
public set message(value: DialogMessage) {
|
||||
if (this._message && !value || !this._message && value || this._message && value && (this._message.level !== value.level || this._message.text !== value.text)) {
|
||||
this._message = value;
|
||||
this._onMessageChange.fire(this._message);
|
||||
}
|
||||
this._message = value;
|
||||
this._onMessageChange.fire(this._message);
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.dialogModal-hidden {
|
||||
|
||||
@@ -7,8 +7,7 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 80px;
|
||||
height: calc(100% + 25px);
|
||||
margin-top: -25px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.hc-black .wizardNavigation-container {
|
||||
@@ -24,7 +23,7 @@
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
max-height: 130px;
|
||||
max-height: 100px;
|
||||
}
|
||||
|
||||
.wizardNavigation-pageNumber a {
|
||||
|
||||
@@ -24,6 +24,7 @@ import { attachButtonStyler } from 'vs/platform/theme/common/styler';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
|
||||
export class WizardModal extends Modal {
|
||||
private _dialogPanes = new Map<WizardPage, DialogPane>();
|
||||
@@ -48,9 +49,10 @@ export class WizardModal extends Modal {
|
||||
@IWorkbenchThemeService private _themeService: IWorkbenchThemeService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService,
|
||||
@IInstantiationService private _instantiationService: IInstantiationService
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@IClipboardService clipboardService: IClipboardService
|
||||
) {
|
||||
super(_wizard.title, name, partService, telemetryService, contextKeyService, options);
|
||||
super(_wizard.title, name, partService, telemetryService, clipboardService, contextKeyService, options);
|
||||
}
|
||||
|
||||
public layout(): void {
|
||||
@@ -58,7 +60,7 @@ export class WizardModal extends Modal {
|
||||
}
|
||||
|
||||
public render() {
|
||||
super.render(true);
|
||||
super.render();
|
||||
attachModalDialogStyler(this, this._themeService);
|
||||
|
||||
if (this.backButton) {
|
||||
@@ -83,7 +85,7 @@ export class WizardModal extends Modal {
|
||||
|
||||
let messageChangeHandler = (message: DialogMessage) => {
|
||||
if (message && message.text) {
|
||||
this.setError(message.text, message.level);
|
||||
this.setError(message.text, message.level, message.description);
|
||||
} else {
|
||||
this.setError('');
|
||||
}
|
||||
|
||||
2
src/sql/sqlops.proposed.d.ts
vendored
@@ -58,6 +58,7 @@ declare module 'sqlops' {
|
||||
|
||||
export class TreeComponentItem extends vscode.TreeItem {
|
||||
checked?: boolean;
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface ComponentBuilder<T extends Component> {
|
||||
@@ -889,6 +890,7 @@ declare module 'sqlops' {
|
||||
*/
|
||||
export type DialogMessage = {
|
||||
readonly text: string,
|
||||
readonly description?: string,
|
||||
readonly level?: MessageLevel
|
||||
};
|
||||
|
||||
|
||||
@@ -245,6 +245,7 @@ export enum MessageLevel {
|
||||
export interface DialogMessage {
|
||||
text: string;
|
||||
level?: MessageLevel;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
/// Card-related APIs that need to be here to avoid early load issues
|
||||
|
||||
@@ -164,7 +164,7 @@ export class ExtHostTreeView<T> extends vsTreeExt.ExtHostTreeView<T> {
|
||||
|
||||
protected createTreeItem(element: T, extensionTreeItem: sqlops.TreeComponentItem, parent?: vsTreeExt.TreeNode): ITreeComponentItem {
|
||||
let item = super.createTreeItem(element, extensionTreeItem, parent);
|
||||
item = Object.assign({}, item, { checked: extensionTreeItem.checked });
|
||||
item = Object.assign({}, item, { checked: extensionTreeItem.checked, enabled: extensionTreeItem.enabled });
|
||||
return item;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import { ITreeViewDataProvider, ITreeItem } from 'vs/workbench/common/views';
|
||||
|
||||
export interface ITreeComponentItem extends ITreeItem {
|
||||
checked?: boolean;
|
||||
enabled?: boolean;
|
||||
onCheckedChanged?: (checked: boolean) => void;
|
||||
children?: ITreeComponentItem[];
|
||||
}
|
||||
|
||||
@@ -43,12 +43,12 @@ export class ErrorMessageDialog extends Modal {
|
||||
|
||||
constructor(
|
||||
@IThemeService private _themeService: IThemeService,
|
||||
@IClipboardService private _clipboardService: IClipboardService,
|
||||
@IClipboardService clipboardService: IClipboardService,
|
||||
@IPartService partService: IPartService,
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IContextKeyService contextKeyService: IContextKeyService
|
||||
) {
|
||||
super('', TelemetryKeys.ErrorMessage, partService, telemetryService, contextKeyService, { isFlyout: false, hasTitleIcon: true });
|
||||
super('', TelemetryKeys.ErrorMessage, partService, telemetryService, clipboardService, contextKeyService, { isFlyout: false, hasTitleIcon: true });
|
||||
this._okLabel = localize('errorMessageDialog.ok', 'OK');
|
||||
this._closeLabel = localize('errorMessageDialog.close', 'Close');
|
||||
}
|
||||
|
||||