mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Add wizard sidebar navigation (#1911)
This commit is contained in:
@@ -13,6 +13,7 @@ import { CommonModule, APP_BASE_HREF } from '@angular/common';
|
|||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
|
||||||
import { DialogContainer } from 'sql/platform/dialog/dialogContainer.component';
|
import { DialogContainer } from 'sql/platform/dialog/dialogContainer.component';
|
||||||
|
import { WizardNavigation } from 'sql/platform/dialog/wizardNavigation.component';
|
||||||
import { Extensions, IComponentRegistry } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
import { Extensions, IComponentRegistry } from 'sql/platform/dashboard/common/modelComponentRegistry';
|
||||||
import { ModelViewContent } from 'sql/parts/modelComponents/modelViewContent.component';
|
import { ModelViewContent } from 'sql/parts/modelComponents/modelViewContent.component';
|
||||||
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
|
import { ModelComponentWrapper } from 'sql/parts/modelComponents/modelComponentWrapper.component';
|
||||||
@@ -37,12 +38,13 @@ export const DialogModule = (params, selector: string, instantiationService: IIn
|
|||||||
SelectBox,
|
SelectBox,
|
||||||
InputBox,
|
InputBox,
|
||||||
DialogContainer,
|
DialogContainer,
|
||||||
|
WizardNavigation,
|
||||||
ModelViewContent,
|
ModelViewContent,
|
||||||
ModelComponentWrapper,
|
ModelComponentWrapper,
|
||||||
ComponentHostDirective,
|
ComponentHostDirective,
|
||||||
...extensionComponents
|
...extensionComponents
|
||||||
],
|
],
|
||||||
entryComponents: [DialogContainer, ...extensionComponents],
|
entryComponents: [DialogContainer, WizardNavigation, ...extensionComponents],
|
||||||
imports: [
|
imports: [
|
||||||
FormsModule,
|
FormsModule,
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -65,7 +67,8 @@ export const DialogModule = (params, selector: string, instantiationService: IIn
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngDoBootstrap(appRef: ApplicationRef) {
|
ngDoBootstrap(appRef: ApplicationRef) {
|
||||||
const factoryWrapper: any = this._resolver.resolveComponentFactory(DialogContainer);
|
let componentClass = this.selector.startsWith(WizardNavigation.SELECTOR) ? WizardNavigation : DialogContainer;
|
||||||
|
const factoryWrapper: any = this._resolver.resolveComponentFactory<WizardNavigation | DialogContainer>(componentClass);
|
||||||
factoryWrapper.factory.selector = this.selector;
|
factoryWrapper.factory.selector = this.selector;
|
||||||
appRef.bootstrap(factoryWrapper);
|
appRef.bootstrap(factoryWrapper);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
.dialogModal-body {
|
.dialogModal-body {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
min-width: 500px;
|
min-width: 500px;
|
||||||
|
|||||||
94
src/sql/platform/dialog/media/wizardNavigation.css
Normal file
94
src/sql/platform/dialog/media/wizardNavigation.css
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.wizardNavigation-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 80px;
|
||||||
|
height: calc(100% + 25px);
|
||||||
|
margin-top: -25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hc-black .wizardNavigation-container {
|
||||||
|
border-right-color: #2b56f2;
|
||||||
|
border-right-style: solid;
|
||||||
|
border-right-width: 1px;
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizardNavigation-pageNumber {
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
max-height: 130px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizardNavigation-pageNumber a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizardNavigation-dot {
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
background-color: rgb(200, 200, 200);
|
||||||
|
color: white;
|
||||||
|
border-radius: 50%;
|
||||||
|
border-style: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hc-black .wizardNavigation-dot {
|
||||||
|
flex-grow: 1;
|
||||||
|
background-color: unset;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 1px;
|
||||||
|
border-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizardNavigation-connector {
|
||||||
|
width: 3px;
|
||||||
|
display: inline-block;
|
||||||
|
flex-grow: 1;
|
||||||
|
background-color: rgb(200, 200, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hc-black .wizardNavigation-connector {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizardNavigation-connector.active,
|
||||||
|
.wizardNavigation-dot.active {
|
||||||
|
background-color: rgb(9, 109, 201);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hc-black .wizardNavigation-dot.active {
|
||||||
|
border-color: #2b56f2;
|
||||||
|
background-color: unset;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hc-black .wizardNavigation-dot.active:hover,
|
||||||
|
.hc-black .wizardNavigation-dot.active.currentPage:hover {
|
||||||
|
border-color: #F38518;
|
||||||
|
border-style: dashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizardNavigation-dot.active.currentPage {
|
||||||
|
border-style: double;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hc-black .wizardNavigation-dot.active.currentPage {
|
||||||
|
border-style: solid;
|
||||||
|
border-color: #F38518;
|
||||||
|
}
|
||||||
|
|
||||||
|
.wizardNavigation-connector.invisible {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
@@ -8,23 +8,22 @@
|
|||||||
import 'vs/css!./media/dialogModal';
|
import 'vs/css!./media/dialogModal';
|
||||||
import { Modal, IModalOptions } from 'sql/base/browser/ui/modal/modal';
|
import { Modal, IModalOptions } from 'sql/base/browser/ui/modal/modal';
|
||||||
import { attachModalDialogStyler } from 'sql/common/theme/styler';
|
import { attachModalDialogStyler } from 'sql/common/theme/styler';
|
||||||
import { Wizard, Dialog, DialogButton, WizardPage } from 'sql/platform/dialog/dialogTypes';
|
import { Wizard, DialogButton, WizardPage } from 'sql/platform/dialog/dialogTypes';
|
||||||
import { DialogPane } from 'sql/platform/dialog/dialogPane';
|
import { DialogPane } from 'sql/platform/dialog/dialogPane';
|
||||||
import { bootstrapAngular } from 'sql/services/bootstrap/bootstrapService';
|
import { bootstrapAngular } from 'sql/services/bootstrap/bootstrapService';
|
||||||
|
import { DialogMessage } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
import { DialogModule } from 'sql/platform/dialog/dialog.module';
|
||||||
import { Button } from 'vs/base/browser/ui/button/button';
|
import { Button } from 'vs/base/browser/ui/button/button';
|
||||||
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||||
import { Builder } from 'vs/base/browser/builder';
|
import { Builder } from 'vs/base/browser/builder';
|
||||||
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
import { IPartService } from 'vs/workbench/services/part/common/partService';
|
||||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
|
||||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||||
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
|
import { attachButtonStyler } from 'vs/platform/theme/common/styler';
|
||||||
import { localize } from 'vs/nls';
|
|
||||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
import { Emitter } from 'vs/base/common/event';
|
import { Emitter } from 'vs/base/common/event';
|
||||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||||
import { DialogMessage, MessageLevel } from '../../workbench/api/common/sqlExtHostTypes';
|
|
||||||
|
|
||||||
export class WizardModal extends Modal {
|
export class WizardModal extends Modal {
|
||||||
private _dialogPanes = new Map<WizardPage, DialogPane>();
|
private _dialogPanes = new Map<WizardPage, DialogPane>();
|
||||||
@@ -128,6 +127,8 @@ export class WizardModal extends Modal {
|
|||||||
this._body = bodyBuilder.getHTMLElement();
|
this._body = bodyBuilder.getHTMLElement();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.initializeNavigation(this._body);
|
||||||
|
|
||||||
this._wizard.pages.forEach(page => {
|
this._wizard.pages.forEach(page => {
|
||||||
this.registerPage(page);
|
this.registerPage(page);
|
||||||
});
|
});
|
||||||
@@ -201,6 +202,22 @@ export class WizardModal extends Modal {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bootstrap angular for the wizard's left nav bar
|
||||||
|
*/
|
||||||
|
private initializeNavigation(bodyContainer: HTMLElement) {
|
||||||
|
bootstrapAngular(this._instantiationService,
|
||||||
|
DialogModule,
|
||||||
|
bodyContainer,
|
||||||
|
'wizard-navigation',
|
||||||
|
{
|
||||||
|
wizard: this._wizard,
|
||||||
|
navigationHandler: (index: number) => this.showPage(index, index > this._wizard.currentPage)
|
||||||
|
},
|
||||||
|
undefined,
|
||||||
|
() => undefined);
|
||||||
|
}
|
||||||
|
|
||||||
public open(): void {
|
public open(): void {
|
||||||
this.showPage(0, false);
|
this.showPage(0, false);
|
||||||
this.show();
|
this.show();
|
||||||
|
|||||||
91
src/sql/platform/dialog/wizardNavigation.component.ts
Normal file
91
src/sql/platform/dialog/wizardNavigation.component.ts
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.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
import 'vs/css!./media/wizardNavigation';
|
||||||
|
import { Component, Inject, forwardRef, ElementRef, AfterViewInit, ChangeDetectorRef, ViewChild } from '@angular/core';
|
||||||
|
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
|
||||||
|
import { Event, Emitter } from 'vs/base/common/event';
|
||||||
|
import { Wizard } from './dialogTypes';
|
||||||
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
|
import { attachStyler } from 'vs/platform/theme/common/styler';
|
||||||
|
import { SIDE_BAR_BACKGROUND } from 'vs/workbench/common/theme';
|
||||||
|
|
||||||
|
export class WizardNavigationParams implements IBootstrapParams {
|
||||||
|
wizard: Wizard;
|
||||||
|
navigationHandler: (index: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: WizardNavigation.SELECTOR,
|
||||||
|
providers: [],
|
||||||
|
template: `
|
||||||
|
<div #container class="wizardNavigation-container">
|
||||||
|
<ng-container *ngFor="let item of _params.wizard.pages; let i = index">
|
||||||
|
<div class="wizardNavigation-pageNumber">
|
||||||
|
<div class="wizardNavigation-connector" [ngClass]="{'invisible': !hasTopConnector(i), 'active': isActive(i)}"></div>
|
||||||
|
<a [attr.href]="isActive(i) ? '' : null" [title]="item.title">
|
||||||
|
<span class="wizardNavigation-dot" [ngClass]="{'active': isActive(i), 'currentPage': isCurrentPage(i)}" (click)="navigate(i)">{{i+1}}</span>
|
||||||
|
</a>
|
||||||
|
<div class="wizardNavigation-connector" [ngClass]="{'invisible': !hasBottomConnector(i), 'active': isActive(i)}"></div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
export class WizardNavigation implements AfterViewInit {
|
||||||
|
public static readonly SELECTOR = 'wizard-navigation';
|
||||||
|
|
||||||
|
private _onResize = new Emitter<void>();
|
||||||
|
public readonly onResize: Event<void> = this._onResize.event;
|
||||||
|
|
||||||
|
@ViewChild('container', { read: ElementRef }) private _container: ElementRef;
|
||||||
|
constructor(
|
||||||
|
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
|
||||||
|
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef,
|
||||||
|
@Inject(IBootstrapParams) private _params: WizardNavigationParams,
|
||||||
|
@Inject(IWorkbenchThemeService) private _themeService: IWorkbenchThemeService) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngAfterViewInit() {
|
||||||
|
this._themeService.onThemeChange(() => this.style());
|
||||||
|
this.style();
|
||||||
|
this._params.wizard.onPageChanged(() => this._changeRef.detectChanges());
|
||||||
|
}
|
||||||
|
|
||||||
|
hasTopConnector(index: number): boolean {
|
||||||
|
return index > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasBottomConnector(index: number): boolean {
|
||||||
|
return index + 1 !== this._params.wizard.pages.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
isActive(index: number): boolean {
|
||||||
|
return index <= this._params.wizard.currentPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
isCurrentPage(index: number): boolean {
|
||||||
|
return index === this._params.wizard.currentPage;
|
||||||
|
}
|
||||||
|
|
||||||
|
navigate(index: number): void {
|
||||||
|
if (this.isActive(index)) {
|
||||||
|
this._params.navigationHandler(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private style(): void {
|
||||||
|
let theme = this._themeService.getTheme();
|
||||||
|
let navigationBackgroundColor = theme.getColor(SIDE_BAR_BACKGROUND);
|
||||||
|
if (theme.type === 'light') {
|
||||||
|
navigationBackgroundColor = navigationBackgroundColor.lighten(0.03);
|
||||||
|
} else if (theme.type === 'dark') {
|
||||||
|
navigationBackgroundColor = navigationBackgroundColor.darken(0.03);
|
||||||
|
}
|
||||||
|
(this._container.nativeElement as HTMLElement).style.backgroundColor = navigationBackgroundColor.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user