-
Notifications
You must be signed in to change notification settings - Fork 1.3k
[dashboard] Adjust Prebuild and Project Configurator pages to spec #5474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bdb5278
2781462
302e763
3b896ac
ff1a0bf
788e766
1f4f75b
12afee9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,20 +6,18 @@ | |
|
||
import React, { Suspense, useContext, useEffect, useState } from "react"; | ||
import { useLocation, useRouteMatch } from "react-router"; | ||
import { CreateWorkspaceMode, Project, WorkspaceCreationResult, WorkspaceInstance } from "@gitpod/gitpod-protocol"; | ||
import { Project, StartPrebuildResult, WorkspaceInstance } from "@gitpod/gitpod-protocol"; | ||
import PrebuildLogs from "../components/PrebuildLogs"; | ||
import TabMenuItem from "../components/TabMenuItem"; | ||
import { getGitpodService } from "../service/service"; | ||
import { getCurrentTeam, TeamsContext } from "../teams/teams-context"; | ||
import Header from "../components/Header"; | ||
import Spinner from "../icons/Spinner.svg"; | ||
import SpinnerDark from "../icons/SpinnerDark.svg"; | ||
import StatusDone from "../icons/StatusDone.svg"; | ||
import StatusPaused from "../icons/StatusPaused.svg"; | ||
import StatusRunning from "../icons/StatusRunning.svg"; | ||
import PrebuildLogsEmpty from "../images/prebuild-logs-empty.svg"; | ||
import PrebuildLogsEmptyDark from "../images/prebuild-logs-empty-dark.svg"; | ||
import { ThemeContext } from "../theme-context"; | ||
import { PrebuildInstanceStatus } from "./Prebuilds"; | ||
|
||
const MonacoEditor = React.lazy(() => import('../components/MonacoEditor')); | ||
|
||
|
@@ -69,8 +67,8 @@ export default function () { | |
const [ isEditorDisabled, setIsEditorDisabled ] = useState<boolean>(true); | ||
const [ isDetecting, setIsDetecting ] = useState<boolean>(true); | ||
const [ prebuildWasTriggered, setPrebuildWasTriggered ] = useState<boolean>(false); | ||
const [ workspaceCreationResult, setWorkspaceCreationResult ] = useState<WorkspaceCreationResult | undefined>(); | ||
const [ prebuildPhase, setPrebuildPhase ] = useState<string | undefined>(); | ||
const [ startPrebuildResult, setStartPrebuildResult ] = useState<StartPrebuildResult | undefined>(); | ||
const [ prebuildInstance, setPrebuildInstance ] = useState<WorkspaceInstance | undefined>(); | ||
const { isDark } = useContext(ThemeContext); | ||
|
||
useEffect(() => { | ||
|
@@ -97,12 +95,17 @@ export default function () { | |
const guessedConfigStringPromise = getGitpodService().server.guessProjectConfiguration(project.id); | ||
const repoConfigString = await getGitpodService().server.fetchProjectRepositoryConfiguration(project.id); | ||
if (repoConfigString) { | ||
// TODO(janx): Link to .gitpod.yml directly instead of just the cloneUrl. | ||
setIsDetecting(false); | ||
setEditorMessage(<EditorMessage type="warning" heading="Configuration already exists in git." message="Run a prebuild or open a new workspace to edit project configuration."/>); | ||
setGitpodYml(repoConfigString); | ||
return; | ||
} | ||
if (project.config && project.config['.gitpod.yml']) { | ||
setIsDetecting(false); | ||
setIsEditorDisabled(false); | ||
setGitpodYml(project.config['.gitpod.yml']); | ||
return; | ||
} | ||
const guessedConfigString = await guessedConfigStringPromise; | ||
setIsDetecting(false); | ||
setIsEditorDisabled(false); | ||
|
@@ -111,10 +114,6 @@ export default function () { | |
setGitpodYml(guessedConfigString); | ||
return; | ||
} | ||
if (project.config && project.config['.gitpod.yml']) { | ||
setGitpodYml(project.config['.gitpod.yml']); | ||
return; | ||
} | ||
setEditorMessage(<EditorMessage type="warning" heading="Project type could not be detected." message="You can edit project configuration below before running a prebuild."/>); | ||
setGitpodYml(TASKS.Other); | ||
})(); | ||
|
@@ -126,25 +125,24 @@ export default function () { | |
} | ||
// (event.target as HTMLButtonElement).disabled = true; | ||
setEditorMessage(null); | ||
if (!!workspaceCreationResult) { | ||
setWorkspaceCreationResult(undefined); | ||
if (!!startPrebuildResult) { | ||
setStartPrebuildResult(undefined); | ||
} | ||
try { | ||
setPrebuildWasTriggered(true); | ||
await getGitpodService().server.setProjectConfiguration(project.id, gitpodYml); | ||
const result = await getGitpodService().server.createWorkspace({ | ||
contextUrl: `prebuild/${project.cloneUrl}`, | ||
mode: CreateWorkspaceMode.ForceNew, | ||
}); | ||
setWorkspaceCreationResult(result); | ||
if (!isEditorDisabled) { | ||
await getGitpodService().server.setProjectConfiguration(project.id, gitpodYml); | ||
} | ||
const result = await getGitpodService().server.triggerPrebuild(project.id, null); | ||
setStartPrebuildResult(result); | ||
} catch (error) { | ||
setPrebuildWasTriggered(false); | ||
setEditorMessage(<EditorMessage type="warning" heading="Could not run prebuild." message={String(error).replace(/Error: Request \w+ failed with message: /, '')}/>); | ||
} | ||
} | ||
|
||
const onInstanceUpdate = (instance: WorkspaceInstance) => { | ||
setPrebuildPhase(instance.status.phase); | ||
setPrebuildInstance(instance); | ||
} | ||
|
||
useEffect(() => { document.title = 'Configure Project — Gitpod' }, []); | ||
|
@@ -166,23 +164,25 @@ export default function () { | |
</Suspense> | ||
{isDetecting && <div className="absolute h-full w-full bg-gray-100 dark:bg-gray-700 flex items-center justify-center space-x-2"> | ||
<img className="h-5 w-5 animate-spin" src={isDark ? SpinnerDark : Spinner} /> | ||
<span className="font-semibold text-gray-400">Detecting project type ...</span> | ||
<span className="font-semibold text-gray-400">Detecting project configuration ...</span> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. praise: Thanks for changing this! New message makes more sense for loading an existing project with a git based configuration. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. question: This is taking noticeably more time sometimes, like 4-5 seconds or more when there's no git based configuration. Expected? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I think we should look if we can do that ahead of time. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could also probably optimize the "config inferrer": It currently makes repository requests one by one (e.g. "does a Fetching the entire repo structure (not necessarily file content or history) in one go, and using that to respond to the "config inferrer"'s queries would already be a huge performance boost. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now tracked as #5527 |
||
</div>} | ||
</div> | ||
<div className="flex-1 h-96 rounded-xl overflow-hidden bg-gray-100 dark:bg-gray-700 flex flex-col"> | ||
<div className="flex-grow flex">{workspaceCreationResult | ||
? <PrebuildLogs workspaceId={workspaceCreationResult.createdWorkspaceId} onInstanceUpdate={onInstanceUpdate} /> | ||
: <div className="flex-grow flex flex-col items-center justify-center"> | ||
<div className="flex-grow flex">{startPrebuildResult | ||
? <PrebuildLogs workspaceId={startPrebuildResult.wsid} onInstanceUpdate={onInstanceUpdate} /> | ||
: (!prebuildWasTriggered && <div className="flex-grow flex flex-col items-center justify-center"> | ||
<img className="w-14" role="presentation" src={isDark ? PrebuildLogsEmptyDark : PrebuildLogsEmpty} /> | ||
<h3 className="text-center text-lg text-gray-500 dark:text-gray-50 mt-4">No Recent Prebuild</h3> | ||
<p className="text-center text-base text-gray-500 dark:text-gray-400 mt-2 w-64">Edit the project configuration on the left to get started. <a className="gp-link" href="https://www.gitpod.io/docs/config-gitpod-file/">Learn more</a></p> | ||
</div> | ||
</div>) | ||
}</div> | ||
<div className="h-20 px-6 bg-gray-50 dark:bg-gray-800 border-t border-gray-200 dark:border-gray-600 flex space-x-2"> | ||
{prebuildWasTriggered && <PrebuildStatus prebuildPhase={prebuildPhase} isDark={isDark} />} | ||
{prebuildWasTriggered && <PrebuildInstanceStatus prebuildInstance={prebuildInstance} isDark={isDark} />} | ||
<div className="flex-grow" /> | ||
<button className="secondary">New Workspace</button> | ||
<button disabled={isEditorDisabled} onClick={buildProject}>Run Prebuild</button> | ||
{(prebuildInstance?.status.phase === "stopped" && !prebuildInstance?.status.conditions.failed) | ||
? <a className="my-auto" href={`/#${project?.cloneUrl}`}><button className="secondary">New Workspace</button></a> | ||
: <button disabled={true} className="secondary">New Workspace</button>} | ||
<button disabled={isDetecting || (prebuildWasTriggered && prebuildInstance?.status.phase !== "stopped")} onClick={buildProject}>Run Prebuild</button> | ||
</div> | ||
</div> | ||
</div> | ||
|
@@ -196,51 +196,4 @@ function EditorMessage(props: { heading: string, message: string, type: 'success | |
</div>; | ||
} | ||
|
||
function PrebuildStatus(props: { prebuildPhase?: string, isDark?: boolean }) { | ||
let status = <></>; | ||
let details = <></>; | ||
switch (props.prebuildPhase) { | ||
case undefined: // Fall through | ||
case 'unknown': | ||
status = <div className="flex space-x-1 items-center text-yellow-600"> | ||
<img className="h-4 w-4" src={StatusPaused} /> | ||
<span>PENDING</span> | ||
</div>; | ||
details = <div className="flex space-x-1 items-center text-gray-400"> | ||
<img className="h-4 w-4 animate-spin" src={props.isDark ? SpinnerDark : Spinner} /> | ||
<span>Prebuild in progress ...</span> | ||
</div>; | ||
break; | ||
case 'preparing': // Fall through | ||
case 'pending': // Fall through | ||
case 'creating': // Fall through | ||
case 'initializing': // Fall through | ||
case 'running': // Fall through | ||
case 'interrupted': | ||
status = <div className="flex space-x-1 items-center text-blue-600"> | ||
<img className="h-4 w-4" src={StatusRunning} /> | ||
<span>RUNNING</span> | ||
</div>; | ||
details = <div className="flex space-x-1 items-center text-gray-400"> | ||
<img className="h-4 w-4 animate-spin" src={props.isDark ? SpinnerDark : Spinner} /> | ||
<span>Prebuild in progress ...</span> | ||
</div>; | ||
break; | ||
case 'stopping': // Fall through | ||
case 'stopped': | ||
status = <div className="flex space-x-1 items-center text-green-600"> | ||
<img className="h-4 w-4" src={StatusDone} /> | ||
<span>READY</span> | ||
</div>; | ||
// TODO(janx): Calculate actual duration from prebuild instance. | ||
details = <div className="flex space-x-1 items-center text-gray-400"> | ||
<img className="h-4 w-4 filter-grayscale" src={StatusRunning} /> | ||
<span>00:34</span> | ||
</div>; | ||
break; | ||
} | ||
return <div className="flex flex-col space-y-1 justify-center text-sm font-semibold"> | ||
<div>{status}</div> | ||
<div>{details}</div> | ||
</div>; | ||
} | ||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -385,7 +385,7 @@ export default function NewProject() { | |||||||
|
||||||||
return (<div className="flex flex-col w-96 mt-24 mx-auto items-center"> | ||||||||
<h1>New Project</h1> | ||||||||
<p className="text-gray-500 text-center text-base">Select a git repository on <strong>{provider}</strong>.</p> | ||||||||
<p className="text-gray-500 text-center text-base">Select a git repository on <strong>{provider}</strong>. (<a className="gp-link cursor-pointer" onClick={() => setShowGitProviders(true)}>change</a>)</p> | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. praise: Thanks for making this more visible! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. suggestion: I think using just the verb change could go unoticed and confuse some users. Following the discussion in #5120 (comment) and the second iteration of the designs for repository selection in #4948, we could use a more verbose message here or below the repositories list. What do you think?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Filed as #5524 |
||||||||
|
||||||||
{!selectedRepo && renderSelectRepository()} | ||||||||
|
||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,14 +5,15 @@ | |
*/ | ||
|
||
import moment from "moment"; | ||
import { PrebuildWithStatus } from "@gitpod/gitpod-protocol"; | ||
import { PrebuildWithStatus, WorkspaceInstance } from "@gitpod/gitpod-protocol"; | ||
import { useContext, useEffect, useState } from "react"; | ||
import { useLocation, useRouteMatch } from "react-router"; | ||
import Header from "../components/Header"; | ||
import { getGitpodService } from "../service/service"; | ||
import { TeamsContext, getCurrentTeam } from "../teams/teams-context"; | ||
import { prebuildStatusIcon, prebuildStatusLabel } from "./Prebuilds"; | ||
import PrebuildLogs from "../components/PrebuildLogs"; | ||
import { getGitpodService, gitpodHostUrl } from "../service/service"; | ||
import { TeamsContext, getCurrentTeam } from "../teams/teams-context"; | ||
import { ThemeContext } from "../theme-context"; | ||
import { prebuildStatusIcon, prebuildStatusLabel, PrebuildInstanceStatus } from "./Prebuilds"; | ||
import { shortCommitMessage } from "./render-utils"; | ||
|
||
export default function () { | ||
|
@@ -26,6 +27,8 @@ export default function () { | |
const prebuildId = match?.params?.prebuildId; | ||
|
||
const [ prebuild, setPrebuild ] = useState<PrebuildWithStatus | undefined>(); | ||
const [ prebuildInstance, setPrebuildInstance ] = useState<WorkspaceInstance | undefined>(); | ||
const { isDark } = useContext(ThemeContext); | ||
|
||
useEffect(() => { | ||
if (!teams || !projectName || !prebuildId) { | ||
|
@@ -78,13 +81,26 @@ export default function () { | |
</div>) | ||
}; | ||
|
||
const onInstanceUpdate = (instance: WorkspaceInstance) => { | ||
setPrebuildInstance(instance); | ||
} | ||
|
||
useEffect(() => { document.title = 'Prebuild — Gitpod' }, []); | ||
|
||
return <> | ||
<Header title={renderTitle()} subtitle={renderSubtitle()} /> | ||
<div className="lg:px-28 px-10 mt-8"> | ||
<div className="h-96 rounded-xl overflow-hidden bg-gray-100 dark:bg-gray-800 flex flex-col"> | ||
<PrebuildLogs workspaceId={prebuild?.info?.buildWorkspaceId}/> | ||
<div className="rounded-xl overflow-hidden bg-gray-100 dark:bg-gray-800 flex flex-col"> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. issue: Could not get any prebuild log output here. Expected? 😭 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It took some time the first time I opened it. But I, at last, got logs. I think this is unrelated to this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, sometimes logs don't show up at all ("Error: could not find headless logs for 1234"). Sometimes, they don't show up live, but eventually the entire logs show up after the prebuild is complete. This morning I also had live logs. It's kind of a shame that this isn't more reliable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We need to look into it (in a separate PR). Can we merge this? 😁 |
||
<div className="h-96 flex"> | ||
<PrebuildLogs workspaceId={prebuild?.info?.buildWorkspaceId} onInstanceUpdate={onInstanceUpdate} /> | ||
</div> | ||
<div className="h-20 px-6 bg-gray-50 dark:bg-gray-800 border-t border-gray-200 dark:border-gray-600 flex space-x-2"> | ||
{prebuildInstance && <PrebuildInstanceStatus prebuildInstance={prebuildInstance} isDark={isDark} />} | ||
<div className="flex-grow" /> | ||
{prebuildInstance?.status.phase === "stopped" | ||
? <a className="my-auto" href={gitpodHostUrl.withContext(`${prebuild?.info.changeUrl}`).toString()}><button>New Workspace</button></a> | ||
: <button disabled={true}>New Workspace</button>} | ||
</div> | ||
</div> | ||
</div> | ||
</>; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
issue: This is probably out of the scope of these changes but noticed that it takes a while to redirect to the configuration page once you select a team. Is this expected or needed? Cc @AlexTugarev
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, @AlexTugarev noticed a UI freeze, and I did too today. Maybe it's indeed MonacoEditor? (It's loaded lazily in the Configurator, in order not to make the entire dashboard slower)