Initial work on Arc tree view (#11008)

* Initial work on Arc tree view

* finish my thoughts
This commit is contained in:
Charles Gagnon
2020-06-18 16:50:31 -07:00
committed by GitHub
parent 935733d23c
commit 88fce764d3
23 changed files with 464 additions and 77 deletions

View File

@@ -78,7 +78,7 @@ export class MiaaConnectionStringsPage extends DashboardPage {
const ip = this._instanceRegistration.externalIp;
const port = this._instanceRegistration.externalPort;
const username = this._miaaModel.connectionProfile.userName;
const username = this._miaaModel.username;
const pairs: KeyValue[] = [
new InputKeyValue('ADO.NET', `Server=tcp:${ip},${port};Persist Security Info=False;User ID=${username};Password={your_password_here};MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;`),

View File

@@ -9,7 +9,7 @@ import * as loc from '../../../localizedConstants';
import { DashboardPage } from '../../components/dashboardPage';
import { IconPathHelper, cssStyles, ResourceType } from '../../../constants';
import { ControllerModel, Registration } from '../../../models/controllerModel';
import { getAzurecoreApi, promptForResourceDeletion, getErrorText } from '../../../common/utils';
import { getAzurecoreApi, promptForResourceDeletion, getDatabaseStateDisplayText } from '../../../common/utils';
import { MiaaModel, DatabaseModel } from '../../../models/miaaModel';
import { HybridSqlNsNameGetResponse } from '../../../controller/generated/v1/model/hybridSqlNsNameGetResponse';
import { EndpointModel } from '../../../controller/generated/v1/api';
@@ -39,7 +39,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
constructor(modelView: azdata.ModelView, private _controllerModel: ControllerModel, private _miaaModel: MiaaModel) {
super(modelView);
this._instanceProperties.miaaAdmin = this._miaaModel.connectionProfile.userName;
this._instanceProperties.miaaAdmin = this._miaaModel.username || this._instanceProperties.miaaAdmin;
this._controllerModel.onRegistrationsUpdated((_: Registration[]) => {
this.eventuallyRunOnInitialized(() => {
this.handleRegistrationsUpdated().catch(e => console.log(e));
@@ -184,7 +184,7 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
vscode.window.showInformationMessage(loc.resourceDeleted(this._miaaModel.name));
}
} catch (error) {
vscode.window.showErrorMessage(loc.resourceDeletionFailed(this._miaaModel.name, getErrorText(error)));
vscode.window.showErrorMessage(loc.resourceDeletionFailed(this._miaaModel.name, error));
} finally {
deleteButton.enabled = true;
}
@@ -253,7 +253,10 @@ export class MiaaDashboardOverviewPage extends DashboardPage {
}
private handleDatabasesUpdated(databases: DatabaseModel[]): void {
this._databasesTable.data = databases.map(d => [d.name, d.status]);
// If we were able to get the databases it means we have a good connection so update the username too
this._instanceProperties.miaaAdmin = this._miaaModel.username || this._instanceProperties.miaaAdmin;
this.refreshDisplayedProperties();
this._databasesTable.data = databases.map(d => [d.name, getDatabaseStateDisplayText(d.status)]);
this._databasesTableLoading.loading = false;
}

View File

@@ -19,8 +19,8 @@ import { PostgresDiagnoseAndSolveProblemsPage } from './postgresDiagnoseAndSolve
import { PostgresSupportRequestPage } from './postgresSupportRequestPage';
export class PostgresDashboard extends Dashboard {
constructor(title: string, private _context: vscode.ExtensionContext, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
super(title);
constructor(private _context: vscode.ExtensionContext, private _controllerModel: ControllerModel, private _postgresModel: PostgresModel) {
super(loc.postgresDashboard);
}
protected async registerTabs(modelView: azdata.ModelView): Promise<(azdata.DashboardTab | azdata.DashboardTabGroup)[]> {

View File

@@ -11,7 +11,7 @@ import { DuskyObjectModelsDatabase, DuskyObjectModelsDatabaseServiceArcPayload,
import { DashboardPage } from '../../components/dashboardPage';
import { ControllerModel } from '../../../models/controllerModel';
import { PostgresModel, PodRole } from '../../../models/postgresModel';
import { promptForResourceDeletion, getErrorText } from '../../../common/utils';
import { promptForResourceDeletion } from '../../../common/utils';
export class PostgresOverviewPage extends DashboardPage {
private propertiesLoading?: azdata.LoadingComponent;
@@ -226,7 +226,7 @@ export class PostgresOverviewPage extends DashboardPage {
vscode.window.showInformationMessage(loc.resourceDeleted(this._postgresModel.fullName));
}
} catch (error) {
vscode.window.showErrorMessage(loc.resourceDeletionFailed(this._postgresModel.fullName, getErrorText(error)));
vscode.window.showErrorMessage(loc.resourceDeletionFailed(this._postgresModel.fullName, error));
} finally {
deleteButton.enabled = true;
}

View File

@@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { ControllerTreeNode } from './controllerTreeNode';
import { TreeNode } from './treeNode';
import { LoadingControllerNode as LoadingTreeNode } from './loadingTreeNode';
import { ControllerModel } from '../../models/controllerModel';
/**
* The TreeDataProvider for the Azure Arc view, which displays a list of registered
* controllers and the resources under them.
*/
export class AzureArcTreeDataProvider implements vscode.TreeDataProvider<TreeNode> {
private _onDidChangeTreeData: vscode.EventEmitter<TreeNode | undefined> = new vscode.EventEmitter<TreeNode | undefined>();
readonly onDidChangeTreeData: vscode.Event<TreeNode | undefined> = this._onDidChangeTreeData.event;
private _loading: boolean = true;
private _loadingNode = new LoadingTreeNode();
private _controllerNodes: ControllerTreeNode[] = [];
constructor(private _context: vscode.ExtensionContext) {
// TODO:
setTimeout(() => {
this._loading = false;
this._onDidChangeTreeData.fire(undefined);
}, 5000);
}
public async getChildren(element?: TreeNode): Promise<TreeNode[]> {
if (this._loading) {
return [this._loadingNode];
}
if (element) {
return element.getChildren();
} else {
return this._controllerNodes;
}
}
public getTreeItem(element: TreeNode): TreeNode | Thenable<TreeNode> {
return element;
}
public addController(model: ControllerModel): void {
this._controllerNodes.push(new ControllerTreeNode(model, this._context));
this._onDidChangeTreeData.fire(undefined);
}
public removeController(controllerNode: ControllerTreeNode): void {
this._controllerNodes = this._controllerNodes.filter(node => node !== controllerNode);
this._onDidChangeTreeData.fire(undefined);
}
}

View File

@@ -0,0 +1,56 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { TreeNode } from './treeNode';
import { MiaaTreeNode } from './miaaTreeNode';
import { ResourceType } from '../../constants';
import { PostgresTreeNode } from './postgresTreeNode';
import { ControllerModel, Registration } from '../../models/controllerModel';
import { ControllerDashboard } from '../dashboards/controller/controllerDashboard';
import { PostgresModel } from '../../models/postgresModel';
import { parseInstanceName } from '../../common/utils';
import { MiaaModel } from '../../models/miaaModel';
/**
* The TreeNode for displaying an Azure Arc Controller
*/
export class ControllerTreeNode extends TreeNode {
private _children: TreeNode[] = [];
constructor(private _model: ControllerModel, private _context: vscode.ExtensionContext) {
super(_model.controllerUrl, vscode.TreeItemCollapsibleState.Collapsed, ResourceType.dataControllers);
_model.onRegistrationsUpdated(registrations => this.refreshChildren(registrations));
_model.refresh().catch(err => console.log(`Error refreshing Arc Controller model for tree node : ${err}`));
}
public async getChildren(): Promise<TreeNode[]> {
return this._children;
}
public async openDashboard(): Promise<void> {
const controllerDashboard = new ControllerDashboard(this._model);
await controllerDashboard.showDashboard();
}
private refreshChildren(registrations: Registration[]): void {
this._children = <TreeNode[]>registrations.map(registration => {
if (!registration.instanceNamespace || !registration.instanceName) {
console.warn('Registration is missing required namespace and name values, skipping');
return undefined;
}
switch (registration.instanceType) {
case ResourceType.postgresInstances:
const postgresModel = new PostgresModel(this._model.controllerUrl, this._model.auth, registration.instanceNamespace, parseInstanceName(registration.instanceName));
return new PostgresTreeNode(postgresModel, this._model, this._context);
case ResourceType.sqlManagedInstances:
const miaaModel = new MiaaModel(this._model.controllerUrl, this._model.auth, registration.instanceNamespace, parseInstanceName(registration.instanceName));
return new MiaaTreeNode(miaaModel, this._model);
}
return undefined;
}).filter(item => item); // filter out invalid nodes (controllers or ones without required properties)
}
}

View File

@@ -0,0 +1,18 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import * as loc from '../../localizedConstants';
import { TreeNode } from './treeNode';
/**
* A placeholder TreeNode to display while we're loading the initial set of stored nodes
*/
export class LoadingControllerNode extends TreeNode {
constructor() {
super(loc.loading, vscode.TreeItemCollapsibleState.None, 'loading');
}
}

View File

@@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { ResourceType } from '../../constants';
import { TreeNode } from './treeNode';
import { MiaaModel } from '../../models/miaaModel';
import { ControllerModel } from '../../models/controllerModel';
import { MiaaDashboard } from '../dashboards/miaa/miaaDashboard';
/**
* The TreeNode for displaying a SQL Managed Instance on Azure Arc
*/
export class MiaaTreeNode extends TreeNode {
constructor(private _model: MiaaModel, private _controllerModel: ControllerModel) {
super(_model.name, vscode.TreeItemCollapsibleState.None, ResourceType.sqlManagedInstances);
}
public async openDashboard(): Promise<void> {
const miaaDashboard = new MiaaDashboard(this._controllerModel, this._model);
await Promise.all([
miaaDashboard.showDashboard(),
this._model.refresh()]);
}
}

View File

@@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { ResourceType } from '../../constants';
import { TreeNode } from './treeNode';
import { PostgresModel } from '../../models/postgresModel';
import { ControllerModel } from '../../models/controllerModel';
import { PostgresDashboard } from '../dashboards/postgres/postgresDashboard';
/**
* The TreeNode for displaying an Postgres Server group
*/
export class PostgresTreeNode extends TreeNode {
constructor(private _model: PostgresModel, private _controllerModel: ControllerModel, private _context: vscode.ExtensionContext) {
super(_model.name, vscode.TreeItemCollapsibleState.None, ResourceType.postgresInstances);
}
public async openDashboard(): Promise<void> {
const postgresDashboard = new PostgresDashboard(this._context, this._controllerModel, this._model);
await Promise.all([
postgresDashboard.showDashboard(),
this._model.refresh()]);
}
}

View File

@@ -0,0 +1,25 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { getResourceTypeIcon } from '../../common/utils';
/**
* The base class for a TreeNode to be displayed in the TreeView
*/
export abstract class TreeNode extends vscode.TreeItem {
constructor(label: string, collapsibleState: vscode.TreeItemCollapsibleState, private resourceType?: string) {
super(label, collapsibleState);
}
public async getChildren(): Promise<TreeNode[]> {
return [];
}
public async openDashboard(): Promise<void> { }
iconPath = getResourceTypeIcon(this.resourceType);
contextValue = this.resourceType;
}