Angular Individual Service Injection - Decouple bootstrap service (#1457)

* change services to be individually injected into angular

* messing around with injection

* change angular bootstrapping to factory style

* formatting

* formatting

* fix imports

* fix build errors

* fix testsw

* fix tests

* fix compile errors
This commit is contained in:
Anthony Dresser
2018-05-23 16:51:02 -07:00
committed by GitHub
parent cd0f9b71c5
commit 1359354387
68 changed files with 1011 additions and 1116 deletions

View File

@@ -19,8 +19,9 @@ import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import * as BackupConstants from 'sql/parts/disasterRecovery/backup/constants';
import { IBackupService, IBackupUiService, TaskExecutionMode } from 'sql/parts/disasterRecovery/backup/common/backupService';
import FileValidationConstants = require('sql/parts/fileBrowser/common/fileValidationServiceConstants');
import { DashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams';
import { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/bootstrapService';
import { IDashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams';
import { IFileBrowserDialogController } from 'sql/parts/fileBrowser/common/interfaces';
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
import { MessageType } from 'vs/base/browser/ui/inputbox/inputBox';
import * as lifecycle from 'vs/base/common/lifecycle';
@@ -30,6 +31,9 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import * as types from 'vs/base/common/types';
import * as strings from 'vs/base/common/strings';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
export const BACKUP_SELECTOR: string = 'backup-component';
@@ -143,8 +147,6 @@ export class BackupComponent {
private localizedStrings = LocalizedStrings;
private _backupService: IBackupService;
private _backupUiService: IBackupUiService;
private _uri: string;
private _toDispose: lifecycle.IDisposable[] = [];
private _advancedHeaderSize = 32;
@@ -199,10 +201,14 @@ export class BackupComponent {
constructor(
@Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
@Inject(forwardRef(() => ChangeDetectorRef)) private _changeDetectorRef: ChangeDetectorRef,
@Inject(BOOTSTRAP_SERVICE_ID) private _bootstrapService: IBootstrapService,
@Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService,
@Inject(IContextViewService) private contextViewService: IContextViewService,
@Inject(IFileBrowserDialogController) private fileBrowserDialogService: IFileBrowserDialogController,
@Inject(IBackupUiService) private _backupUiService: IBackupUiService,
@Inject(IBackupService) private _backupService: IBackupService,
@Inject(IClipboardService) private clipboardService: IClipboardService,
@Inject(IConnectionManagementService) private connectionManagementService: IConnectionManagementService
) {
this._backupService = _bootstrapService.backupService;
this._backupUiService = _bootstrapService.backupUiService;
this._backupUiService.onShowBackupEvent((param) => this.onGetBackupConfigInfo(param));
}
@@ -210,12 +216,12 @@ export class BackupComponent {
let self = this;
this.addFooterButtons();
this.recoveryBox = new InputBox(this.recoveryModelElement.nativeElement, this._bootstrapService.contextViewService, {
this.recoveryBox = new InputBox(this.recoveryModelElement.nativeElement, this.contextViewService, {
placeholder: this.recoveryModel,
ariaLabel: LocalizedStrings.RECOVERY_MODEL
});
// Set backup type
this.backupTypeSelectBox = new SelectBox([], '', this._bootstrapService.contextViewService);
this.backupTypeSelectBox = new SelectBox([], '', this.contextViewService);
this.backupTypeSelectBox.render(this.backupTypeElement.nativeElement);
// Set copy-only check box
@@ -259,12 +265,12 @@ export class BackupComponent {
});
// Set backup name
this.backupNameBox = new InputBox(this.backupNameElement.nativeElement, this._bootstrapService.contextViewService, {
this.backupNameBox = new InputBox(this.backupNameElement.nativeElement, this.contextViewService, {
ariaLabel: LocalizedStrings.BACKUP_NAME
});
// Set backup path list
this.pathListBox = new ListBox([], '', this._bootstrapService.contextViewService, this._bootstrapService.clipboardService);
this.pathListBox = new ListBox([], '', this.contextViewService, this.clipboardService);
this.pathListBox.render(this.pathElement.nativeElement);
// Set backup path add/remove buttons
@@ -277,18 +283,18 @@ export class BackupComponent {
this.removePathButton.title = localize('removeFile', 'Remove files');
// Set compression
this.compressionSelectBox = new SelectBox(this.compressionOptions, this.compressionOptions[0], this._bootstrapService.contextViewService);
this.compressionSelectBox = new SelectBox(this.compressionOptions, this.compressionOptions[0], this.contextViewService);
this.compressionSelectBox.render(this.compressionElement.nativeElement);
// Set encryption
this.algorithmSelectBox = new SelectBox(this.encryptionAlgorithms, this.encryptionAlgorithms[0], this._bootstrapService.contextViewService);
this.algorithmSelectBox = new SelectBox(this.encryptionAlgorithms, this.encryptionAlgorithms[0], this.contextViewService);
this.algorithmSelectBox.render(this.encryptionAlgorithmElement.nativeElement);
this.encryptorSelectBox = new SelectBox([], '', this._bootstrapService.contextViewService);
this.encryptorSelectBox = new SelectBox([], '', this.contextViewService);
this.encryptorSelectBox.render(this.encryptorElement.nativeElement);
// Set media
this.mediaNameBox = new InputBox(this.mediaNameElement.nativeElement,
this._bootstrapService.contextViewService,
this.contextViewService,
{
validationOptions: {
validation: (value: string) => !value ? ({ type: MessageType.ERROR, content: LocalizedStrings.MEDIA_NAME_REQUIRED_ERROR }) : null
@@ -297,14 +303,14 @@ export class BackupComponent {
}
);
this.mediaDescriptionBox = new InputBox(this.mediaDescriptionElement.nativeElement, this._bootstrapService.contextViewService, {
this.mediaDescriptionBox = new InputBox(this.mediaDescriptionElement.nativeElement, this.contextViewService, {
ariaLabel: LocalizedStrings.NEW_MEDIA_SET_DESCRIPTION
});
// Set backup retain days
let invalidInputMessage = localize('backupComponent.invalidInput', 'Invalid input. Value must be greater than or equal 0.');
this.backupRetainDaysBox = new InputBox(this.backupDaysElement.nativeElement,
this._bootstrapService.contextViewService,
this.contextViewService,
{
placeholder: '0',
type: 'number',
@@ -387,21 +393,21 @@ export class BackupComponent {
this.scriptButton = new Button(this.scriptButtonElement.nativeElement);
this.scriptButton.label = localize('backupComponent.script', 'Script');
this.addButtonClickHandler(this.scriptButton, () => this.onScript());
this._toDispose.push(attachButtonStyler(this.scriptButton, this._bootstrapService.themeService));
this._toDispose.push(attachButtonStyler(this.scriptButton, this.themeService));
this.scriptButton.enabled = false;
// Set backup footer button
this.backupButton = new Button(this.backupButtonElement.nativeElement);
this.backupButton.label = localize('backupComponent.backup', 'Backup');
this.addButtonClickHandler(this.backupButton, () => this.onOk());
this._toDispose.push(attachButtonStyler(this.backupButton, this._bootstrapService.themeService));
this._toDispose.push(attachButtonStyler(this.backupButton, this.themeService));
this.backupEnabled = false;
// Set cancel footer button
this.cancelButton = new Button(this.cancelButtonElement.nativeElement);
this.cancelButton.label = localize('backupComponent.cancel', 'Cancel');
this.addButtonClickHandler(this.cancelButton, () => this.onCancel());
this._toDispose.push(attachButtonStyler(this.cancelButton, this._bootstrapService.themeService));
this._toDispose.push(attachButtonStyler(this.cancelButton, this.themeService));
}
private initialize(isMetadataPopulated: boolean): void {
@@ -505,18 +511,18 @@ export class BackupComponent {
private registerListeners(): void {
// Theme styler
this._toDispose.push(attachInputBoxStyler(this.backupNameBox, this._bootstrapService.themeService));
this._toDispose.push(attachInputBoxStyler(this.recoveryBox, this._bootstrapService.themeService));
this._toDispose.push(attachSelectBoxStyler(this.backupTypeSelectBox, this._bootstrapService.themeService));
this._toDispose.push(attachListBoxStyler(this.pathListBox, this._bootstrapService.themeService));
this._toDispose.push(attachButtonStyler(this.addPathButton, this._bootstrapService.themeService));
this._toDispose.push(attachButtonStyler(this.removePathButton, this._bootstrapService.themeService));
this._toDispose.push(attachSelectBoxStyler(this.compressionSelectBox, this._bootstrapService.themeService));
this._toDispose.push(attachSelectBoxStyler(this.algorithmSelectBox, this._bootstrapService.themeService));
this._toDispose.push(attachSelectBoxStyler(this.encryptorSelectBox, this._bootstrapService.themeService));
this._toDispose.push(attachInputBoxStyler(this.mediaNameBox, this._bootstrapService.themeService));
this._toDispose.push(attachInputBoxStyler(this.mediaDescriptionBox, this._bootstrapService.themeService));
this._toDispose.push(attachInputBoxStyler(this.backupRetainDaysBox, this._bootstrapService.themeService));
this._toDispose.push(attachInputBoxStyler(this.backupNameBox, this.themeService));
this._toDispose.push(attachInputBoxStyler(this.recoveryBox, this.themeService));
this._toDispose.push(attachSelectBoxStyler(this.backupTypeSelectBox, this.themeService));
this._toDispose.push(attachListBoxStyler(this.pathListBox, this.themeService));
this._toDispose.push(attachButtonStyler(this.addPathButton, this.themeService));
this._toDispose.push(attachButtonStyler(this.removePathButton, this.themeService));
this._toDispose.push(attachSelectBoxStyler(this.compressionSelectBox, this.themeService));
this._toDispose.push(attachSelectBoxStyler(this.algorithmSelectBox, this.themeService));
this._toDispose.push(attachSelectBoxStyler(this.encryptorSelectBox, this.themeService));
this._toDispose.push(attachInputBoxStyler(this.mediaNameBox, this.themeService));
this._toDispose.push(attachInputBoxStyler(this.mediaDescriptionBox, this.themeService));
this._toDispose.push(attachInputBoxStyler(this.backupRetainDaysBox, this.themeService));
this._toDispose.push(this.backupTypeSelectBox.onDidSelect(selected => this.onBackupTypeChanged()));
this.addButtonClickHandler(this.addPathButton, () => this.onAddClick());
@@ -528,7 +534,7 @@ export class BackupComponent {
this.backupRetainDaysChanged(days);
}));
this._toDispose.push(this._bootstrapService.themeService.onDidColorThemeChange(e => this.updateTheme()));
this._toDispose.push(this.themeService.onDidColorThemeChange(e => this.updateTheme()));
}
// Update theming that is specific to backup dialog
@@ -566,7 +572,7 @@ export class BackupComponent {
private onCancel(): void {
this.close();
this._bootstrapService.connectionManagementService.disconnect(this._uri);
this.connectionManagementService.disconnect(this._uri);
}
private close(): void {
@@ -629,7 +635,7 @@ export class BackupComponent {
}
private onAddClick(): void {
this._bootstrapService.fileBrowserDialogService.showDialog(this._uri,
this.fileBrowserDialogService.showDialog(this._uri,
this.defaultNewBackupFolder,
BackupConstants.fileFiltersSet,
FileValidationConstants.backup,

View File

@@ -3,43 +3,50 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ApplicationRef, ComponentFactoryResolver, ModuleWithProviders, NgModule,
Inject, forwardRef } from '@angular/core';
import {
ApplicationRef, ComponentFactoryResolver, ModuleWithProviders, NgModule,
Inject, forwardRef, Type
} from '@angular/core';
import { APP_BASE_HREF, CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { IBootstrapService, BOOTSTRAP_SERVICE_ID } from 'sql/services/bootstrap/bootstrapService';
import { IBootstrapParams } from 'sql/services/bootstrap/bootstrapService';
import { BackupComponent, BACKUP_SELECTOR } from 'sql/parts/disasterRecovery/backup/backup.component';
// work around
const BrowserAnimationsModule = (<any> require.__$__nodeRequire('@angular/platform-browser/animations')).BrowserAnimationsModule;
const BrowserAnimationsModule = (<any>require.__$__nodeRequire('@angular/platform-browser/animations')).BrowserAnimationsModule;
// Backup wizard main angular module
@NgModule({
declarations: [
BackupComponent
],
entryComponents: [BackupComponent],
imports: [
FormsModule,
CommonModule,
BrowserModule,
BrowserAnimationsModule,
],
providers: [{ provide: APP_BASE_HREF, useValue: '/' }]
})
export class BackupModule {
export const BackupModule = (params: IBootstrapParams, selector: string): Type<any> => {
@NgModule({
declarations: [
BackupComponent
],
entryComponents: [BackupComponent],
imports: [
FormsModule,
CommonModule,
BrowserModule,
BrowserAnimationsModule,
],
providers: [
{ provide: APP_BASE_HREF, useValue: '/' },
{ provide: IBootstrapParams, useValue: params }
]
})
class ModuleClass {
constructor(
@Inject(forwardRef(() => ComponentFactoryResolver)) private _resolver: ComponentFactoryResolver,
@Inject(BOOTSTRAP_SERVICE_ID) private _bootstrapService: IBootstrapService
) {
constructor(
@Inject(forwardRef(() => ComponentFactoryResolver)) private _resolver: ComponentFactoryResolver
) {
}
ngDoBootstrap(appRef: ApplicationRef) {
const factory = this._resolver.resolveComponentFactory(BackupComponent);
(<any>factory).factory.selector = selector;
appRef.bootstrap(factory);
}
}
ngDoBootstrap(appRef: ApplicationRef) {
const factory = this._resolver.resolveComponentFactory(BackupComponent);
const uniqueSelector: string = this._bootstrapService.getUniqueSelector(BACKUP_SELECTOR);
(<any>factory).factory.selector = uniqueSelector;
appRef.bootstrap(factory);
}
}
return ModuleClass;
};

View File

@@ -7,7 +7,6 @@ import { Modal } from 'sql/base/browser/ui/modal/modal';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { BackupModule } from 'sql/parts/disasterRecovery/backup/backup.module';
import { BACKUP_SELECTOR } from 'sql/parts/disasterRecovery/backup/backup.component';
import { IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
import { attachModalDialogStyler } from 'sql/common/theme/styler';
import { IConnectionManagementService } from 'sql/parts/connection/common/connectionManagement';
import * as TelemetryKeys from 'sql/common/telemetryKeys';
@@ -17,6 +16,8 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IPartService } from 'vs/workbench/services/part/common/partService';
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';
export class BackupDialog extends Modal {
private _bodyBuilder: Builder;
@@ -25,12 +26,12 @@ export class BackupDialog extends Modal {
private _moduleRef: any;
constructor(
@IBootstrapService private _bootstrapService: IBootstrapService,
@IThemeService private _themeService: IThemeService,
@IPartService partService: IPartService,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService,
@ITelemetryService telemetryService: ITelemetryService,
@IContextKeyService contextKeyService: IContextKeyService
@IContextKeyService contextKeyService: IContextKeyService,
@IInstantiationService private _instantiationService: IInstantiationService
) {
super('', TelemetryKeys.Backup, partService, telemetryService, contextKeyService, { isAngular: true, hasErrors: true });
}
@@ -53,7 +54,7 @@ export class BackupDialog extends Modal {
* Get the bootstrap params and perform the bootstrap
*/
private bootstrapAngular(bodyContainer: HTMLElement) {
this._uniqueSelector = this._bootstrapService.bootstrap(
this._uniqueSelector = this._instantiationService.invokeFunction(bootstrapAngular,
BackupModule,
bodyContainer,
BACKUP_SELECTOR,

View File

@@ -9,7 +9,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import Event from 'vs/base/common/event';
import * as sqlops from 'sqlops';
import { DashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams';
import { IDashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams';
import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';

View File

@@ -14,7 +14,7 @@ import { IBackupService, TaskExecutionMode, IBackupUiService } from 'sql/parts/d
import { BackupDialog } from 'sql/parts/disasterRecovery/backup/backupDialog';
import { OptionsDialog } from 'sql/base/browser/ui/modal/optionsDialog';
import Event, { Emitter } from 'vs/base/common/event';
import { DashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams';
import { IDashboardComponentParams } from 'sql/services/bootstrap/bootstrapParams';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { ICapabilitiesService } from 'sql/services/capabilities/capabilitiesService';
@@ -22,7 +22,6 @@ import { IConnectionProfile } from 'sql/parts/connection/common/interfaces';
import { TPromise } from 'vs/base/common/winjs.base';
import * as ConnectionUtils from 'sql/parts/connection/common/utils';
import { ProviderConnectionInfo } from 'sql/parts/connection/common/providerConnectionInfo';
import { ServiceOption } from 'sqlops';
export class BackupService implements IBackupService {
@@ -96,11 +95,13 @@ export class BackupUiService implements IBackupUiService {
private _onShowBackupEvent: Emitter<{ connection: IConnectionProfile, ownerUri: string }>;
public get onShowBackupEvent(): Event<{ connection: IConnectionProfile, ownerUri: string }> { return this._onShowBackupEvent.event; }
constructor( @IInstantiationService private _instantiationService: IInstantiationService,
constructor(
@IInstantiationService private _instantiationService: IInstantiationService,
@IPartService private _partService: IPartService,
@ICapabilitiesService private _capabilitiesService: ICapabilitiesService,
@IBackupService private _disasterRecoveryService: IBackupService,
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService) {
@IConnectionManagementService private _connectionManagementService: IConnectionManagementService
) {
this._onShowBackupEvent = new Emitter<{ connection: IConnectionProfile, ownerUri: string }>();
}
@@ -115,7 +116,7 @@ export class BackupUiService implements IBackupUiService {
});
}
private getOptions(provider: string): ServiceOption[] {
private getOptions(provider: string): sqlops.ServiceOption[] {
let feature = this._capabilitiesService.getLegacyCapabilities(this._currentProvider).features.find(f => f.featureName === 'backup');
if (feature) {
return feature.optionsMetadata;

View File

@@ -17,6 +17,11 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { localize } from 'vs/nls';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { mixin } from 'vs/base/common/objects';
import * as DOM from 'vs/base/browser/dom';
import * as strings from 'vs/base/common/strings';
import * as sqlops from 'sqlops';
import { Button } from 'sql/base/browser/ui/button/button';
import { Checkbox } from 'sql/base/browser/ui/checkbox/checkbox';
@@ -33,14 +38,10 @@ import * as TelemetryKeys from 'sql/common/telemetryKeys';
import * as BackupConstants from 'sql/parts/disasterRecovery/backup/constants';
import { RestoreViewModel, RestoreOptionParam, SouceDatabaseNamesParam } from 'sql/parts/disasterRecovery/restore/restoreViewModel';
import * as FileValidationConstants from 'sql/parts/fileBrowser/common/fileValidationServiceConstants';
import { IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
import { Dropdown } from 'sql/base/browser/ui/editableDropdown/dropdown';
import { TabbedPanel, PanelTabIdentifier } from 'sql/base/browser/ui/panel/panel';
import * as DOM from 'vs/base/browser/dom';
import * as sqlops from 'sqlops';
import * as strings from 'vs/base/common/strings';
import { ServiceOptionType } from 'sql/workbench/api/common/sqlExtHostTypes';
import { mixin } from 'vs/base/common/objects';
import { IFileBrowserDialogController } from 'sql/parts/fileBrowser/common/interfaces';
interface FileListElement {
logicalFileName: string;
@@ -130,9 +131,9 @@ export class RestoreDialog extends Modal {
@IPartService partService: IPartService,
@IThemeService private _themeService: IThemeService,
@IContextViewService private _contextViewService: IContextViewService,
@IBootstrapService private _bootstrapService: IBootstrapService,
@ITelemetryService telemetryService: ITelemetryService,
@IContextKeyService contextKeyService: IContextKeyService
@IContextKeyService contextKeyService: IContextKeyService,
@IFileBrowserDialogController private fileBrowserDialogService: IFileBrowserDialogController
) {
super(localize('RestoreDialogTitle', 'Restore database'), TelemetryKeys.Restore, partService, telemetryService, contextKeyService, { hasErrors: true, isWide: true, hasSpinner: true });
this._restoreTitle = localize('restoreDialog.restoreTitle', 'Restore database');
@@ -656,7 +657,7 @@ export class RestoreDialog extends Modal {
}
private onFileBrowserRequested(): void {
this._bootstrapService.fileBrowserDialogService.showDialog(this._ownerUri,
this.fileBrowserDialogService.showDialog(this._ownerUri,
this.viewModel.defaultBackupFolder,
BackupConstants.fileFiltersSet,
FileValidationConstants.restore,