Skip to content

Commit ec4e003

Browse files
committed
[projects] add message: Prebuilds have been paused
1 parent c5e353d commit ec4e003

File tree

6 files changed

+52
-9
lines changed

6 files changed

+52
-9
lines changed

Diff for: components/dashboard/src/projects/Project.tsx

+28
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import Spinner from "../icons/Spinner.svg";
1818
import NoAccess from "../icons/NoAccess.svg";
1919
import { ErrorCodes } from "@gitpod/gitpod-protocol/lib/messaging/error";
2020
import { openAuthorizeWindow } from "../provider-utils";
21+
import Alert from "../components/Alert";
2122

2223
export default function () {
2324
const location = useLocation();
@@ -34,6 +35,7 @@ export default function () {
3435
const [isLoading, setIsLoading] = useState<boolean>(false);
3536
const [isLoadingBranches, setIsLoadingBranches] = useState<boolean>(false);
3637
const [branches, setBranches] = useState<Project.BranchDetails[]>([]);
38+
const [isConsideredInactive, setIsConsideredInactive] = useState<boolean>(false);
3739
const [prebuilds, setPrebuilds] = useState<Map<string, PrebuildWithStatus | undefined>>(new Map());
3840
const [prebuildLoaders] = useState<Set<string>>(new Set());
3941

@@ -91,6 +93,7 @@ export default function () {
9193
// default branch on top of the rest
9294
const branches = details.branches.sort((a, b) => (b.isDefault as any) - (a.isDefault as any)) || [];
9395
setBranches(branches);
96+
setIsConsideredInactive(details.prebuildState === "suspended_on_inactivity");
9497
}
9598
} finally {
9699
setIsLoadingBranches(false);
@@ -259,6 +262,31 @@ export default function () {
259262
<span>Prebuild</span>
260263
</ItemField>
261264
</Item>
265+
{isConsideredInactive && (
266+
<Alert
267+
type={"warning"}
268+
onClose={() => {}}
269+
showIcon={true}
270+
className="flex rounded mb-2 w-full"
271+
>
272+
Prebuilds have been paused for this projects because no workspaces were opened for
273+
the past 7+ days.{" "}
274+
<a
275+
href="javascript:void(0)"
276+
className="gp-link hover:text-gray-600"
277+
onClick={() => {
278+
if (project) {
279+
getGitpodService()
280+
.server.triggerPrebuild(project.id, null)
281+
.then(() => setIsConsideredInactive(false))
282+
.catch((e) => console.log(e));
283+
}
284+
}}
285+
>
286+
Resume prebuilds
287+
</a>
288+
</Alert>
289+
)}
262290
{isLoadingBranches && (
263291
<div className="flex items-center justify-center space-x-2 text-gray-400 text-sm pt-16 pb-40">
264292
<img className="h-4 w-4 animate-spin" src={Spinner} />

Diff for: components/gitpod-protocol/src/teams-projects-protocol.ts

+1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ export namespace Project {
4545

4646
export interface Overview {
4747
branches: BranchDetails[];
48+
prebuildState?: "suspended_on_inactivity" | "enabled";
4849
}
4950

5051
export namespace Overview {

Diff for: components/server/ee/src/prebuilds/prebuild-manager.ts

+1-8
Original file line numberDiff line numberDiff line change
@@ -394,14 +394,7 @@ export class PrebuildManager {
394394
}
395395

396396
private async shouldSkipInactiveProject(project: Project): Promise<boolean> {
397-
const usage = await this.projectService.getProjectUsage(project.id);
398-
if (!usage?.lastWorkspaceStart) {
399-
return false;
400-
}
401-
const now = Date.now();
402-
const lastUse = new Date(usage.lastWorkspaceStart).getTime();
403-
const inactiveProjectTime = 1000 * 60 * 60 * 24 * 7 * 1; // 1 week
404-
return now - lastUse > inactiveProjectTime;
397+
return await this.projectService.isProjectConsideredInactive(project.id);
405398
}
406399

407400
private async shouldSkipInactiveRepository(ctx: TraceContext, cloneURL: string): Promise<boolean> {

Diff for: components/server/ee/src/workspace/gitpod-server-impl.ts

+5
Original file line numberDiff line numberDiff line change
@@ -2649,6 +2649,11 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
26492649

26502650
const context = (await this.contextParser.handle(ctx, user, contextURL)) as CommitContext;
26512651

2652+
// HACK: treat manual triggered prebuild as a reset for the inactivity state
2653+
await this.projectDB.updateProjectUsage(project.id, {
2654+
lastWorkspaceStart: new Date().toISOString(),
2655+
});
2656+
26522657
const prebuild = await this.prebuildManager.startPrebuild(ctx, {
26532658
context,
26542659
user,

Diff for: components/server/src/projects/projects-service.ts

+11
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,17 @@ export class ProjectsService {
279279
return this.projectDB.getProjectUsage(projectId);
280280
}
281281

282+
async isProjectConsideredInactive(projectId: string): Promise<boolean> {
283+
const usage = await this.getProjectUsage(projectId);
284+
if (!usage?.lastWorkspaceStart) {
285+
return false;
286+
}
287+
const now = Date.now();
288+
const lastUse = new Date(usage.lastWorkspaceStart).getTime();
289+
const inactiveProjectTime = 1000 * 60 * 60 * 24 * 7 * 1; // 1 week
290+
return now - lastUse > inactiveProjectTime;
291+
}
292+
282293
async getPrebuildEvents(cloneUrl: string): Promise<PrebuildEvent[]> {
283294
const events = await this.webhookEventDB.findByCloneUrl(cloneUrl, 100);
284295
return events.map((we) => ({

Diff for: components/server/src/workspace/gitpod-server-impl.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -2345,7 +2345,12 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
23452345
}
23462346
await this.guardProjectOperation(user, projectId, "get");
23472347
try {
2348-
return await this.projectsService.getProjectOverviewCached(user, project);
2348+
const result = await this.projectsService.getProjectOverviewCached(user, project);
2349+
if (result) {
2350+
const isProjectConsideredInactive = await this.projectsService.isProjectConsideredInactive(project.id);
2351+
result.prebuildState = isProjectConsideredInactive ? "suspended_on_inactivity" : "enabled";
2352+
}
2353+
return result;
23492354
} catch (error) {
23502355
if (UnauthorizedError.is(error)) {
23512356
throw new ResponseError(ErrorCodes.NOT_AUTHENTICATED, "Unauthorized", error.data);

0 commit comments

Comments
 (0)