mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-17 02:51:36 -05:00
Correctly announce loading state for arc cluster context loading (#15747)
* Correctly announce loading state for arc cluster context loading * localize * Fix compile * Fix test
This commit is contained in:
@@ -191,7 +191,7 @@ export const noPodIssuesDetected = localize('arc.noPodIssuesDetected', "There ar
|
|||||||
export const podIssuesDetected = localize('arc.podIssuesDetected', "The pods listed below are experiencing issues that may affect performance or availability.");
|
export const podIssuesDetected = localize('arc.podIssuesDetected', "The pods listed below are experiencing issues that may affect performance or availability.");
|
||||||
export const containerReady = localize('arc.containerReady', "Pod containers are ready.");
|
export const containerReady = localize('arc.containerReady', "Pod containers are ready.");
|
||||||
export const podScheduled = localize('arc.podScheduled', "Pod is schedulable.");
|
export const podScheduled = localize('arc.podScheduled', "Pod is schedulable.");
|
||||||
|
export const loadingClusterContextCompleted = localize('arc.loadingClusterContextCompleted', "Loading cluster contexts completed");
|
||||||
export function rangeSetting(min: string, max: string): string { return localize('arc.rangeSetting', "Value is expected to be in the range {0} - {1}", min, max); }
|
export function rangeSetting(min: string, max: string): string { return localize('arc.rangeSetting', "Value is expected to be in the range {0} - {1}", min, max); }
|
||||||
export function databaseCreated(name: string): string { return localize('arc.databaseCreated', "Database {0} created", name); }
|
export function databaseCreated(name: string): string { return localize('arc.databaseCreated', "Database {0} created", name); }
|
||||||
export function deletingInstance(name: string): string { return localize('arc.deletingInstance', "Deleting instance '{0}'...", name); }
|
export function deletingInstance(name: string): string { return localize('arc.deletingInstance', "Deleting instance '{0}'...", name); }
|
||||||
@@ -262,3 +262,5 @@ export const noCurrentContextFound = (configFile: string) => localize('noCurrent
|
|||||||
export const noNameInContext = (configFile: string) => localize('noNameInContext', "No name field was found in a cluster context in the config file: {0}", configFile);
|
export const noNameInContext = (configFile: string) => localize('noNameInContext', "No name field was found in a cluster context in the config file: {0}", configFile);
|
||||||
export const userCancelledError = localize('arc.userCancelledError', "User cancelled the dialog");
|
export const userCancelledError = localize('arc.userCancelledError', "User cancelled the dialog");
|
||||||
export const clusterContextConfigNoLongerValid = (configFile: string, clusterContext: string, error: any) => localize('clusterContextConfigNoLongerValid', "The cluster context information specified by config file: {0} and cluster context: {1} is no longer valid. Error is:\n\t{2}\n Do you want to update this information?", configFile, clusterContext, getErrorMessage(error));
|
export const clusterContextConfigNoLongerValid = (configFile: string, clusterContext: string, error: any) => localize('clusterContextConfigNoLongerValid', "The cluster context information specified by config file: {0} and cluster context: {1} is no longer valid. Error is:\n\t{2}\n Do you want to update this information?", configFile, clusterContext, getErrorMessage(error));
|
||||||
|
export const invalidConfigPath = localize('arc.invalidConfigPath', "Invalid config path");
|
||||||
|
export const loadingClusterContextsError = (error: any): string => localize('arc.loadingClusterContextsError', "Error loading cluster contexts. {0}", getErrorMessage(error));
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const newFileUri = vscode.Uri.file(path.join('path', 'to', 'new', '.kube', 'conf
|
|||||||
describe('filePicker', function (): void {
|
describe('filePicker', function (): void {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const { modelBuilderMock } = createModelViewMock();
|
const { modelBuilderMock } = createModelViewMock();
|
||||||
filePicker = new FilePicker(modelBuilderMock.object, initialPath, (_disposable) => { }, '');
|
filePicker = new FilePicker(modelBuilderMock.object, initialPath, (_disposable) => { }, '', '');
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
|
|||||||
@@ -5,10 +5,10 @@
|
|||||||
|
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import * as should from 'should';
|
import * as should from 'should';
|
||||||
import { getErrorMessage } from '../../../common/utils';
|
|
||||||
import { RadioOptionsGroup, RadioOptionsInfo } from '../../../ui/components/radioOptionsGroup';
|
import { RadioOptionsGroup, RadioOptionsInfo } from '../../../ui/components/radioOptionsGroup';
|
||||||
import { createModelViewMock } from '@microsoft/azdata-test/out/mocks/modelView/modelViewMock';
|
import { createModelViewMock } from '@microsoft/azdata-test/out/mocks/modelView/modelViewMock';
|
||||||
import { StubRadioButton } from '@microsoft/azdata-test/out/stubs/modelView/stubRadioButton';
|
import { StubRadioButton } from '@microsoft/azdata-test/out/stubs/modelView/stubRadioButton';
|
||||||
|
import * as loc from '../../../localizedConstants';
|
||||||
|
|
||||||
|
|
||||||
const loadingError = new Error('Error loading options');
|
const loadingError = new Error('Error loading options');
|
||||||
@@ -25,7 +25,7 @@ let radioOptionsGroup: RadioOptionsGroup;
|
|||||||
describe('radioOptionsGroup', function (): void {
|
describe('radioOptionsGroup', function (): void {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
const { modelBuilderMock } = createModelViewMock();
|
const { modelBuilderMock } = createModelViewMock();
|
||||||
radioOptionsGroup = new RadioOptionsGroup(modelBuilderMock.object, (_disposable) => { });
|
radioOptionsGroup = new RadioOptionsGroup(modelBuilderMock.object, (_disposable) => { }, undefined, '', () => '');
|
||||||
await radioOptionsGroup.load(async () => radioOptionsInfo);
|
await radioOptionsGroup.load(async () => radioOptionsInfo);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ describe('radioOptionsGroup', function (): void {
|
|||||||
radioOptionsGroup.items.length.should.equal(1, 'There is should be only one element in the divContainer when loading error happens');
|
radioOptionsGroup.items.length.should.equal(1, 'There is should be only one element in the divContainer when loading error happens');
|
||||||
const label = radioOptionsGroup.items[0] as azdata.TextComponent;
|
const label = radioOptionsGroup.items[0] as azdata.TextComponent;
|
||||||
should(label.value).not.be.undefined();
|
should(label.value).not.be.undefined();
|
||||||
label.value!.should.deepEqual(getErrorMessage(loadingError));
|
label.value!.should.deepEqual(loc.loadingClusterContextsError(loadingError));
|
||||||
should(label.CSSStyles).not.be.undefined();
|
should(label.CSSStyles).not.be.undefined();
|
||||||
should(label.CSSStyles!.color).not.be.undefined();
|
should(label.CSSStyles!.color).not.be.undefined();
|
||||||
label.CSSStyles!.color.should.equal('Red');
|
label.CSSStyles!.color.should.equal('Red');
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import * as azdata from 'azdata';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as loc from '../../localizedConstants';
|
import * as loc from '../../localizedConstants';
|
||||||
|
import { promises as fs } from 'fs';
|
||||||
export interface RadioOptionsInfo {
|
export interface RadioOptionsInfo {
|
||||||
values?: string[],
|
values?: string[],
|
||||||
defaultValue: string
|
defaultValue: string
|
||||||
@@ -20,14 +20,24 @@ export class FilePicker {
|
|||||||
modelBuilder: azdata.ModelBuilder,
|
modelBuilder: azdata.ModelBuilder,
|
||||||
initialPath: string,
|
initialPath: string,
|
||||||
onNewDisposableCreated: (disposable: vscode.Disposable) => void,
|
onNewDisposableCreated: (disposable: vscode.Disposable) => void,
|
||||||
ariaLabel: string
|
ariaLabel: string,
|
||||||
|
validationErrorMessage: string
|
||||||
) {
|
) {
|
||||||
const buttonWidth = 80;
|
const buttonWidth = 80;
|
||||||
this.filePathInputBox = modelBuilder.inputBox()
|
this.filePathInputBox = modelBuilder.inputBox()
|
||||||
.withProperties<azdata.InputBoxProperties>({
|
.withProperties<azdata.InputBoxProperties>({
|
||||||
value: initialPath,
|
value: initialPath,
|
||||||
ariaLabel: ariaLabel,
|
ariaLabel: ariaLabel,
|
||||||
|
validationErrorMessage: validationErrorMessage,
|
||||||
width: 350
|
width: 350
|
||||||
|
}).withValidation(async () => {
|
||||||
|
try {
|
||||||
|
await fs.stat(this.filePathInputBox.value || '');
|
||||||
|
} catch (err) {
|
||||||
|
console.log('Error checking config path ', err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}).component();
|
}).component();
|
||||||
|
|
||||||
this.filePickerButton = modelBuilder.button()
|
this.filePickerButton = modelBuilder.button()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
*--------------------------------------------------------------------------------------------*/
|
*--------------------------------------------------------------------------------------------*/
|
||||||
import * as azdata from 'azdata';
|
import * as azdata from 'azdata';
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { getErrorMessage } from '../../common/utils';
|
import * as loc from '../../localizedConstants';
|
||||||
|
|
||||||
export interface RadioOptionsInfo {
|
export interface RadioOptionsInfo {
|
||||||
values?: string[],
|
values?: string[],
|
||||||
@@ -20,7 +20,12 @@ export class RadioOptionsGroup {
|
|||||||
private _onRadioOptionChanged: vscode.EventEmitter<string | undefined> = new vscode.EventEmitter<string | undefined>();
|
private _onRadioOptionChanged: vscode.EventEmitter<string | undefined> = new vscode.EventEmitter<string | undefined>();
|
||||||
public onRadioOptionChanged: vscode.Event<string | undefined> = this._onRadioOptionChanged.event;
|
public onRadioOptionChanged: vscode.Event<string | undefined> = this._onRadioOptionChanged.event;
|
||||||
|
|
||||||
constructor(private _modelBuilder: azdata.ModelBuilder, private _onNewDisposableCreated: (disposable: vscode.Disposable) => void, private _groupName: string = `RadioOptionsGroup${RadioOptionsGroup.id++}`) {
|
constructor(private _modelBuilder: azdata.ModelBuilder,
|
||||||
|
private _onNewDisposableCreated: (disposable: vscode.Disposable) => void,
|
||||||
|
private _groupName: string = `RadioOptionsGroup${RadioOptionsGroup.id++}`,
|
||||||
|
private _loadingCompleteMessage: string,
|
||||||
|
private _loadingCompleteErrorMessage: (error: any) => string
|
||||||
|
) {
|
||||||
this._divContainer = this._modelBuilder.divContainer().withProperties<azdata.DivContainerProperties>({ clickable: false }).component();
|
this._divContainer = this._modelBuilder.divContainer().withProperties<azdata.DivContainerProperties>({ clickable: false }).component();
|
||||||
this._loadingBuilder = this._modelBuilder.loadingComponent().withItem(this._divContainer);
|
this._loadingBuilder = this._modelBuilder.loadingComponent().withItem(this._divContainer);
|
||||||
}
|
}
|
||||||
@@ -59,10 +64,12 @@ export class RadioOptionsGroup {
|
|||||||
}));
|
}));
|
||||||
this._divContainer.addItem(radioOption);
|
this._divContainer.addItem(radioOption);
|
||||||
});
|
});
|
||||||
|
this.component().loadingCompletedText = this._loadingCompleteMessage;
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
const errorLabel = this._modelBuilder.text().withProperties({ value: getErrorMessage(e), CSSStyles: { 'color': 'Red' } }).component();
|
const errorLabel = this._modelBuilder.text().withProperties({ value: loc.loadingClusterContextsError(e), CSSStyles: { 'color': 'Red' } }).component();
|
||||||
this._divContainer.addItem(errorLabel);
|
this._divContainer.addItem(errorLabel);
|
||||||
|
this.component().loadingCompletedText = this._loadingCompleteErrorMessage(e);
|
||||||
}
|
}
|
||||||
this.component().loading = false;
|
this.component().loading = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,13 +97,14 @@ abstract class ControllerDialogBase extends InitializingComponent {
|
|||||||
this.modelBuilder,
|
this.modelBuilder,
|
||||||
controllerInfo?.kubeConfigFilePath || getDefaultKubeConfigPath(),
|
controllerInfo?.kubeConfigFilePath || getDefaultKubeConfigPath(),
|
||||||
(disposable) => this._toDispose.push(disposable),
|
(disposable) => this._toDispose.push(disposable),
|
||||||
loc.controllerKubeConfig
|
loc.controllerKubeConfig,
|
||||||
|
loc.invalidConfigPath
|
||||||
);
|
);
|
||||||
this.modelBuilder.inputBox()
|
this.modelBuilder.inputBox()
|
||||||
.withProps({
|
.withProps({
|
||||||
value: controllerInfo?.kubeConfigFilePath || getDefaultKubeConfigPath()
|
value: controllerInfo?.kubeConfigFilePath || getDefaultKubeConfigPath()
|
||||||
}).component();
|
}).component();
|
||||||
this.clusterContextRadioGroup = new RadioOptionsGroup(this.modelBuilder, (disposable) => this._toDispose.push(disposable));
|
this.clusterContextRadioGroup = new RadioOptionsGroup(this.modelBuilder, (disposable) => this._toDispose.push(disposable), undefined, loc.loadingClusterContextCompleted, loc.loadingClusterContextsError);
|
||||||
this.loadRadioGroup(controllerInfo?.kubeClusterContext);
|
this.loadRadioGroup(controllerInfo?.kubeClusterContext);
|
||||||
this._toDispose.push(this.clusterContextRadioGroup.onRadioOptionChanged(newContext => this.updateNamespace(newContext)));
|
this._toDispose.push(this.clusterContextRadioGroup.onRadioOptionChanged(newContext => this.updateNamespace(newContext)));
|
||||||
this._toDispose.push(this.kubeConfigInputBox.onTextChanged(() => this.loadRadioGroup(controllerInfo?.kubeClusterContext)));
|
this._toDispose.push(this.kubeConfigInputBox.onTextChanged(() => this.loadRadioGroup(controllerInfo?.kubeClusterContext)));
|
||||||
|
|||||||
Reference in New Issue
Block a user