Fix for PG parameters table disappearing when trying to reset a value (#15303)

* Working on table bug

* Removed unit test checking for onEngineSettingsUpdated event to fire since removed from model

* Moved instanceofcheckbox function to utils, pr fixes

* Fix comment
This commit is contained in:
nasc17
2021-04-30 20:50:39 -07:00
committed by GitHub
parent ef8b26b7ae
commit 7a726e5dfa
4 changed files with 108 additions and 86 deletions

View File

@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { ResourceType } from 'arc'; import { ResourceType } from 'arc';
import * as azdata from 'azdata';
import * as azurecore from 'azurecore'; import * as azurecore from 'azurecore';
import * as vscode from 'vscode'; import * as vscode from 'vscode';
import { ConnectionMode, IconPath, IconPathHelper } from '../constants'; import { ConnectionMode, IconPath, IconPathHelper } from '../constants';
@@ -300,6 +301,13 @@ export function convertToGibibyteString(value: string): string {
return String(floatValue); return String(floatValue);
} }
/**
* Used to confirm if object is an azdata CheckBoxComponent
*/
export function instanceOfCheckBox(object: any): object is azdata.CheckBoxComponent {
return 'checked' in object;
}
/* /*
* Throws an Error with given {@link message} unless {@link condition} is true. * Throws an Error with given {@link message} unless {@link condition} is true.
* This also tells the typescript compiler that the condition is 'truthy' in the remainder of the scope * This also tells the typescript compiler that the condition is 'truthy' in the remainder of the scope

View File

@@ -33,13 +33,12 @@ export class PostgresModel extends ResourceModel {
private readonly _azdataApi: azdataExt.IExtension; private readonly _azdataApi: azdataExt.IExtension;
private readonly _onConfigUpdated = new vscode.EventEmitter<azdataExt.PostgresServerShowResult>(); private readonly _onConfigUpdated = new vscode.EventEmitter<azdataExt.PostgresServerShowResult>();
public readonly _onEngineSettingsUpdated = new vscode.EventEmitter<EngineSettingsModel[]>();
public onConfigUpdated = this._onConfigUpdated.event; public onConfigUpdated = this._onConfigUpdated.event;
public onEngineSettingsUpdated = this._onEngineSettingsUpdated.event;
public configLastUpdated?: Date; public configLastUpdated?: Date;
public engineSettingsLastUpdated?: Date; public engineSettingsLastUpdated?: Date;
private _refreshPromise?: Deferred<void>; private _refreshPromise?: Deferred<void>;
private _engineSettingsPromise?: Deferred<void>;
constructor(_controllerModel: ControllerModel, private _pgInfo: PGResourceInfo, registration: Registration, private _treeDataProvider: AzureArcTreeDataProvider) { constructor(_controllerModel: ControllerModel, private _pgInfo: PGResourceInfo, registration: Registration, private _treeDataProvider: AzureArcTreeDataProvider) {
super(_controllerModel, _pgInfo, registration); super(_controllerModel, _pgInfo, registration);
@@ -132,6 +131,13 @@ export class PostgresModel extends ResourceModel {
} }
public async getEngineSettings(): Promise<void> { public async getEngineSettings(): Promise<void> {
// Only allow to get engine setting once at a time
if (this._engineSettingsPromise) {
return this._engineSettingsPromise.promise;
}
this._engineSettingsPromise = new Deferred();
try {
if (!this._connectionProfile) { if (!this._connectionProfile) {
await this.getConnectionProfile(); await this.getConnectionProfile();
} }
@@ -179,8 +185,15 @@ export class PostgresModel extends ResourceModel {
} }
}); });
this.engineSettingsLastUpdated = new Date(); this.engineSettingsLastUpdated = new Date();
this._onEngineSettingsUpdated.fire(this.workerNodesEngineSettings); this._engineSettingsPromise.resolve();
} catch (err) {
this._engineSettingsPromise.reject(err);
throw err;
} finally {
this._engineSettingsPromise = undefined;
}
} }
protected createConnectionProfile(): azdata.IConnectionProfile { protected createConnectionProfile(): azdata.IConnectionProfile {

View File

@@ -462,29 +462,6 @@ describe('PostgresModel', function (): void {
should(postgresModel.engineSettingsLastUpdated).be.Date(); should(postgresModel.engineSettingsLastUpdated).be.Date();
}); });
it('Calls onEngineSettingsUpdated event after populating engine settings', async function (): Promise<void> {
const connectionResultMock = TypeMoq.Mock.ofType<azdata.ConnectionResult>();
connectionResultMock.setup(x => x.connected).returns(() => true);
connectionResultMock.setup((x: any) => x.then).returns(() => undefined);
sinon.stub(azdata.connection, 'connect').returns(Promise.resolve(connectionResultMock.object));
const array: azdata.DbCellValue[][] = [];
const executeMock = TypeMoq.Mock.ofType<azdata.SimpleExecuteResult>();
executeMock.setup(x => x.rows).returns(() => array);
executeMock.setup((x: any) => x.then).returns(() => undefined);
const providerMock = TypeMoq.Mock.ofType<azdata.QueryProvider>();
providerMock.setup(x => x.runQueryAndReturn(TypeMoq.It.isAny(), TypeMoq.It.isAny())).returns(async () => executeMock.object);
providerMock.setup((x: any) => x.then).returns(() => undefined);
sinon.stub(azdata.dataprotocol, 'getProvider').returns(providerMock.object);
const onEngineSettingsUpdated = sinon.spy(vscode.EventEmitter.prototype, 'fire');
await postgresModel.getEngineSettings();
sinon.assert.calledOnceWithExactly(onEngineSettingsUpdated, postgresModel.workerNodesEngineSettings);
});
it('Populating engine settings skips certain parameters', async function (): Promise<void> { it('Populating engine settings skips certain parameters', async function (): Promise<void> {
const connectionResultMock = TypeMoq.Mock.ofType<azdata.ConnectionResult>(); const connectionResultMock = TypeMoq.Mock.ofType<azdata.ConnectionResult>();
connectionResultMock.setup(x => x.connected).returns(() => true); connectionResultMock.setup(x => x.connected).returns(() => true);

View File

@@ -11,7 +11,7 @@ import { UserCancelledError } from '../../../common/api';
import { IconPathHelper, cssStyles } from '../../../constants'; import { IconPathHelper, cssStyles } from '../../../constants';
import { DashboardPage } from '../../components/dashboardPage'; import { DashboardPage } from '../../components/dashboardPage';
import { EngineSettingsModel, PostgresModel } from '../../../models/postgresModel'; import { EngineSettingsModel, PostgresModel } from '../../../models/postgresModel';
import { debounce } from '../../../common/utils'; import { debounce, instanceOfCheckBox } from '../../../common/utils';
export type ParametersModel = { export type ParametersModel = {
parameterName: string, parameterName: string,
@@ -47,8 +47,7 @@ export abstract class PostgresParametersPage extends DashboardPage {
this.initializeSearchBox(); this.initializeSearchBox();
this.disposables.push( this.disposables.push(
this._postgresModel.onConfigUpdated(() => this.eventuallyRunOnInitialized(() => this.handleServiceUpdated())), this._postgresModel.onConfigUpdated(() => this.eventuallyRunOnInitialized(() => this.handleServiceUpdated()))
this._postgresModel.onEngineSettingsUpdated(() => this.eventuallyRunOnInitialized(() => this.refreshParametersTable()))
); );
} }
@@ -160,9 +159,9 @@ export abstract class PostgresParametersPage extends DashboardPage {
throw err; throw err;
} }
try { try {
await this._postgresModel.refresh(); await this.callGetEngineSettings();
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(loc.refreshFailed(error)); vscode.window.showErrorMessage(loc.fetchEngineSettingsFailed(this._postgresModel.info.name, error));
} }
} }
); );
@@ -238,9 +237,9 @@ export abstract class PostgresParametersPage extends DashboardPage {
} }
this.changedComponentValues.clear(); this.changedComponentValues.clear();
try { try {
await this._postgresModel.refresh(); await this.callGetEngineSettings();
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(loc.refreshFailed(error)); vscode.window.showErrorMessage(loc.fetchEngineSettingsFailed(this._postgresModel.info.name, error));
} }
} }
); );
@@ -321,13 +320,19 @@ export abstract class PostgresParametersPage extends DashboardPage {
this.searchBox.enabled = true; this.searchBox.enabled = true;
this.resetAllButton.enabled = true; this.resetAllButton.enabled = true;
this.parameterContainer.addItem(this._parametersTable!); this.parameterContainer.addItem(this._parametersTable!);
this.refreshParametersTable(); this.refreshParametersTableValues();
} }
} }
private async callGetEngineSettings(): Promise<void> { private async callGetEngineSettings(): Promise<void> {
try { try {
await this._postgresModel.getEngineSettings(); await this._postgresModel.getEngineSettings().then(() => {
if (this._parametersTable.data?.length !== 0) {
this.refreshParametersTableValues();
} else {
this.populateParametersTable();
}
});
} catch (error) { } catch (error) {
if (error instanceof UserCancelledError) { if (error instanceof UserCancelledError) {
vscode.window.showWarningMessage(loc.pgConnectionRequired); vscode.window.showWarningMessage(loc.pgConnectionRequired);
@@ -415,9 +420,9 @@ export abstract class PostgresParametersPage extends DashboardPage {
async (_progress, _token): Promise<void> => { async (_progress, _token): Promise<void> => {
await this.resetParameter(engineSetting.parameterName!); await this.resetParameter(engineSetting.parameterName!);
try { try {
await this._postgresModel.refresh(); await this.callGetEngineSettings();
} catch (error) { } catch (error) {
vscode.window.showErrorMessage(loc.refreshFailed(error)); vscode.window.showErrorMessage(loc.fetchEngineSettingsFailed(this._postgresModel.info.name, error));
} }
} }
); );
@@ -573,10 +578,6 @@ export abstract class PostgresParametersPage extends DashboardPage {
} }
private discardParametersTableChanges(): void { private discardParametersTableChanges(): void {
let instanceOfCheckBox = function (object: any): object is azdata.CheckBoxComponent {
return 'checked' in object;
};
this.changedComponentValues.forEach(v => { this.changedComponentValues.forEach(v => {
let param = this._parameters.find(p => p.parameterName === v); let param = this._parameters.find(p => p.parameterName === v);
if (instanceOfCheckBox(param!.valueComponent)) { if (instanceOfCheckBox(param!.valueComponent)) {
@@ -591,7 +592,7 @@ export abstract class PostgresParametersPage extends DashboardPage {
}); });
} }
private refreshParametersTable(): void { private populateParametersTable(): void {
this._parameters = this.engineSettings.map(parameter => this.createParameterComponents(parameter)); this._parameters = this.engineSettings.map(parameter => this.createParameterComponents(parameter));
this._parametersTable.data = this._parameters.map(p => { this._parametersTable.data = this._parameters.map(p => {
@@ -607,14 +608,37 @@ export abstract class PostgresParametersPage extends DashboardPage {
}); });
} }
/**
* Checks if exisiting parameter values needs to be updated.
* Only updates exisiting parameters, will not add/remove parameters from the table.
*/
private refreshParametersTableValues(): void {
this.engineSettings.map(parameter => {
let param = this._parameters.find(p => p.parameterName === parameter.parameterName);
if (param) {
if (parameter.value !== param.originalValue) {
param.originalValue = parameter.value!;
if (instanceOfCheckBox(param.valueComponent)) {
if (param.originalValue === 'on') {
param.valueComponent.checked = true;
} else {
param.valueComponent.checked = false;
}
} else {
param.valueComponent.value = parameter.value;
}
}
}
});
}
private async handleServiceUpdated(): Promise<void> { private async handleServiceUpdated(): Promise<void> {
if (this._postgresModel.configLastUpdated && !this._postgresModel.engineSettingsLastUpdated) { if (this._postgresModel.configLastUpdated && !this._postgresModel.engineSettingsLastUpdated) {
this.connectToServerButton!.enabled = true; this.connectToServerButton!.enabled = true;
this.parametersTableLoading!.loading = false; this.parametersTableLoading!.loading = false;
} else if (this._postgresModel.engineSettingsLastUpdated) { } else if (this._postgresModel.engineSettingsLastUpdated) {
await this.callGetEngineSettings(); await this.callGetEngineSettings();
this.discardButton.enabled = false;
this.saveButton.enabled = false;
} }
} }