mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
Enabled Azure Arc data controller upgrade for direct and indirect mode (#19060)
* Fixed a connect to Server typo * Added upgrade tab with description and title. Table is still stuck loading. * Renamed backups to upgrades. * Removed loading icon * Table appearing and not stuck loading * Saving for now to upgrade arc and azcli versions * Added upgrade confirmation dialog, populated dummy data and added upgrade apis. * Added parsing of versions and current version from listupgrades * Upgrade itself not working, but added upgrade as a part of azure cli api. * Table now populating with release dates and version numbers. Upgrade button only shows for appropriate cells. Upgrade done but no release version column. * Changed text using PM advice * Removed comments from controllerUpgrades.ts * Replaced code in upgradecontroller.ts and made refresh work * Removed one call to handleTablesUpdated * Removed some code in upgradeControllers.ts and it still works * removing more code for pitr refresh from upgradeController.ts * Created and used UpgradeModel even though it is empty * Added upgrademodel * PR comments addressed Co-authored-by: Candice Ye <canye@microsoft.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import { Dashboard } from '../../components/dashboard';
|
||||
import { ControllerModel } from '../../../models/controllerModel';
|
||||
import { ControllerDashboardOverviewPage } from './controllerDashboardOverviewPage';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { ControllerUpgradesPage } from './controllerUpgrades';
|
||||
|
||||
export class ControllerDashboard extends Dashboard {
|
||||
|
||||
@@ -23,8 +24,10 @@ export class ControllerDashboard extends Dashboard {
|
||||
|
||||
protected async registerTabs(modelView: azdata.ModelView): Promise<(azdata.DashboardTab | azdata.DashboardTabGroup)[]> {
|
||||
const overviewPage = new ControllerDashboardOverviewPage(modelView, this.dashboard, this._controllerModel);
|
||||
const upgradesPage = new ControllerUpgradesPage(modelView, this.dashboard, this._controllerModel);
|
||||
return [
|
||||
overviewPage.tab
|
||||
overviewPage.tab,
|
||||
upgradesPage.tab
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 azdata from 'azdata';
|
||||
import * as azExt from 'az-ext';
|
||||
import * as loc from '../../../localizedConstants';
|
||||
import { IconPathHelper, cssStyles, ConnectionMode } from '../../../constants';
|
||||
import { DashboardPage } from '../../components/dashboardPage';
|
||||
import { ControllerModel } from '../../../models/controllerModel';
|
||||
import { UpgradeController } from '../../dialogs/upgradeController';
|
||||
|
||||
export class ControllerUpgradesPage extends DashboardPage {
|
||||
constructor(modelView: azdata.ModelView, dashboard: azdata.window.ModelViewDashboard, private _controllerModel: ControllerModel) {
|
||||
super(modelView, dashboard);
|
||||
this._azApi = vscode.extensions.getExtension(azExt.extension.name)?.exports;
|
||||
}
|
||||
private _upgradesContainer!: azdata.DivContainer;
|
||||
private _configureRetentionPolicyButton!: azdata.ButtonComponent;
|
||||
private _upgradesTableLoading!: azdata.LoadingComponent;
|
||||
private _upgradesTable!: azdata.DeclarativeTableComponent;
|
||||
private _upgradesMessage!: azdata.TextComponent;
|
||||
private readonly _azApi: azExt.IExtension;
|
||||
|
||||
public get title(): string {
|
||||
return loc.upgradeManagement;
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
return 'upgrades';
|
||||
}
|
||||
|
||||
public get icon(): { dark: string, light: string } {
|
||||
return IconPathHelper.pitr;
|
||||
}
|
||||
protected async refresh(): Promise<void> {
|
||||
await Promise.resolve(this._controllerModel.refresh(false, this._controllerModel.info.namespace));
|
||||
this.handleTableUpdated();
|
||||
}
|
||||
|
||||
public get container(): azdata.Component {
|
||||
const root = this.modelView.modelBuilder.flexContainer()
|
||||
.withLayout({ flexFlow: 'column' })
|
||||
.withProps({ CSSStyles: { 'margin': '18px' } })
|
||||
.component();
|
||||
const content = this.modelView.modelBuilder.divContainer().component();
|
||||
this._upgradesContainer = this.modelView.modelBuilder.divContainer().component();
|
||||
root.addItem(content, { CSSStyles: { 'margin': '5px' } });
|
||||
|
||||
// Upgrades title and description
|
||||
const availableUpgradesTitle = this.modelView.modelBuilder.text().withProps({
|
||||
value: loc.availableUpgrades,
|
||||
CSSStyles: { ...cssStyles.title },
|
||||
}).component();
|
||||
content.addItem(availableUpgradesTitle);
|
||||
|
||||
const infoAvailableUpgrades = this.modelView.modelBuilder.text().withProps({
|
||||
value: loc.availableUpgradesDescription,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
|
||||
const upgradesInfoDescription = this.modelView.modelBuilder.flexContainer()
|
||||
.withLayout({ flexWrap: 'wrap' })
|
||||
.withItems([
|
||||
infoAvailableUpgrades
|
||||
]).component();
|
||||
|
||||
const upgradesVersionLogLink = this.modelView.modelBuilder.hyperlink().withProps({
|
||||
label: loc.versionLog,
|
||||
url: 'https://docs.microsoft.com/en-us/azure/azure-arc/data/version-log',
|
||||
CSSStyles: { 'margin-block-start': '0px', 'margin-block-end': '0px' }
|
||||
}).component();
|
||||
|
||||
const upgradesInfoAndLink = this.modelView.modelBuilder.flexContainer()
|
||||
.withLayout({ flexWrap: 'wrap' })
|
||||
.withItems([
|
||||
upgradesInfoDescription,
|
||||
upgradesVersionLogLink
|
||||
], { CSSStyles: { 'margin-right': '5px' } }).component();
|
||||
|
||||
content.addItem(upgradesInfoAndLink, { CSSStyles: { 'min-height': '30px' } });
|
||||
|
||||
const infoOnlyNextImmediateVersion = this.modelView.modelBuilder.text().withProps({
|
||||
value: loc.onlyNextImmediateVersion,
|
||||
CSSStyles: { ...cssStyles.text, 'margin-block-start': '0px', 'margin-block-end': '0px', 'max-width': 'auto' }
|
||||
}).component();
|
||||
|
||||
content.addItem(infoOnlyNextImmediateVersion, { CSSStyles: { 'min-height': '30px' } });
|
||||
|
||||
// Create loaded components
|
||||
this._upgradesTableLoading = this.modelView.modelBuilder.loadingComponent().component();
|
||||
this._upgradesTable = this.modelView.modelBuilder.declarativeTable().withProps({
|
||||
width: '100%',
|
||||
columns: [
|
||||
{
|
||||
displayName: loc.version,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
isReadOnly: true,
|
||||
width: '30%',
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
},
|
||||
{
|
||||
displayName: loc.releaseDate,
|
||||
valueType: azdata.DeclarativeDataType.string,
|
||||
isReadOnly: true,
|
||||
width: '30%',
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow
|
||||
},
|
||||
{
|
||||
displayName: loc.upgrade,
|
||||
valueType: azdata.DeclarativeDataType.component,
|
||||
isReadOnly: true,
|
||||
width: '10%',
|
||||
headerCssStyles: cssStyles.tableHeader,
|
||||
rowCssStyles: cssStyles.tableRow,
|
||||
}
|
||||
],
|
||||
dataValues: []
|
||||
}).component();
|
||||
|
||||
this._upgradesMessage = this.modelView.modelBuilder.text()
|
||||
.withProps({ CSSStyles: { 'text-align': 'center' } })
|
||||
.component();
|
||||
|
||||
this.handleTableUpdated();
|
||||
this._upgradesTableLoading.component = this._upgradesTable;
|
||||
|
||||
root.addItem(this._upgradesContainer);
|
||||
root.addItem(this._upgradesMessage);
|
||||
|
||||
this.initialized = true;
|
||||
|
||||
this._upgradesTableLoading.loading = false;
|
||||
this._upgradesContainer.addItem(this._upgradesTableLoading, { CSSStyles: { 'margin-bottom': '20px' } });
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
public get toolbarContainer(): azdata.ToolbarContainer {
|
||||
// Refresh
|
||||
const refreshButton = this.modelView.modelBuilder.button().withProps({
|
||||
label: loc.refresh,
|
||||
iconPath: IconPathHelper.refresh
|
||||
}).component();
|
||||
this.disposables.push(
|
||||
refreshButton.onDidClick(async () => {
|
||||
refreshButton.enabled = false;
|
||||
try {
|
||||
await this.refresh();
|
||||
} finally {
|
||||
refreshButton.enabled = true;
|
||||
}
|
||||
}));
|
||||
this._configureRetentionPolicyButton = this.modelView.modelBuilder.button().withProps({
|
||||
label: loc.configureRetentionPolicyButton,
|
||||
enabled: true,
|
||||
iconPath: IconPathHelper.edit,
|
||||
}).component();
|
||||
|
||||
return this.modelView.modelBuilder.toolbarContainer().withToolbarItems(
|
||||
[
|
||||
{ component: refreshButton, toolbarSeparatorAfter: true },
|
||||
{ component: this._configureRetentionPolicyButton, toolbarSeparatorAfter: false },
|
||||
|
||||
]
|
||||
).component();
|
||||
}
|
||||
|
||||
private formatTableData(result: azExt.AzOutput<azExt.DcListUpgradesResult>): (string | azdata.ButtonComponent)[][] {
|
||||
let formattedValues: (string | azdata.ButtonComponent)[][] = [];
|
||||
const versions = result.stdout.versions;
|
||||
const dates = result.stdout.dates;
|
||||
const currentVersion = result.stdout.currentVersion;
|
||||
const nextVersion = this.getNextUpgrade(result.stdout.versions, result.stdout.currentVersion);
|
||||
let currentVersionHit = false;
|
||||
for (let i = 0; i < versions.length; i++) {
|
||||
if (currentVersionHit) {
|
||||
continue;
|
||||
} else {
|
||||
if (versions[i] === currentVersion) {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.currentVersion, false, '')]);
|
||||
currentVersionHit = true;
|
||||
} else if (versions[i] === nextVersion) {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.upgrade, true, nextVersion)]);
|
||||
} else {
|
||||
formattedValues.push([versions[i], dates[i], this.createUpgradeButton(loc.upgrade, false, '')]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return formattedValues;
|
||||
}
|
||||
|
||||
private async handleTableUpdated(): Promise<void> {
|
||||
const result = await this._azApi.az.arcdata.dc.listUpgrades(this._controllerModel.info.namespace);
|
||||
let tableDisplay = this.formatTableData(result);
|
||||
let tableValues = tableDisplay.map(d => {
|
||||
return d.map((value: any): azdata.DeclarativeTableCellValue => {
|
||||
return { value: value };
|
||||
});
|
||||
});
|
||||
|
||||
this._upgradesTable.setDataValues(tableValues);
|
||||
this._upgradesTableLoading.loading = false;
|
||||
this._upgradesContainer.addItem(this._upgradesTableLoading, { CSSStyles: { 'margin-bottom': '20px' } });
|
||||
}
|
||||
|
||||
// Given the list of available versions and the current version, if the current version is not the latest,
|
||||
// then return the next version available. (Can only upgrade to next version due to limitations by Azure CLI arcdata extension.)
|
||||
// If current version is the latest, then return undefined.
|
||||
private getNextUpgrade(versions: string[], currentVersion: string): string | undefined {
|
||||
let index = versions.indexOf(currentVersion);
|
||||
// The version at index 0 will be the latest
|
||||
if (index > 0) {
|
||||
return versions[index - 1];
|
||||
} else {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
//Create restore button for every database entry in the database table
|
||||
private createUpgradeButton(label: string, enabled: boolean, nextVersion: string): azdata.ButtonComponent | string {
|
||||
let upgradeButton = this.modelView.modelBuilder.button().withProps({
|
||||
label: label,
|
||||
enabled: enabled
|
||||
}).component();
|
||||
|
||||
this.disposables.push(
|
||||
upgradeButton.onDidClick(async () => {
|
||||
const upgradeDialog = new UpgradeController(this._controllerModel);
|
||||
upgradeDialog.showDialog(loc.upgradeDataController);
|
||||
let dialogClosed = await upgradeDialog.waitForClose();
|
||||
if (dialogClosed) {
|
||||
try {
|
||||
upgradeButton.enabled = false;
|
||||
vscode.window.showInformationMessage(loc.upgrading);
|
||||
await vscode.window.withProgress(
|
||||
{
|
||||
location: vscode.ProgressLocation.Notification,
|
||||
title: loc.updatingInstance(this._controllerModel.info.name),
|
||||
cancellable: false
|
||||
},
|
||||
async (_progress, _token): Promise<void> => {
|
||||
if (nextVersion !== '') {
|
||||
if (this._controllerModel.info.connectionMode === ConnectionMode.direct) {
|
||||
await this._azApi.az.arcdata.dc.upgrade(
|
||||
nextVersion,
|
||||
this._controllerModel.info.name,
|
||||
this._controllerModel.info.resourceGroup,
|
||||
undefined, // Indirect mode argument - namespace
|
||||
undefined // Indirect mode argument - usek8s
|
||||
);
|
||||
} else {
|
||||
await this._azApi.az.arcdata.dc.upgrade(
|
||||
nextVersion,
|
||||
this._controllerModel.info.name,
|
||||
undefined, // Direct mode argument - resourceGroup
|
||||
this._controllerModel.info.namespace,
|
||||
true
|
||||
);
|
||||
}
|
||||
} else {
|
||||
vscode.window.showInformationMessage(loc.noUpgrades);
|
||||
}
|
||||
|
||||
try {
|
||||
await this._controllerModel.refresh(false, this._controllerModel.info.namespace);
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.refreshFailed(error));
|
||||
}
|
||||
}
|
||||
);
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(loc.updateExtensionsFailed(error));
|
||||
} finally {
|
||||
this._configureRetentionPolicyButton.enabled = true;
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
return upgradeButton;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user