Add SQL DB offline migration wizard experience (#20403)

* sql db wizard with target selection

* add database table selection

* add sqldb to service and IR page

* Code complete

* navigation bug fixes

* fix target db selection

* improve sqldb error and status reporting

* fix error count bug

* remove table status inference

* address review feedback

* update resource strings and content

* fix migraton status string, use localized value

* fix ux navigation issues

* fix back/fwd w/o changes from changing data
This commit is contained in:
brian-harris
2022-08-19 18:12:34 -07:00
committed by GitHub
parent c0b09dcedd
commit 7a736b76fa
42 changed files with 5716 additions and 4209 deletions

View File

@@ -0,0 +1,125 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import * as vscode from 'vscode';
import * as loc from '../constants/strings';
export interface ErrorEvent {
connectionId: string;
title: string;
label: string;
message: string;
}
export class DashboardStatusBar implements vscode.Disposable {
private _errorTitle: string = '';
private _errorLabel: string = '';
private _errorDescription: string = '';
private _errorDialogIsOpen: boolean = false;
private _statusInfoBox: azdata.InfoBoxComponent;
private _context: vscode.ExtensionContext;
private _errorEvent: vscode.EventEmitter<ErrorEvent> = new vscode.EventEmitter<ErrorEvent>();
private _disposables: vscode.Disposable[] = [];
constructor(context: vscode.ExtensionContext, connectionId: string, statusInfoBox: azdata.InfoBoxComponent, errorEvent: vscode.EventEmitter<ErrorEvent>) {
this._context = context;
this._statusInfoBox = statusInfoBox;
this._errorEvent = errorEvent;
this._disposables.push(
this._errorEvent.event(
async (e) => {
if (e.connectionId === connectionId) {
return (e.title.length > 0 && e.label.length > 0)
? await this.showError(e.title, e.label, e.message)
: await this.clearError();
}
}));
}
dispose() {
this._disposables.forEach(
d => { try { d.dispose(); } catch { } });
}
public async showError(errorTitle: string, errorLabel: string, errorDescription: string): Promise<void> {
this._errorTitle = errorTitle;
this._errorLabel = errorLabel;
this._errorDescription = errorDescription;
this._statusInfoBox.style = 'error';
this._statusInfoBox.text = errorTitle;
this._statusInfoBox.ariaLabel = errorTitle;
await this._updateStatusDisplay(this._statusInfoBox, true);
}
public async clearError(): Promise<void> {
await this._updateStatusDisplay(this._statusInfoBox, false);
this._errorTitle = '';
this._errorLabel = '';
this._errorDescription = '';
this._statusInfoBox.style = 'success';
this._statusInfoBox.text = '';
}
public async openErrorDialog(): Promise<void> {
if (this._errorDialogIsOpen) {
return;
}
try {
const tab = azdata.window.createTab(this._errorTitle);
tab.registerContent(async (view) => {
const flex = view.modelBuilder.flexContainer()
.withItems([
view.modelBuilder.text()
.withProps({ value: this._errorLabel, CSSStyles: { 'margin': '0px 0px 5px 5px' } })
.component(),
view.modelBuilder.inputBox()
.withProps({
value: this._errorDescription,
readOnly: true,
multiline: true,
height: 400,
inputType: 'text',
display: 'inline-block',
CSSStyles: { 'overflow': 'hidden auto', 'margin': '0px 0px 0px 5px' },
})
.component()])
.withLayout({ flexFlow: 'column', width: 420, })
.withProps({ CSSStyles: { 'margin': '0 10px 0 10px' } })
.component();
await view.initializeModel(flex);
});
const dialog = azdata.window.createModelViewDialog(
this._errorTitle,
'errorDialog',
450,
'flyout');
dialog.content = [tab];
dialog.okButton.label = loc.ERROR_DIALOG_CLEAR_BUTTON_LABEL;
dialog.okButton.focused = true;
dialog.cancelButton.label = loc.CLOSE;
this._context.subscriptions.push(
dialog.onClosed(async e => {
if (e === 'ok') {
await this.clearError();
}
this._errorDialogIsOpen = false;
}));
azdata.window.openDialog(dialog);
} catch (error) {
this._errorDialogIsOpen = false;
}
}
private async _updateStatusDisplay(control: azdata.Component, visible: boolean): Promise<void> {
await control.updateCssStyles({ 'display': visible ? 'inline' : 'none' });
}
}