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

@@ -9,25 +9,28 @@ import * as constants from '../../constants/strings';
import { MigrationStateModel } from '../../models/stateMachine';
import { WizardController } from '../../wizard/wizardController';
import * as styles from '../../constants/styles';
import { ServiceContextChangeEvent } from '../../dashboard/tabBase';
export class SavedAssessmentDialog {
private static readonly OkButtonText: string = constants.NEXT_LABEL;
private static readonly CancelButtonText: string = constants.CANCEL_LABEL;
private _isOpen: boolean = false;
private dialog: azdata.window.Dialog | undefined;
private _rootContainer!: azdata.FlexContainer;
private stateModel: MigrationStateModel;
private context: vscode.ExtensionContext;
private _serviceContextChangedEvent: vscode.EventEmitter<ServiceContextChangeEvent>;
private _disposables: vscode.Disposable[] = [];
private _isOpen: boolean = false;
private _rootContainer!: azdata.FlexContainer;
constructor(
context: vscode.ExtensionContext,
stateModel: MigrationStateModel,
private readonly _onClosedCallback: () => Promise<void>) {
serviceContextChangedEvent: vscode.EventEmitter<ServiceContextChangeEvent>) {
this.stateModel = stateModel;
this.context = context;
this._serviceContextChangedEvent = serviceContextChangedEvent;
}
private async initializeDialog(dialog: azdata.window.Dialog): Promise<void> {
@@ -36,18 +39,18 @@ export class SavedAssessmentDialog {
try {
this._rootContainer = this.initializePageContent(view);
await view.initializeModel(this._rootContainer);
this._disposables.push(dialog.okButton.onClick(async e => {
await this.execute();
}));
this._disposables.push(dialog.cancelButton.onClick(e => {
this.cancel();
}));
this._disposables.push(
dialog.okButton.onClick(
async e => await this.execute()));
this._disposables.push(
dialog.cancelButton.onClick(
e => this.cancel()));
this._disposables.push(
view.onClosed(
e => this._disposables.forEach(
d => { try { d.dispose(); } catch { } })));
this._disposables.push(view.onClosed(e => {
this._disposables.forEach(
d => { try { d.dispose(); } catch { } }
);
}));
resolve();
} catch (ex) {
reject(ex);
@@ -83,7 +86,7 @@ export class SavedAssessmentDialog {
const wizardController = new WizardController(
this.context,
this.stateModel,
this._onClosedCallback);
this._serviceContextChangedEvent);
await wizardController.openWizard(this.stateModel.sourceConnectionId);
this._isOpen = false;
@@ -100,44 +103,39 @@ export class SavedAssessmentDialog {
public initializePageContent(view: azdata.ModelView): azdata.FlexContainer {
const buttonGroup = 'resumeMigration';
const radioStart = view.modelBuilder.radioButton().withProps({
label: constants.START_NEW_SESSION,
name: buttonGroup,
CSSStyles: {
...styles.BODY_CSS,
'margin-bottom': '8px'
},
checked: true
}).component();
const radioStart = view.modelBuilder.radioButton()
.withProps({
label: constants.START_NEW_SESSION,
name: buttonGroup,
CSSStyles: { ...styles.BODY_CSS, 'margin-bottom': '8px' },
checked: true
}).component();
this._disposables.push(radioStart.onDidChangeCheckedState((e) => {
if (e) {
this.stateModel.resumeAssessment = false;
}
}));
const radioContinue = view.modelBuilder.radioButton().withProps({
label: constants.RESUME_SESSION,
name: buttonGroup,
CSSStyles: {
...styles.BODY_CSS,
},
checked: false
}).component();
this._disposables.push(
radioStart.onDidChangeCheckedState(checked => {
if (checked) {
this.stateModel.resumeAssessment = false;
}
}));
const radioContinue = view.modelBuilder.radioButton()
.withProps({
label: constants.RESUME_SESSION,
name: buttonGroup,
CSSStyles: { ...styles.BODY_CSS },
checked: false
}).component();
this._disposables.push(radioContinue.onDidChangeCheckedState((e) => {
if (e) {
this.stateModel.resumeAssessment = true;
}
}));
this._disposables.push(
radioContinue.onDidChangeCheckedState(checked => {
if (checked) {
this.stateModel.resumeAssessment = true;
}
}));
const flex = view.modelBuilder.flexContainer()
.withLayout({
flexFlow: 'column',
}).withProps({
CSSStyles: {
'padding': '20px 15px',
}
}).component();
.withLayout({ flexFlow: 'column', })
.withProps({ CSSStyles: { 'padding': '20px 15px', } })
.component();
flex.addItem(radioStart, { flex: '0 0 auto' });
flex.addItem(radioContinue, { flex: '0 0 auto' });