mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-01-19 07:20:21 +00:00
Add UX for error Information for Phoenix workspace connection (#1234)
* Add UX for error Information * update text messages
This commit is contained in:
parent
8b22027cb6
commit
06f6df83ad
@ -450,6 +450,24 @@ export interface IResponse<T> {
|
||||
data: T;
|
||||
}
|
||||
|
||||
export interface IValidationError {
|
||||
message: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface IMaxAllocationTimeExceeded extends IValidationError {
|
||||
earliestAllocationTimestamp: string;
|
||||
maxAllocationTimePerDayPerUserInMinutes: string;
|
||||
}
|
||||
|
||||
export interface IMaxDbAccountsPerUserExceeded extends IValidationError {
|
||||
maxSimultaneousConnectionsPerUser: string;
|
||||
}
|
||||
|
||||
export interface IMaxUsersPerDbAccountExceeded extends IValidationError {
|
||||
maxSimultaneousUsersPerDbAccount: string;
|
||||
}
|
||||
|
||||
export interface IPhoenixConnectionInfoResult {
|
||||
readonly notebookAuthToken?: string;
|
||||
readonly notebookServerUrl?: string;
|
||||
@ -531,3 +549,12 @@ export interface ContainerConnectionInfo {
|
||||
status: ConnectionStatusType;
|
||||
//need to add ram and rom info
|
||||
}
|
||||
|
||||
export enum PhoenixErrorType {
|
||||
MaxAllocationTimeExceeded = "MaxAllocationTimeExceeded",
|
||||
MaxDbAccountsPerUserExceeded = "MaxDbAccountsPerUserExceeded",
|
||||
MaxUsersPerDbAccountExceeded = "MaxUsersPerDbAccountExceeded",
|
||||
AllocationValidationResult = "AllocationValidationResult",
|
||||
RegionNotServicable = "RegionNotServicable",
|
||||
SubscriptionNotAllowed = "SubscriptionNotAllowed",
|
||||
}
|
||||
|
@ -362,12 +362,13 @@ export default class Explorer {
|
||||
status: ConnectionStatusType.Connecting,
|
||||
};
|
||||
useNotebook.getState().setConnectionInfo(connectionStatus);
|
||||
let connectionInfo;
|
||||
try {
|
||||
TelemetryProcessor.traceStart(Action.PhoenixConnection, {
|
||||
dataExplorerArea: Areas.Notebook,
|
||||
});
|
||||
useNotebook.getState().setIsAllocating(true);
|
||||
const connectionInfo = await this.phoenixClient.allocateContainer(provisionData);
|
||||
connectionInfo = await this.phoenixClient.allocateContainer(provisionData);
|
||||
if (connectionInfo.status !== HttpStatusCodes.OK) {
|
||||
throw new Error(`Received status code: ${connectionInfo?.status}`);
|
||||
}
|
||||
@ -386,12 +387,16 @@ export default class Explorer {
|
||||
});
|
||||
connectionStatus.status = ConnectionStatusType.Failed;
|
||||
useNotebook.getState().resetContainerConnection(connectionStatus);
|
||||
useDialog
|
||||
.getState()
|
||||
.showOkModalDialog(
|
||||
"Connection Failed",
|
||||
"We are unable to connect to the temporary workspace. Please try again in a few minutes. If the error persists, file a support ticket."
|
||||
);
|
||||
if (error?.status === HttpStatusCodes.Forbidden && error.message) {
|
||||
useDialog.getState().showOkModalDialog("Connection Failed", `${error.message}`);
|
||||
} else {
|
||||
useDialog
|
||||
.getState()
|
||||
.showOkModalDialog(
|
||||
"Connection Failed",
|
||||
"We are unable to connect to the temporary workspace. Please try again in a few minutes. If the error persists, file a support ticket."
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
} finally {
|
||||
useNotebook.getState().setIsAllocating(false);
|
||||
|
@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Notebook container related stuff
|
||||
*/
|
||||
import { useDialog } from "Explorer/Controls/Dialog";
|
||||
import promiseRetry, { AbortError } from "p-retry";
|
||||
import { PhoenixClient } from "Phoenix/PhoenixClient";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
@ -159,6 +160,16 @@ export class NotebookContainerClient {
|
||||
return null;
|
||||
} catch (error) {
|
||||
Logger.logError(getErrorMessage(error), "NotebookContainerClient/resetWorkspace");
|
||||
if (error?.status === HttpStatusCodes.Forbidden && error.message) {
|
||||
useDialog.getState().showOkModalDialog("Connection Failed", `${error.message}`);
|
||||
} else {
|
||||
useDialog
|
||||
.getState()
|
||||
.showOkModalDialog(
|
||||
"Connection Failed",
|
||||
"We are unable to connect to the temporary workspace. Please try again in a few minutes. If the error persists, file a support ticket."
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { useDialog } from "Explorer/Controls/Dialog";
|
||||
import promiseRetry, { AbortError } from "p-retry";
|
||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||
import { allowedJunoOrigins, validateEndpoint } from "Utils/EndpointValidation";
|
||||
@ -16,9 +17,14 @@ import {
|
||||
ContainerConnectionInfo,
|
||||
ContainerInfo,
|
||||
IContainerData,
|
||||
IMaxAllocationTimeExceeded,
|
||||
IMaxDbAccountsPerUserExceeded,
|
||||
IMaxUsersPerDbAccountExceeded,
|
||||
IPhoenixConnectionInfoResult,
|
||||
IProvisionData,
|
||||
IResponse,
|
||||
IValidationError,
|
||||
PhoenixErrorType,
|
||||
} from "../Contracts/DataModels";
|
||||
import { useNotebook } from "../Explorer/Notebook/useNotebook";
|
||||
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
|
||||
@ -45,23 +51,25 @@ export class PhoenixClient {
|
||||
provisionData: IProvisionData,
|
||||
operation: string
|
||||
): Promise<IResponse<IPhoenixConnectionInfoResult>> {
|
||||
let response;
|
||||
try {
|
||||
const response = await fetch(`${this.getPhoenixControlPlanePathPrefix()}/containerconnections`, {
|
||||
response = await fetch(`${this.getPhoenixControlPlanePathPrefix()}/containerconnections`, {
|
||||
method: operation === "allocate" ? "POST" : "PATCH",
|
||||
headers: PhoenixClient.getHeaders(),
|
||||
body: JSON.stringify(provisionData),
|
||||
});
|
||||
|
||||
let data: IPhoenixConnectionInfoResult;
|
||||
if (response.status === HttpStatusCodes.OK) {
|
||||
data = await response.json();
|
||||
const responseJson = await response?.json();
|
||||
if (response.status === HttpStatusCodes.Forbidden) {
|
||||
throw new Error(this.ConvertToForbiddenErrorString(responseJson));
|
||||
}
|
||||
return {
|
||||
status: response.status,
|
||||
data,
|
||||
data: responseJson,
|
||||
};
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
if (response.status === HttpStatusCodes.Forbidden) {
|
||||
error.status = HttpStatusCodes.Forbidden;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@ -108,6 +116,18 @@ export class PhoenixClient {
|
||||
});
|
||||
useNotebook.getState().resetContainerConnection(connectionStatus);
|
||||
useNotebook.getState().setIsRefreshed(!useNotebook.getState().isRefreshed);
|
||||
useDialog
|
||||
.getState()
|
||||
.showOkModalDialog(
|
||||
"Disconnected",
|
||||
"Disconnected from temporary workspace. Please click on connect button to connect to temporary workspace."
|
||||
);
|
||||
throw new AbortError(response.statusText);
|
||||
} else if (response?.status === HttpStatusCodes.Forbidden) {
|
||||
const validationMessage = this.ConvertToForbiddenErrorString(await response.json());
|
||||
if (validationMessage) {
|
||||
useDialog.getState().showOkModalDialog("Connection Failed", `${validationMessage}`);
|
||||
}
|
||||
throw new AbortError(response.statusText);
|
||||
}
|
||||
throw new Error(response.statusText);
|
||||
@ -177,4 +197,48 @@ export class PhoenixClient {
|
||||
[HttpHeaders.contentType]: "application/json",
|
||||
};
|
||||
}
|
||||
|
||||
public ConvertToForbiddenErrorString(jsonData: IValidationError): string {
|
||||
const errInfo = jsonData;
|
||||
switch (errInfo?.type) {
|
||||
case PhoenixErrorType.MaxAllocationTimeExceeded: {
|
||||
const maxAllocationTimeExceeded = errInfo as IMaxAllocationTimeExceeded;
|
||||
const allocateAfterTimestamp = new Date(maxAllocationTimeExceeded?.earliestAllocationTimestamp);
|
||||
allocateAfterTimestamp.setDate(allocateAfterTimestamp.getDate() + 1);
|
||||
return (
|
||||
`${errInfo.message}` +
|
||||
" Max allocation time for a day to a user is " +
|
||||
`${maxAllocationTimeExceeded.maxAllocationTimePerDayPerUserInMinutes}` +
|
||||
". Please try again after " +
|
||||
`${allocateAfterTimestamp.toLocaleString()}`
|
||||
);
|
||||
}
|
||||
case PhoenixErrorType.MaxDbAccountsPerUserExceeded: {
|
||||
const maxDbAccountsPerUserExceeded = errInfo as IMaxDbAccountsPerUserExceeded;
|
||||
return (
|
||||
`${errInfo.message}` +
|
||||
" Max simultaneous connections allowed per user is " +
|
||||
`${maxDbAccountsPerUserExceeded.maxSimultaneousConnectionsPerUser}` +
|
||||
"."
|
||||
);
|
||||
}
|
||||
case PhoenixErrorType.MaxUsersPerDbAccountExceeded: {
|
||||
const maxUsersPerDbAccountExceeded = errInfo as IMaxUsersPerDbAccountExceeded;
|
||||
return (
|
||||
`${errInfo.message}` +
|
||||
" Max simultaneous users allowed per DbAccount is " +
|
||||
`${maxUsersPerDbAccountExceeded.maxSimultaneousUsersPerDbAccount}` +
|
||||
"."
|
||||
);
|
||||
}
|
||||
case PhoenixErrorType.AllocationValidationResult:
|
||||
case PhoenixErrorType.RegionNotServicable:
|
||||
case PhoenixErrorType.SubscriptionNotAllowed: {
|
||||
return `${errInfo.message}`;
|
||||
}
|
||||
default: {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user