From bdb5278ad106c822e327355f5b237a353b457e7e Mon Sep 17 00:00:00 2001 From: Jan Keromnes Date: Thu, 2 Sep 2021 16:28:53 +0000 Subject: [PATCH 1/8] [dashboard] Rename 'Detecting project type' to 'Detecting project configuration' --- components/dashboard/src/projects/ConfigureProject.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/dashboard/src/projects/ConfigureProject.tsx b/components/dashboard/src/projects/ConfigureProject.tsx index 41cd4333ac7b49..34feaadbf617cf 100644 --- a/components/dashboard/src/projects/ConfigureProject.tsx +++ b/components/dashboard/src/projects/ConfigureProject.tsx @@ -166,7 +166,7 @@ export default function () { {isDetecting &&
- Detecting project type ... + Detecting project configuration ...
}
From 27814624961799f5508c0016694c0f77b9a104e7 Mon Sep 17 00:00:00 2001 From: Jan Keromnes Date: Tue, 31 Aug 2021 09:47:44 +0000 Subject: [PATCH 2/8] [dashboard] Add more discoverable 'change' link when adding projects from GitLab/GitHub --- components/dashboard/src/projects/NewProject.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/dashboard/src/projects/NewProject.tsx b/components/dashboard/src/projects/NewProject.tsx index 9d81b25e5ddb9d..0fcd1a66660d1e 100644 --- a/components/dashboard/src/projects/NewProject.tsx +++ b/components/dashboard/src/projects/NewProject.tsx @@ -385,7 +385,7 @@ export default function NewProject() { return (

New Project

-

Select a git repository on {provider}.

+

Select a git repository on {provider}. ( setShowGitProviders(true)}>change)

{!selectedRepo && renderSelectRepository()} From 302e76373141ea18ac3238f5448a7f0869e2e267 Mon Sep 17 00:00:00 2001 From: Jan Keromnes Date: Tue, 31 Aug 2021 13:09:25 +0000 Subject: [PATCH 3/8] [dashboard][server] Accelerate Prebuilds page by making branchName optional for server.triggerPrebuild() --- components/dashboard/src/projects/Prebuilds.tsx | 10 ++-------- components/gitpod-protocol/src/gitpod-service.ts | 2 +- .../server/ee/src/workspace/gitpod-server-impl.ts | 8 +++++--- components/server/src/workspace/gitpod-server-impl.ts | 2 +- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/components/dashboard/src/projects/Prebuilds.tsx b/components/dashboard/src/projects/Prebuilds.tsx index ef9f152599d63b..f9c14b38da09e3 100644 --- a/components/dashboard/src/projects/Prebuilds.tsx +++ b/components/dashboard/src/projects/Prebuilds.tsx @@ -27,7 +27,6 @@ export default function () { const projectName = match?.params?.resource; const [project, setProject] = useState(); - const [defaultBranch, setDefaultBranch] = useState(); const [searchFilter, setSearchFilter] = useState(); const [statusFilter, setStatusFilter] = useState(); @@ -66,11 +65,6 @@ export default function () { const newProject = projectName && projects.find(p => p.name === projectName); if (newProject) { setProject(newProject); - - const details = await getGitpodService().server.getProjectOverview(newProject.id); - if (details?.branches) { - setDefaultBranch(details.branches.find(b => b.isDefault)?.name); - } } })(); }, [teams]); @@ -124,7 +118,7 @@ export default function () { history.push(`/${!!team ? team.slug : 'projects'}/${projectName}/${pb.id}`); } - const triggerPrebuild = (branchName: string) => { + const triggerPrebuild = (branchName: string | null) => { if (project) { getGitpodService().server.triggerPrebuild(project.id, branchName); } @@ -148,7 +142,7 @@ export default function () {
- +
diff --git a/components/gitpod-protocol/src/gitpod-service.ts b/components/gitpod-protocol/src/gitpod-service.ts index e36ba9c81af31b..b1a3bae8897ca0 100644 --- a/components/gitpod-protocol/src/gitpod-service.ts +++ b/components/gitpod-protocol/src/gitpod-service.ts @@ -132,7 +132,7 @@ export interface GitpodServer extends JsonRpcServer, AdminServer, getUserProjects(): Promise; getProjectOverview(projectId: string): Promise; findPrebuilds(params: FindPrebuildsParams): Promise; - triggerPrebuild(projectId: string, branch: string): Promise; + triggerPrebuild(projectId: string, branchName: string | null): Promise; setProjectConfiguration(projectId: string, configString: string): Promise; fetchProjectRepositoryConfiguration(projectId: string): Promise; guessProjectConfiguration(projectId: string): Promise; diff --git a/components/server/ee/src/workspace/gitpod-server-impl.ts b/components/server/ee/src/workspace/gitpod-server-impl.ts index 89eb84cbe29ee9..14535fb7ea22e6 100644 --- a/components/server/ee/src/workspace/gitpod-server-impl.ts +++ b/components/server/ee/src/workspace/gitpod-server-impl.ts @@ -1508,7 +1508,7 @@ export class GitpodServerEEImpl extends GitpodServerImpl { + async triggerPrebuild(projectId: string, branchName: string | null): Promise { const user = this.checkAndBlockUser("triggerPrebuild"); const project = await this.projectsService.getProject(projectId); @@ -1520,7 +1520,9 @@ export class GitpodServerEEImpl extends GitpodServerImpl b.isDefault)); if (branchDetails.length !== 1) { log.debug({ userId: user.id }, 'Cannot find branch details.', { project, branchName }); } @@ -1533,7 +1535,7 @@ export class GitpodServerEEImpl extends GitpodServerImpl { + public async triggerPrebuild(projectId: string, branchName: string | null): Promise { this.checkAndBlockUser("triggerPrebuild"); // implemented in EE } From 3b896ac4f650148948fe77152986cc6eccbc3aa4 Mon Sep 17 00:00:00 2001 From: Jan Keromnes Date: Wed, 1 Sep 2021 10:27:46 +0000 Subject: [PATCH 4/8] [server][protocol] Make server.triggerPrebuild() return the StartPrebuildResult --- components/gitpod-protocol/src/gitpod-service.ts | 4 ++-- components/gitpod-protocol/src/teams-projects-protocol.ts | 6 ++++++ components/server/ee/src/prebuilds/bitbucket-app.ts | 3 +-- components/server/ee/src/prebuilds/github-app.ts | 4 ++-- components/server/ee/src/prebuilds/gitlab-app.ts | 3 +-- components/server/ee/src/prebuilds/prebuild-manager.ts | 8 +------- components/server/ee/src/workspace/gitpod-server-impl.ts | 8 ++++---- components/server/src/workspace/gitpod-server-impl.ts | 6 +++--- 8 files changed, 20 insertions(+), 22 deletions(-) diff --git a/components/gitpod-protocol/src/gitpod-service.ts b/components/gitpod-protocol/src/gitpod-service.ts index b1a3bae8897ca0..06fb109675f262 100644 --- a/components/gitpod-protocol/src/gitpod-service.ts +++ b/components/gitpod-protocol/src/gitpod-service.ts @@ -13,7 +13,7 @@ import { } from './protocol'; import { Team, TeamMemberInfo, - TeamMembershipInvite, Project, TeamMemberRole, PrebuildWithStatus + TeamMembershipInvite, Project, TeamMemberRole, PrebuildWithStatus, StartPrebuildResult } from './teams-projects-protocol'; import { JsonRpcProxy, JsonRpcServer } from './messaging/proxy-factory'; import { Disposable, CancellationTokenSource } from 'vscode-jsonrpc'; @@ -132,7 +132,7 @@ export interface GitpodServer extends JsonRpcServer, AdminServer, getUserProjects(): Promise; getProjectOverview(projectId: string): Promise; findPrebuilds(params: FindPrebuildsParams): Promise; - triggerPrebuild(projectId: string, branchName: string | null): Promise; + triggerPrebuild(projectId: string, branchName: string | null): Promise; setProjectConfiguration(projectId: string, configString: string): Promise; fetchProjectRepositoryConfiguration(projectId: string): Promise; guessProjectConfiguration(projectId: string): Promise; diff --git a/components/gitpod-protocol/src/teams-projects-protocol.ts b/components/gitpod-protocol/src/teams-projects-protocol.ts index 376fb9b124ef24..b96f800512047f 100644 --- a/components/gitpod-protocol/src/teams-projects-protocol.ts +++ b/components/gitpod-protocol/src/teams-projects-protocol.ts @@ -90,6 +90,12 @@ export namespace PrebuildInfo { } } +export interface StartPrebuildResult { + wsid: string; + done: boolean; + didFinish?: boolean; +} + export interface Team { id: string; name: string; diff --git a/components/server/ee/src/prebuilds/bitbucket-app.ts b/components/server/ee/src/prebuilds/bitbucket-app.ts index e60f06d5f75692..b2f757c2ddc2a0 100644 --- a/components/server/ee/src/prebuilds/bitbucket-app.ts +++ b/components/server/ee/src/prebuilds/bitbucket-app.ts @@ -7,10 +7,9 @@ import * as express from 'express'; import { postConstruct, injectable, inject } from 'inversify'; import { UserDB } from '@gitpod/gitpod-db/lib'; -import { User } from '@gitpod/gitpod-protocol'; +import { User, StartPrebuildResult } from '@gitpod/gitpod-protocol'; import { PrebuildManager } from '../prebuilds/prebuild-manager'; import { TraceContext } from '@gitpod/gitpod-protocol/lib/util/tracing'; -import { StartPrebuildResult } from './prebuild-manager'; import { TokenService } from '../../../src/user/token-service'; @injectable() diff --git a/components/server/ee/src/prebuilds/github-app.ts b/components/server/ee/src/prebuilds/github-app.ts index 3538b2d98627d4..8b5827b3b0d2d7 100644 --- a/components/server/ee/src/prebuilds/github-app.ts +++ b/components/server/ee/src/prebuilds/github-app.ts @@ -13,11 +13,11 @@ import { Config } from '../../../src/config'; import { AppInstallationDB, TracedWorkspaceDB, DBWithTracing, UserDB, WorkspaceDB, ProjectDB, TeamDB } from '@gitpod/gitpod-db/lib'; import * as express from 'express'; import { log, LogContext } from '@gitpod/gitpod-protocol/lib/util/logging'; -import { WorkspaceConfig, User, Project } from '@gitpod/gitpod-protocol'; +import { WorkspaceConfig, User, Project, StartPrebuildResult } from '@gitpod/gitpod-protocol'; import { MessageBusIntegration } from '../../../src/workspace/messagebus-integration'; import { GithubAppRules } from './github-app-rules'; import { TraceContext } from '@gitpod/gitpod-protocol/lib/util/tracing'; -import { PrebuildManager, StartPrebuildResult } from './prebuild-manager'; +import { PrebuildManager } from './prebuild-manager'; import { PrebuildStatusMaintainer } from './prebuilt-status-maintainer'; import { Options, ApplicationFunctionOptions } from 'probot/lib/types'; diff --git a/components/server/ee/src/prebuilds/gitlab-app.ts b/components/server/ee/src/prebuilds/gitlab-app.ts index 2620cd8ef209f8..6c93fdb9b025e1 100644 --- a/components/server/ee/src/prebuilds/gitlab-app.ts +++ b/components/server/ee/src/prebuilds/gitlab-app.ts @@ -7,10 +7,9 @@ import * as express from 'express'; import { postConstruct, injectable, inject } from 'inversify'; import { ProjectDB, TeamDB, UserDB } from '@gitpod/gitpod-db/lib'; -import { Project, User } from '@gitpod/gitpod-protocol'; +import { Project, User, StartPrebuildResult } from '@gitpod/gitpod-protocol'; import { PrebuildManager } from '../prebuilds/prebuild-manager'; import { TraceContext } from '@gitpod/gitpod-protocol/lib/util/tracing'; -import { StartPrebuildResult } from './prebuild-manager'; import { TokenService } from '../../../src/user/token-service'; import { HostContextProvider } from '../../../src/auth/host-context-provider'; import { GitlabService } from './gitlab-service'; diff --git a/components/server/ee/src/prebuilds/prebuild-manager.ts b/components/server/ee/src/prebuilds/prebuild-manager.ts index c290bff5cf777b..60e5a38bf2f873 100644 --- a/components/server/ee/src/prebuilds/prebuild-manager.ts +++ b/components/server/ee/src/prebuilds/prebuild-manager.ts @@ -5,7 +5,7 @@ */ import { DBWithTracing, TracedWorkspaceDB, WorkspaceDB } from '@gitpod/gitpod-db/lib'; -import { CommitContext, Project, StartPrebuildContext, User, WorkspaceConfig, WorkspaceInstance } from '@gitpod/gitpod-protocol'; +import { CommitContext, Project, StartPrebuildContext, StartPrebuildResult, User, WorkspaceConfig, WorkspaceInstance } from '@gitpod/gitpod-protocol'; import { log } from '@gitpod/gitpod-protocol/lib/util/logging'; import { TraceContext } from '@gitpod/gitpod-protocol/lib/util/tracing'; import { inject, injectable } from 'inversify'; @@ -30,12 +30,6 @@ export interface StartPrebuildParams { commit: string; project?: Project; } -export interface StartPrebuildResult { - wsid: string; - done: boolean; - didFinish?: boolean; -} - @injectable() export class PrebuildManager { diff --git a/components/server/ee/src/workspace/gitpod-server-impl.ts b/components/server/ee/src/workspace/gitpod-server-impl.ts index 14535fb7ea22e6..268d981c88793f 100644 --- a/components/server/ee/src/workspace/gitpod-server-impl.ts +++ b/components/server/ee/src/workspace/gitpod-server-impl.ts @@ -7,7 +7,7 @@ import { injectable, inject } from "inversify"; import { GitpodServerImpl } from "../../../src/workspace/gitpod-server-impl"; import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing"; -import { GitpodServer, GitpodClient, AdminGetListRequest, User, AdminGetListResult, Permission, AdminBlockUserRequest, AdminModifyRoleOrPermissionRequest, RoleOrPermission, AdminModifyPermanentWorkspaceFeatureFlagRequest, UserFeatureSettings, AdminGetWorkspacesRequest, WorkspaceAndInstance, GetWorkspaceTimeoutResult, WorkspaceTimeoutDuration, WorkspaceTimeoutValues, SetWorkspaceTimeoutResult, WorkspaceContext, CreateWorkspaceMode, WorkspaceCreationResult, PrebuiltWorkspaceContext, CommitContext, PrebuiltWorkspace, PermissionName, WorkspaceInstance, EduEmailDomain, ProviderRepository, Queue, PrebuildWithStatus, CreateProjectParams, Project } from "@gitpod/gitpod-protocol"; +import { GitpodServer, GitpodClient, AdminGetListRequest, User, AdminGetListResult, Permission, AdminBlockUserRequest, AdminModifyRoleOrPermissionRequest, RoleOrPermission, AdminModifyPermanentWorkspaceFeatureFlagRequest, UserFeatureSettings, AdminGetWorkspacesRequest, WorkspaceAndInstance, GetWorkspaceTimeoutResult, WorkspaceTimeoutDuration, WorkspaceTimeoutValues, SetWorkspaceTimeoutResult, WorkspaceContext, CreateWorkspaceMode, WorkspaceCreationResult, PrebuiltWorkspaceContext, CommitContext, PrebuiltWorkspace, PermissionName, WorkspaceInstance, EduEmailDomain, ProviderRepository, Queue, PrebuildWithStatus, CreateProjectParams, Project, StartPrebuildResult } from "@gitpod/gitpod-protocol"; import { ResponseError } from "vscode-jsonrpc"; import { TakeSnapshotRequest, AdmissionLevel, ControlAdmissionRequest, StopWorkspacePolicy, DescribeWorkspaceRequest, SetTimeoutRequest } from "@gitpod/ws-manager/lib"; import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error"; @@ -1508,12 +1508,12 @@ export class GitpodServerEEImpl extends GitpodServerImpl { + async triggerPrebuild(projectId: string, branchName: string | null): Promise { const user = this.checkAndBlockUser("triggerPrebuild"); const project = await this.projectsService.getProject(projectId); if (!project) { - return; + throw new ResponseError(ErrorCodes.NOT_FOUND, "Project not found"); } await this.guardProjectOperation(user, projectId, "update"); @@ -1530,7 +1530,7 @@ export class GitpodServerEEImpl extends GitpodServerImpl { + public async triggerPrebuild(projectId: string, branchName: string | null): Promise { this.checkAndBlockUser("triggerPrebuild"); - // implemented in EE + throw new ResponseError(ErrorCodes.EE_FEATURE, `Triggering Prebuilds is implemented in Gitpod's Enterprise Edition`); } public async setProjectConfiguration(projectId: string, configString: string): Promise { From ff1a0bfa2e482583438b9118a5f0e18141cb54b6 Mon Sep 17 00:00:00 2001 From: Jan Keromnes Date: Tue, 31 Aug 2021 09:46:50 +0000 Subject: [PATCH 5/8] [dashboard] Enable 'Run Prebuild' button for Git-based configurations --- components/dashboard/src/projects/ConfigureProject.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/components/dashboard/src/projects/ConfigureProject.tsx b/components/dashboard/src/projects/ConfigureProject.tsx index 34feaadbf617cf..b9b8279280cdd6 100644 --- a/components/dashboard/src/projects/ConfigureProject.tsx +++ b/components/dashboard/src/projects/ConfigureProject.tsx @@ -131,7 +131,9 @@ export default function () { } try { setPrebuildWasTriggered(true); - await getGitpodService().server.setProjectConfiguration(project.id, gitpodYml); + if (!isEditorDisabled) { + await getGitpodService().server.setProjectConfiguration(project.id, gitpodYml); + } const result = await getGitpodService().server.createWorkspace({ contextUrl: `prebuild/${project.cloneUrl}`, mode: CreateWorkspaceMode.ForceNew, @@ -182,7 +184,7 @@ export default function () { {prebuildWasTriggered && }
- +
From 788e766a0d3296536c339216e340c65c6284ca67 Mon Sep 17 00:00:00 2001 From: Jan Keromnes Date: Wed, 1 Sep 2021 10:32:12 +0000 Subject: [PATCH 6/8] [dashboard] Refactor Project Configurator from 'manual' prefix to server.triggerPrebuild() Also adjust config precedence: - Git-based config > Project DB config > guess config --- .../src/projects/ConfigureProject.tsx | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/components/dashboard/src/projects/ConfigureProject.tsx b/components/dashboard/src/projects/ConfigureProject.tsx index b9b8279280cdd6..5e5ddb98825034 100644 --- a/components/dashboard/src/projects/ConfigureProject.tsx +++ b/components/dashboard/src/projects/ConfigureProject.tsx @@ -6,7 +6,7 @@ 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"; @@ -69,7 +69,7 @@ export default function () { const [ isEditorDisabled, setIsEditorDisabled ] = useState(true); const [ isDetecting, setIsDetecting ] = useState(true); const [ prebuildWasTriggered, setPrebuildWasTriggered ] = useState(false); - const [ workspaceCreationResult, setWorkspaceCreationResult ] = useState(); + const [ startPrebuildResult, setStartPrebuildResult ] = useState(); const [ prebuildPhase, setPrebuildPhase ] = useState(); const { isDark } = useContext(ThemeContext); @@ -97,12 +97,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(); 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 +116,6 @@ export default function () { setGitpodYml(guessedConfigString); return; } - if (project.config && project.config['.gitpod.yml']) { - setGitpodYml(project.config['.gitpod.yml']); - return; - } setEditorMessage(); setGitpodYml(TASKS.Other); })(); @@ -126,19 +127,16 @@ export default function () { } // (event.target as HTMLButtonElement).disabled = true; setEditorMessage(null); - if (!!workspaceCreationResult) { - setWorkspaceCreationResult(undefined); + if (!!startPrebuildResult) { + setStartPrebuildResult(undefined); } try { setPrebuildWasTriggered(true); if (!isEditorDisabled) { await getGitpodService().server.setProjectConfiguration(project.id, gitpodYml); } - const result = await getGitpodService().server.createWorkspace({ - contextUrl: `prebuild/${project.cloneUrl}`, - mode: CreateWorkspaceMode.ForceNew, - }); - setWorkspaceCreationResult(result); + const result = await getGitpodService().server.triggerPrebuild(project.id, null); + setStartPrebuildResult(result); } catch (error) { setPrebuildWasTriggered(false); setEditorMessage(); @@ -172,8 +170,8 @@ export default function () { }
-
{workspaceCreationResult - ? +
{startPrebuildResult + ? :

No Recent Prebuild

From 1f4f75b453c2e417d0db7c6f839ed9eaf3c11b11 Mon Sep 17 00:00:00 2001 From: Jan Keromnes Date: Mon, 30 Aug 2021 14:29:48 +0000 Subject: [PATCH 7/8] [dashboard] Adjust Prebuild page to specs --- .../src/projects/ConfigureProject.tsx | 59 ++-------------- .../dashboard/src/projects/Prebuild.tsx | 25 +++++-- .../dashboard/src/projects/Prebuilds.tsx | 68 ++++++++++++++++++- 3 files changed, 92 insertions(+), 60 deletions(-) diff --git a/components/dashboard/src/projects/ConfigureProject.tsx b/components/dashboard/src/projects/ConfigureProject.tsx index 5e5ddb98825034..591d3aaf4f6edb 100644 --- a/components/dashboard/src/projects/ConfigureProject.tsx +++ b/components/dashboard/src/projects/ConfigureProject.tsx @@ -14,12 +14,10 @@ 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')); @@ -70,7 +68,7 @@ export default function () { const [ isDetecting, setIsDetecting ] = useState(true); const [ prebuildWasTriggered, setPrebuildWasTriggered ] = useState(false); const [ startPrebuildResult, setStartPrebuildResult ] = useState(); - const [ prebuildPhase, setPrebuildPhase ] = useState(); + const [ prebuildInstance, setPrebuildInstance ] = useState(); const { isDark } = useContext(ThemeContext); useEffect(() => { @@ -144,7 +142,7 @@ export default function () { } const onInstanceUpdate = (instance: WorkspaceInstance) => { - setPrebuildPhase(instance.status.phase); + setPrebuildInstance(instance); } useEffect(() => { document.title = 'Configure Project — Gitpod' }, []); @@ -179,7 +177,7 @@ export default function () {
}
- {prebuildWasTriggered && } + {prebuildWasTriggered && }
@@ -196,51 +194,4 @@ function EditorMessage(props: { heading: string, message: string, type: 'success
; } -function PrebuildStatus(props: { prebuildPhase?: string, isDark?: boolean }) { - let status = <>; - let details = <>; - switch (props.prebuildPhase) { - case undefined: // Fall through - case 'unknown': - status =
- - PENDING -
; - details =
- - Prebuild in progress ... -
; - break; - case 'preparing': // Fall through - case 'pending': // Fall through - case 'creating': // Fall through - case 'initializing': // Fall through - case 'running': // Fall through - case 'interrupted': - status =
- - RUNNING -
; - details =
- - Prebuild in progress ... -
; - break; - case 'stopping': // Fall through - case 'stopped': - status =
- - READY -
; - // TODO(janx): Calculate actual duration from prebuild instance. - details =
- - 00:34 -
; - break; - } - return
-
{status}
-
{details}
-
; -} + diff --git a/components/dashboard/src/projects/Prebuild.tsx b/components/dashboard/src/projects/Prebuild.tsx index d3dcdbcca8217e..f04188ddd6d9f5 100644 --- a/components/dashboard/src/projects/Prebuild.tsx +++ b/components/dashboard/src/projects/Prebuild.tsx @@ -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 PrebuildLogs from "../components/PrebuildLogs"; import { getGitpodService } from "../service/service"; import { TeamsContext, getCurrentTeam } from "../teams/teams-context"; -import { prebuildStatusIcon, prebuildStatusLabel } from "./Prebuilds"; -import PrebuildLogs from "../components/PrebuildLogs"; +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(); + const [ prebuildInstance, setPrebuildInstance ] = useState(); + const { isDark } = useContext(ThemeContext); useEffect(() => { if (!teams || !projectName || !prebuildId) { @@ -78,13 +81,25 @@ export default function () {
) }; + const onInstanceUpdate = (instance: WorkspaceInstance) => { + setPrebuildInstance(instance); + } + useEffect(() => { document.title = 'Prebuild — Gitpod' }, []); return <>
-
- +
+
+ +
+
+ {prebuildInstance && } +
+ + +
; diff --git a/components/dashboard/src/projects/Prebuilds.tsx b/components/dashboard/src/projects/Prebuilds.tsx index f9c14b38da09e3..312807147a4677 100644 --- a/components/dashboard/src/projects/Prebuilds.tsx +++ b/components/dashboard/src/projects/Prebuilds.tsx @@ -5,12 +5,18 @@ */ import moment from "moment"; -import { PrebuildInfo, PrebuildWithStatus, PrebuiltWorkspaceState, Project } from "@gitpod/gitpod-protocol"; +import { PrebuildInfo, PrebuildWithStatus, PrebuiltWorkspaceState, Project, WorkspaceInstance } from "@gitpod/gitpod-protocol"; import { useContext, useEffect, useState } from "react"; import { useHistory, useLocation, useRouteMatch } from "react-router"; import Header from "../components/Header"; import DropDown, { DropDownEntry } from "../components/DropDown"; import { ItemsList, Item, ItemField, ItemFieldContextMenu } from "../components/ItemsList"; +import Spinner from "../icons/Spinner.svg"; +import SpinnerDark from "../icons/SpinnerDark.svg"; +import StatusDone from "../icons/StatusDone.svg"; +import StatusFailed from "../icons/StatusFailed.svg"; +import StatusPaused from "../icons/StatusPaused.svg"; +import StatusRunning from "../icons/StatusRunning.svg"; import { getGitpodService } from "../service/service"; import { TeamsContext, getCurrentTeam } from "../teams/teams-context"; import { ContextMenuEntry } from "../components/ContextMenu"; @@ -201,6 +207,7 @@ export function prebuildStatusLabel(status: PrebuiltWorkspaceState | undefined) break; } } + export function prebuildStatusIcon(status: PrebuiltWorkspaceState | undefined) { switch (status) { case "aborted": @@ -222,4 +229,63 @@ export function prebuildStatusIcon(status: PrebuiltWorkspaceState | undefined) { default: break; } +} + +export function PrebuildInstanceStatus(props: { prebuildInstance?: WorkspaceInstance, isDark?: boolean }) { + let status = <>; + let details = <>; + switch (props.prebuildInstance?.status.phase) { + case undefined: // Fall through + case 'unknown': + status =
+ + PENDING +
; + details =
+ + Prebuild in progress ... +
; + break; + case 'preparing': // Fall through + case 'pending': // Fall through + case 'creating': // Fall through + case 'initializing': // Fall through + case 'running': // Fall through + case 'interrupted': + status =
+ + RUNNING +
; + details =
+ + Prebuild in progress ... +
; + break; + case 'stopping': // Fall through + case 'stopped': + status =
+ + READY +
; + details =
+ + {!!props.prebuildInstance?.stoppedTime + ? `${Math.round(((new Date(props.prebuildInstance.stoppedTime).getTime()) - (new Date(props.prebuildInstance.creationTime).getTime())) / 1000)}s` + : '...'} +
; + break; + } + if (props.prebuildInstance?.status.conditions.failed) { + status =
+ + FAILED +
; + details =
+ Prebuild failed +
; + } + return
+
{status}
+
{details}
+
; } \ No newline at end of file From 12afee9336ee1e049817a83a5d54e53c90c980bd Mon Sep 17 00:00:00 2001 From: Jan Keromnes Date: Thu, 2 Sep 2021 12:51:51 +0000 Subject: [PATCH 8/8] [server][dashboard] Fix PrebuildLogs buttons (Run Prebuild, New Workspace) --- .../dashboard/src/components/PrebuildLogs.tsx | 82 +++++++++---------- .../src/projects/ConfigureProject.tsx | 10 ++- .../dashboard/src/projects/Prebuild.tsx | 7 +- components/dashboard/src/projects/Project.tsx | 8 -- .../ee/src/workspace/gitpod-server-impl.ts | 1 + .../ee/src/workspace/workspace-factory.ts | 63 +++++++------- 6 files changed, 85 insertions(+), 86 deletions(-) diff --git a/components/dashboard/src/components/PrebuildLogs.tsx b/components/dashboard/src/components/PrebuildLogs.tsx index 080684fb3bdb9e..a5bed9ce95e936 100644 --- a/components/dashboard/src/components/PrebuildLogs.tsx +++ b/components/dashboard/src/components/PrebuildLogs.tsx @@ -68,47 +68,47 @@ export default function PrebuildLogs(props: PrebuildLogsProps) { case "unknown": break; - // 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": - getGitpodService().server.watchWorkspaceImageBuildLogs(workspace!.id); - 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": - 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": - 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": - 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": - 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": - break; - - // Stopping means that the workspace is currently shutting down. It could go to stopped every moment. - case "stopping": - break; - - // Stopped means the workspace ended regularly because it was shut down. - case "stopped": - getGitpodService().server.watchWorkspaceImageBuildLogs(workspace!.id); - break; + // 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": + getGitpodService().server.watchWorkspaceImageBuildLogs(workspace!.id); + 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": + 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": + 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": + 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": + 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": + break; + + // Stopping means that the workspace is currently shutting down. It could go to stopped every moment. + case "stopping": + break; + + // Stopped means the workspace ended regularly because it was shut down. + case "stopped": + getGitpodService().server.watchWorkspaceImageBuildLogs(workspace!.id); + break; } if (workspaceInstance?.status.conditions.failed) { setError(new Error(workspaceInstance.status.conditions.failed)); diff --git a/components/dashboard/src/projects/ConfigureProject.tsx b/components/dashboard/src/projects/ConfigureProject.tsx index 591d3aaf4f6edb..556d2c0994d5c3 100644 --- a/components/dashboard/src/projects/ConfigureProject.tsx +++ b/components/dashboard/src/projects/ConfigureProject.tsx @@ -170,17 +170,19 @@ export default function () {
{startPrebuildResult ? - :
+ : (!prebuildWasTriggered &&

No Recent Prebuild

Edit the project configuration on the left to get started. Learn more

-
+
) }
{prebuildWasTriggered && }
- - + {(prebuildInstance?.status.phase === "stopped" && !prebuildInstance?.status.conditions.failed) + ? + : } +
diff --git a/components/dashboard/src/projects/Prebuild.tsx b/components/dashboard/src/projects/Prebuild.tsx index f04188ddd6d9f5..5a6a438aa21c79 100644 --- a/components/dashboard/src/projects/Prebuild.tsx +++ b/components/dashboard/src/projects/Prebuild.tsx @@ -10,7 +10,7 @@ import { useContext, useEffect, useState } from "react"; import { useLocation, useRouteMatch } from "react-router"; import Header from "../components/Header"; import PrebuildLogs from "../components/PrebuildLogs"; -import { getGitpodService } from "../service/service"; +import { getGitpodService, gitpodHostUrl } from "../service/service"; import { TeamsContext, getCurrentTeam } from "../teams/teams-context"; import { ThemeContext } from "../theme-context"; import { prebuildStatusIcon, prebuildStatusLabel, PrebuildInstanceStatus } from "./Prebuilds"; @@ -97,8 +97,9 @@ export default function () {
{prebuildInstance && }
- - + {prebuildInstance?.status.phase === "stopped" + ? + : }
diff --git a/components/dashboard/src/projects/Project.tsx b/components/dashboard/src/projects/Project.tsx index 4cec1994295953..64e2d545303b1d 100644 --- a/components/dashboard/src/projects/Project.tsx +++ b/components/dashboard/src/projects/Project.tsx @@ -63,10 +63,6 @@ export default function () { const branchContextMenu = (branch: Project.BranchDetails) => { const entries: ContextMenuEntry[] = []; - entries.push({ - title: "New Workspace", - onClick: () => onNewWorkspace(branch) - }); entries.push({ title: "Rerun Prebuild", onClick: () => triggerPrebuild(branch), @@ -109,10 +105,6 @@ export default function () { return true; } - const onNewWorkspace = (branch: Project.BranchDetails) => { - window.location.href = gitpodHostUrl.withContext(`${branch.url}`).toString(); - } - const triggerPrebuild = (branch: Project.BranchDetails) => { if (project) { getGitpodService().server.triggerPrebuild(project.id, branch.name) diff --git a/components/server/ee/src/workspace/gitpod-server-impl.ts b/components/server/ee/src/workspace/gitpod-server-impl.ts index 268d981c88793f..b39e9bab136042 100644 --- a/components/server/ee/src/workspace/gitpod-server-impl.ts +++ b/components/server/ee/src/workspace/gitpod-server-impl.ts @@ -1525,6 +1525,7 @@ export class GitpodServerEEImpl extends GitpodServerImpl b.isDefault)); if (branchDetails.length !== 1) { log.debug({ userId: user.id }, 'Cannot find branch details.', { project, branchName }); + throw new ResponseError(ErrorCodes.NOT_FOUND, `Could not find ${!branchName ? 'a default branch' : `branch '${branchName}'`} in repository ${project.cloneUrl}`); } const contextURL = branchDetails[0].url; diff --git a/components/server/ee/src/workspace/workspace-factory.ts b/components/server/ee/src/workspace/workspace-factory.ts index 0fb1ecf7277fb0..fe878fca7d08d9 100644 --- a/components/server/ee/src/workspace/workspace-factory.ts +++ b/components/server/ee/src/workspace/workspace-factory.ts @@ -133,7 +133,7 @@ export class WorkspaceFactoryEE extends WorkspaceFactory { { // TODO(at) store prebuild info if (project) { // do not await - this.storePrebuildInfo(ctx, project, pws, user).catch(err => { + this.storePrebuildInfo(ctx, project, pws, ws, user).catch(err => { log.error(`failed to store prebuild info`, err); TraceContext.logError({span}, err); }); @@ -152,39 +152,42 @@ export class WorkspaceFactoryEE extends WorkspaceFactory { } } - protected async storePrebuildInfo(ctx: TraceContext, project: Project, pws: PrebuiltWorkspace, user: User) { + protected async storePrebuildInfo(ctx: TraceContext, project: Project, pws: PrebuiltWorkspace, ws: Workspace, user: User) { const span = TraceContext.startSpan("storePrebuildInfo", ctx); const { userId, teamId, name: projectName, id: projectId } = project; const parsedUrl = parseRepoUrl(project.cloneUrl); - if (parsedUrl) { - const { owner, repo, host } = parsedUrl; - const repositoryProvider = this.hostContextProvider.get(host)?.services?.repositoryProvider; - if (repositoryProvider) { - const commit = await repositoryProvider.getCommitInfo(user, owner, repo, pws.commit); - if (commit) { - await this.db.trace({span}).storePrebuildInfo({ - id: pws.id, - buildWorkspaceId: pws.buildWorkspaceId, - teamId, - userId, - projectName, - projectId, - startedAt: pws.creationTime, - startedBy: "", // TODO - startedByAvatar: "", // TODO - cloneUrl: pws.cloneURL, - branch: pws.branch || "unknown", - changeAuthor: commit.author, - changeAuthorAvatar: commit.authorAvatarUrl, - changeDate: commit.authorDate || "", - changeHash: commit.sha, - changeTitle: commit.commitMessage, - // changePR - // changeUrl - }); - } - } + if (!parsedUrl) { + return; + } + const { owner, repo, host } = parsedUrl; + const repositoryProvider = this.hostContextProvider.get(host)?.services?.repositoryProvider; + if (!repositoryProvider) { + return; + } + const commit = await repositoryProvider.getCommitInfo(user, owner, repo, pws.commit); + if (!commit) { + return; } + await this.db.trace({span}).storePrebuildInfo({ + id: pws.id, + buildWorkspaceId: pws.buildWorkspaceId, + teamId, + userId, + projectName, + projectId, + startedAt: pws.creationTime, + startedBy: "", // TODO + startedByAvatar: "", // TODO + cloneUrl: pws.cloneURL, + branch: pws.branch || "unknown", + changeAuthor: commit.author, + changeAuthorAvatar: commit.authorAvatarUrl, + changeDate: commit.authorDate || "", + changeHash: commit.sha, + changeTitle: commit.commitMessage, + // changePR + changeUrl: ws.contextURL, + }); } protected async createForPrebuiltWorkspace(ctx: TraceContext, user: User, context: PrebuiltWorkspaceContext, normalizedContextURL: string): Promise {