1
+ from collections import defaultdict
1
2
from datetime import datetime
2
3
3
4
import solara
@@ -171,6 +172,104 @@ def _delete_button_clicked(*args):
171
172
return dialog
172
173
173
174
175
+ @solara .component
176
+ def ClassActionsDialog (disabled : bool , class_data : list [dict ]):
177
+ active , set_active = solara .use_state (False )
178
+ message , set_message = solara .use_state ("" )
179
+ message_color , set_message_color = solara .use_state ("" )
180
+
181
+ with rv .Dialog (
182
+ v_model = active ,
183
+ on_v_model = set_active ,
184
+ v_slots = [
185
+ {
186
+ "name" : "activator" ,
187
+ "variable" : "x" ,
188
+ "children" : rv .Btn (
189
+ v_on = "x.on" ,
190
+ v_bind = "x.attrs" ,
191
+ disabled = disabled ,
192
+ text = True ,
193
+ children = ["Modify class" ],
194
+ elevation = 0 ,
195
+ )
196
+ }
197
+ ],
198
+ max_width = 600 ,
199
+ ):
200
+
201
+ def _update_snackbar (message : str , color : str ):
202
+ set_message_color (color )
203
+ set_message (message )
204
+
205
+ def _reset_snackbar ():
206
+ set_message ("" )
207
+
208
+ def close_dialog ():
209
+ set_active (False )
210
+ _reset_snackbar ()
211
+
212
+ classes_by_story = defaultdict (list )
213
+ for data in class_data :
214
+ classes_by_story [data ["story" ]].append (data )
215
+
216
+ with rv .Card (outlined = True ):
217
+ rv .CardTitle (children = ["Modify Class" ])
218
+
219
+ with rv .CardText ():
220
+ solara .Div ("From this dialog you can make any necessary changes to the selected classes" )
221
+
222
+ if "Hubble's Law" in classes_by_story :
223
+
224
+ hubble_classes = classes_by_story ["Hubble's Law" ]
225
+
226
+ override_statuses = [BASE_API .get_hubble_waiting_room_override (data ["id" ])["override_status" ] for data in hubble_classes ]
227
+ all_overridden = all (override_statuses )
228
+
229
+ def _on_override_button_pressed (* args ):
230
+ failures = []
231
+ for data in hubble_classes :
232
+ class_id = data ["id" ]
233
+ response = BASE_API .set_hubble_waiting_room_override (class_id , True )
234
+ success = response .status_code in (200 , 201 )
235
+ if not success :
236
+ failures .append (class_id )
237
+
238
+ relevant_ids = failures if failures else [data ["id" ] for data in hubble_classes ]
239
+ classes_string = "class" if len (relevant_ids ) == 1 else "classes"
240
+ ids_string = ", " .join (str (cid ) for cid in relevant_ids )
241
+ message = f"There was an error updating the waiting room status for { classes_string } { ids_string } " if failures else \
242
+ f"Updated waiting room status for { classes_string } { ids_string } "
243
+ color = "error" if failures else "success"
244
+
245
+ _update_snackbar (message = message , color = color )
246
+
247
+ with rv .Container ():
248
+ with rv .CardText ():
249
+ solara .Text ("Set the small class override for the selected classes. If a class already has the override set, there will be no effect." )
250
+ with solara .Row ():
251
+ no_override_count = len (hubble_classes ) - sum (override_statuses )
252
+ no_override_classes = "class" if no_override_count == 1 else "classes"
253
+ solara .Button (label = f"Set override" ,
254
+ on_click = _on_override_button_pressed ,
255
+ disabled = all_overridden )
256
+ rv .Alert (children = [f"This will affect { no_override_count } { no_override_classes } " ],
257
+ color = "info" ,
258
+ outlined = True ,
259
+ dense = True )
260
+
261
+ rv .Spacer ()
262
+
263
+ with rv .CardActions ():
264
+ solara .Button ("Cancel" , on_click = close_dialog , elevation = 0 )
265
+
266
+ rv .Snackbar (v_model = bool (message ),
267
+ on_v_model = lambda * args : _reset_snackbar (),
268
+ color = message_color ,
269
+ timeout = 5000 ,
270
+ children = [message ])
271
+
272
+
174
273
@solara .component
175
274
def Page ():
176
275
data = solara .use_reactive ([])
@@ -179,20 +278,19 @@ def Page():
179
278
def _retrieve_classes ():
180
279
classes_dict = BASE_API .load_educator_classes ()
181
280
182
- new_classes = []
183
-
184
- for cls in classes_dict ["classes" ]:
185
- new_class = {
281
+ new_classes = [
282
+ {
186
283
"name" : cls ["name" ],
187
- "date" : datetime .fromisoformat (cls ["created" ]).strftime ("%m/%d/%Y" ),
284
+ "date" : datetime .fromisoformat (cls ["created" ]. removesuffix ( "Z" ) ).strftime ("%m/%d/%Y" ),
188
285
"story" : "Hubble's Law" ,
189
286
"code" : cls ["code" ],
190
287
"id" : cls ["id" ],
191
288
"expected_size" : cls ["expected_size" ],
289
+ "small_class" : cls ["small_class" ],
192
290
"asynchronous" : cls ["asynchronous" ],
193
291
}
194
-
195
- new_classes . append ( new_class )
292
+ for cls in classes_dict [ "classes" ]
293
+ ]
196
294
197
295
data .set (new_classes )
198
296
@@ -205,7 +303,6 @@ def _create_class_callback(class_info):
205
303
def _delete_class_callback ():
206
304
for row in selected_rows .value :
207
305
BASE_API .delete_class (row ["code" ])
208
-
209
306
_retrieve_classes ()
210
307
211
308
with solara .Row (classes = ["fill-height" ]):
@@ -232,8 +329,11 @@ def _delete_class_callback():
232
329
elevation = 0 ,
233
330
disabled = len (selected_rows .value ) != 1 ,
234
331
)
332
+ ClassActionsDialog (
333
+ len (selected_rows .value ) == 0 , selected_rows .value
334
+ )
235
335
236
- classes_table = rv .DataTable (
336
+ rv .DataTable (
237
337
items = data .value ,
238
338
single_select = False ,
239
339
show_select = True ,
@@ -252,6 +352,5 @@ def _delete_class_callback():
252
352
{"text" : "ID" , "value" : "id" , "align" : " d-none" },
253
353
{"text" : "Expected size" , "value" : "expected_size" },
254
354
{"text" : "Asynchronous" , "value" : "asynchronous" },
255
- # {"text": "Actions", "value": "actions", "align": "end"},
256
- ],
355
+ ]
257
356
)
0 commit comments