Skip to content

Commit

Permalink
[dashboard] Improve workspace start status messages
Browse files Browse the repository at this point in the history
  • Loading branch information
jankeromnes authored and svenefftinge committed Mar 15, 2021
1 parent 59cba2c commit cfc3af8
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 46 deletions.
2 changes: 1 addition & 1 deletion components/dashboard/src/start/CreateWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class CreateWorkspace extends React.Component<CreateWorkspaceProps, Creat
render() {
const { contextUrl } = this.props;
let phase = StartPhase.Checking;
let statusMessage = <p className="text-base text-gray-400">Creating workspace</p>;
let statusMessage = <p className="text-base text-gray-400">Checking Context</p>;
let logsView = undefined;

const error = this.state?.error;
Expand Down
102 changes: 57 additions & 45 deletions components/dashboard/src/start/StartWorkspace.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ export interface StartWorkspaceProps {
}

export interface StartWorkspaceState {
phase: StartPhase;
contextUrl?: string;
startedInstanceId?: string;
workspaceInstance?: WorkspaceInstance;
error?: StartWorkspaceError;
ideFrontendFailureCause?: string;
}
Expand All @@ -26,9 +26,6 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps,

constructor(props: StartWorkspaceProps) {
super(props);
this.state = {
phase: StartPhase.Building,
};
}

private readonly toDispose = new DisposableCollection();
Expand Down Expand Up @@ -111,7 +108,46 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps,
return;
}

switch (workspaceInstance.status.phase) {
if (workspaceInstance.status.phase === 'preparing') {
this.props.gitpodService.server.watchWorkspaceImageBuildLogs(workspaceInstance.workspaceId);
}

this.setState({ workspaceInstance });
}

async ensureWorkspaceAuth(instanceID: string) {
if (!document.cookie.includes(`${instanceID}_owner_`)) {
const authURL = new GitpodHostUrl(window.location.toString()).asWorkspaceAuth(instanceID);
const response = await fetch(authURL.toString());
if (response.redirected) {
this.redirectTo(response.url);
return;
}
if (!response.ok) {
// getting workspace auth didn't work as planned - redirect
this.redirectTo(authURL.asWorkspaceAuth(instanceID, true).toString());
return;
}
}
}

redirectTo(url: string) {
if (this.runsInIFrame()) {
window.parent.postMessage({ type: 'relocate', url }, '*');
} else {
window.location.href = url;
}
}

runsInIFrame() {
return window.top !== window.self;
}

render() {
let phase = StartPhase.Checking;
let statusMessage = undefined;

switch (this.state?.workspaceInstance?.status.phase) {
// unknown indicates an issue within the system in that it cannot determine the actual phase of
// a workspace. This phase is usually accompanied by an error.
case "unknown":
Expand All @@ -120,84 +156,60 @@ export default class StartWorkspace extends React.Component<StartWorkspaceProps,
// Preparing means that we haven't actually started the workspace instance just yet, but rather
// are still preparing for launch. This means we're building the Docker image for the workspace.
case "preparing":
this.props.gitpodService.server.watchWorkspaceImageBuildLogs(workspaceInstance.workspaceId);
this.setState({ phase: StartPhase.Building });
phase = StartPhase.Building;
statusMessage = <p className="text-base text-gray-400">Building Image …</p>;
break;

// Pending means the workspace does not yet consume resources in the cluster, but rather is looking for
// some space within the cluster. If for example the cluster needs to scale up to accomodate the
// workspace, the workspace will be in Pending state until that happened.
case "pending":
this.setState({ phase: StartPhase.Preparing });
phase = StartPhase.Preparing;
statusMessage = <p className="text-base text-gray-400">Allocating Resources …</p>;
break;

// Creating means the workspace is currently being created. That includes downloading the images required
// to run the workspace over the network. The time spent in this phase varies widely and depends on the current
// network speed, image size and cache states.
case "creating":
this.setState({ phase: StartPhase.Preparing });
phase = StartPhase.Preparing;
statusMessage = <p className="text-base text-gray-400">Pulling Container Image …</p>;
break;

// Initializing is the phase in which the workspace is executing the appropriate workspace initializer (e.g. Git
// clone or backup download). After this phase one can expect the workspace to either be Running or Failed.
case "initializing":
this.setState({ phase: StartPhase.Starting });
phase = StartPhase.Starting;
statusMessage = <p className="text-base text-gray-400">Cloning Repository …</p>; // TODO Loading Prebuild ...
break;

// Running means the workspace is able to actively perform work, either by serving a user through Theia,
// or as a headless workspace.
case "running":
this.setState({ phase: StartPhase.Running });
phase = StartPhase.Running;
statusMessage = <p className="text-base text-gray-400">Opening IDE …</p>;
break;

// Interrupted is an exceptional state where the container should be running but is temporarily unavailable.
// When in this state, we expect it to become running or stopping anytime soon.
case "interrupted":
this.setState({ phase: StartPhase.Running });
phase = StartPhase.Running;
statusMessage = <p className="text-base text-gray-400">Checking On Workspace …</p>;
break;

// Stopping means that the workspace is currently shutting down. It could go to stopped every moment.
case "stopping":
statusMessage = <p className="text-base text-gray-400">Stopping …</p>;
break;

// Stopped means the workspace ended regularly because it was shut down.
case "stopped":
statusMessage = <p className="text-base text-gray-400">Stopped</p>;
break;
}

}

async ensureWorkspaceAuth(instanceID: string) {
if (!document.cookie.includes(`${instanceID}_owner_`)) {
const authURL = new GitpodHostUrl(window.location.toString()).asWorkspaceAuth(instanceID);
const response = await fetch(authURL.toString());
if (response.redirected) {
this.redirectTo(response.url);
return;
}
if (!response.ok) {
// getting workspace auth didn't work as planned - redirect
this.redirectTo(authURL.asWorkspaceAuth(instanceID, true).toString());
return;
}
}
}

redirectTo(url: string) {
if (this.runsInIFrame()) {
window.parent.postMessage({ type: 'relocate', url }, '*');
} else {
window.location.href = url;
}
}

runsInIFrame() {
return window.top !== window.self;
}

render() {
return <StartPage phase={this.state.phase}>
<div className="text-sm text-gray-400">Workspace ID: {this.props.workspaceId}</div>
return <StartPage phase={phase}>
{statusMessage}
</StartPage>;
}
}

0 comments on commit cfc3af8

Please sign in to comment.