@@ -3,6 +3,7 @@ import { COCALC_MINIMAL } from "../fullscreen";
3
3
import { parse_query } from "@cocalc/sync/table/util" ;
4
4
import { once } from "@cocalc/util/async-utils" ;
5
5
import { redux , Table } from "../app-framework" ;
6
+ import { isValidUUID } from "@cocalc/util/misc" ;
6
7
7
8
declare var DEBUG : boolean ;
8
9
@@ -76,7 +77,7 @@ function initTableError(): void {
76
77
export const load_all_projects = reuseInFlight ( async ( ) => {
77
78
if ( DEBUG && COCALC_MINIMAL ) {
78
79
console . error (
79
- "projects/load_all_projects was called in kiosk/minimal mode"
80
+ "projects/load_all_projects was called in kiosk/minimal mode" ,
80
81
) ;
81
82
}
82
83
if ( all_projects_have_been_loaded ) {
@@ -102,6 +103,7 @@ async function load_recent_projects(): Promise<void> {
102
103
// https://github.com/sagemathinc/cocalc/issues/4306
103
104
await redux . getActions ( "projects" ) . load_all_projects ( ) ;
104
105
}
106
+ ensureMostActiveProjectIsRunning ( ) ;
105
107
}
106
108
107
109
export function init ( ) {
@@ -133,3 +135,53 @@ export async function switch_to_project(project_id: string): Promise<void> {
133
135
await once ( redux . getTable ( "projects" ) . _table , "connected" ) ;
134
136
}
135
137
}
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