Skip to content

Commit 2032308

Browse files
committed
autostart the most recent active licensed project on initial page load
1 parent 36fdd36 commit 2032308

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

src/packages/frontend/projects/store.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import { List, Map, Set } from "immutable";
66
import { fromPairs, isEmpty } from "lodash";
77
import LRU from "lru-cache";
8-
98
import { redux, Store, TypedMap } from "@cocalc/frontend/app-framework";
109
import { StudentProjectFunctionality } from "@cocalc/frontend/course/configuration/customize-student-project-functionality";
1110
import { CUSTOM_IMG_PREFIX } from "@cocalc/frontend/custom-software/util";

src/packages/frontend/projects/table.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { COCALC_MINIMAL } from "../fullscreen";
33
import { parse_query } from "@cocalc/sync/table/util";
44
import { once } from "@cocalc/util/async-utils";
55
import { redux, Table } from "../app-framework";
6+
import { isValidUUID } from "@cocalc/util/misc";
67

78
declare var DEBUG: boolean;
89

@@ -76,7 +77,7 @@ function initTableError(): void {
7677
export const load_all_projects = reuseInFlight(async () => {
7778
if (DEBUG && COCALC_MINIMAL) {
7879
console.error(
79-
"projects/load_all_projects was called in kiosk/minimal mode"
80+
"projects/load_all_projects was called in kiosk/minimal mode",
8081
);
8182
}
8283
if (all_projects_have_been_loaded) {
@@ -102,6 +103,7 @@ async function load_recent_projects(): Promise<void> {
102103
// https://github.com/sagemathinc/cocalc/issues/4306
103104
await redux.getActions("projects").load_all_projects();
104105
}
106+
ensureMostActiveProjectIsRunning();
105107
}
106108

107109
export function init() {
@@ -133,3 +135,53 @@ export async function switch_to_project(project_id: string): Promise<void> {
133135
await once(redux.getTable("projects")._table, "connected");
134136
}
135137
}
138+
139+
/*
140+
Looks at all non-deleted, non-hidden licensed projects this user
141+
is a collaborator on, finds the most recently active project,
142+
and starts it if it is not already running. This is meant to
143+
make the experience of using cocalc better for paying users.
144+
It is called exactly once when they first load cocalc in their
145+
browser.
146+
147+
It is controversial and you could argue this is a bad idea.
148+
However, I feel on balance it is a good idea (which BB suggested).
149+
Students will like it, since they usually are a collab on
150+
one project.
151+
*/
152+
153+
function ensureMostActiveProjectIsRunning() {
154+
const project_map = redux.getTable("projects")?._table?.get();
155+
const account_id = redux.getStore("account").get("account_id");
156+
let newest_project: any = null;
157+
let last_edited: Date | null = null;
158+
for (const [_, project] of project_map) {
159+
if (
160+
project.getIn(["users", account_id, "hide"]) ||
161+
project.get("deleted") ||
162+
!project.get("last_edited") ||
163+
(project.get("site_license")?.size ?? 0) == 0
164+
) {
165+
continue;
166+
}
167+
if (last_edited == null || last_edited <= project.get("last_edited")) {
168+
last_edited = project.get("last_edited");
169+
newest_project = project;
170+
}
171+
}
172+
if (newest_project != null) {
173+
if (newest_project.getIn(["state", "state"]) != "running") {
174+
for (const [license_id] of newest_project.get("site_license")) {
175+
if (!isValidUUID(license_id)) {
176+
// TODO: we should also check that the license is currently valid... though that would
177+
// put extra load on the backend and slow this step down. Better might be a way to "start project
178+
// only if license is valid and not otherwise".
179+
return;
180+
}
181+
}
182+
redux
183+
.getActions("projects")
184+
.start_project(newest_project.get("project_id"));
185+
}
186+
}
187+
}

0 commit comments

Comments
 (0)