Skip to content

Commit bf32b22

Browse files
committed
Merge remote-tracking branch 'upstream/main' into pr/26
2 parents 653483f + 25581e9 commit bf32b22

File tree

6 files changed

+137
-19
lines changed

6 files changed

+137
-19
lines changed

src/cds_portal/components/request_form.py

-2
Original file line numberDiff line numberDiff line change
@@ -87,5 +87,3 @@ def _update_form_data(new_data):
8787
type="error",
8888
children=[f"{validation_message.value}"],
8989
)
90-
91-
solara.Markdown(f"{form_data}")

src/cds_portal/components/setup_dialog.py

+6-3
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ def InitialSetup():
4040

4141
def _on_finished_clicked(*args):
4242
Ref(GLOBAL_STATE.fields.initial_setup_finished).set(True)
43-
router.push("/student_classes")
43+
if GLOBAL_STATE.value.user.user_type == UserType.student:
44+
router.push("/student_classes")
45+
else:
46+
router.push("/manage_classes")
4447

4548
with rv.Card():
4649
with rv.CardTitle():
@@ -175,7 +178,7 @@ def _on_join_clicked(*args):
175178

176179
student_response = BASE_API.create_new_student(class_code.value)
177180

178-
if student_response.status_code != 200:
181+
if student_response.status_code != 201:
179182
student_validation_message.set(student_response.reason)
180183
return
181184

@@ -192,7 +195,7 @@ def _on_submit_clicked(*args):
192195
form_data.value
193196
)
194197

195-
if educator_response.status_code != 200:
198+
if educator_response.status_code != 201:
196199
educator_validation_message.set(educator_response.reason)
197200
return
198201

src/cds_portal/pages/manage_classes/__init__.py

+110-11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from collections import defaultdict
12
from datetime import datetime
23

34
import solara
@@ -171,6 +172,104 @@ def _delete_button_clicked(*args):
171172
return dialog
172173

173174

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+
174273
@solara.component
175274
def Page():
176275
data = solara.use_reactive([])
@@ -179,20 +278,19 @@ def Page():
179278
def _retrieve_classes():
180279
classes_dict = BASE_API.load_educator_classes()
181280

182-
new_classes = []
183-
184-
for cls in classes_dict["classes"]:
185-
new_class = {
281+
new_classes = [
282+
{
186283
"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"),
188285
"story": "Hubble's Law",
189286
"code": cls["code"],
190287
"id": cls["id"],
191288
"expected_size": cls["expected_size"],
289+
"small_class": cls["small_class"],
192290
"asynchronous": cls["asynchronous"],
193291
}
194-
195-
new_classes.append(new_class)
292+
for cls in classes_dict["classes"]
293+
]
196294

197295
data.set(new_classes)
198296

@@ -205,7 +303,6 @@ def _create_class_callback(class_info):
205303
def _delete_class_callback():
206304
for row in selected_rows.value:
207305
BASE_API.delete_class(row["code"])
208-
209306
_retrieve_classes()
210307

211308
with solara.Row(classes=["fill-height"]):
@@ -232,8 +329,11 @@ def _delete_class_callback():
232329
elevation=0,
233330
disabled=len(selected_rows.value) != 1,
234331
)
332+
ClassActionsDialog(
333+
len(selected_rows.value) == 0, selected_rows.value
334+
)
235335

236-
classes_table = rv.DataTable(
336+
rv.DataTable(
237337
items=data.value,
238338
single_select=False,
239339
show_select=True,
@@ -252,6 +352,5 @@ def _delete_class_callback():
252352
{"text": "ID", "value": "id", "align": " d-none"},
253353
{"text": "Expected size", "value": "expected_size"},
254354
{"text": "Asynchronous", "value": "asynchronous"},
255-
# {"text": "Actions", "value": "actions", "align": "end"},
256-
],
355+
]
257356
)

src/cds_portal/pages/manage_students/__init__.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,10 @@ def _retrieve_students():
8080
"class_id": cls["id"],
8181
"username": student["username"],
8282
"created": datetime.fromisoformat(
83-
student["profile_created"]
83+
student["profile_created"].removesuffix("Z")
8484
).strftime("%m/%d/%Y"),
8585
"last_visit": datetime.fromisoformat(
86-
student["last_visit"]
86+
student["last_visit"].removesuffix("Z")
8787
).strftime("%m/%d/%Y"),
8888
"class": cls["name"],
8989
"story": "Hubble's Law",

src/cds_portal/pages/student_classes/__init__.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ def Page():
8181
selected_rows, set_selected_rows = solara.use_state([])
8282

8383
def _retrieve_classes():
84+
print(BASE_API.load_student_info())
8485
classes_response = BASE_API.load_student_classes()
8586
formatted_classes = []
8687

@@ -91,7 +92,7 @@ def _retrieve_classes():
9192
"name": cls["name"],
9293
"code": cls["code"],
9394
"educator": f"{educator_response['first_name']} {educator_response['last_name']}",
94-
"date": datetime.fromisoformat(cls["created"]).strftime("%m/%d/%Y"),
95+
"date": datetime.fromisoformat(cls["created"].removesuffix("Z")).strftime("%m/%d/%Y"),
9596
}
9697

9798
formatted_classes.append(cls_fmt)

src/cds_portal/remote.py

+17
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,23 @@ def remove_student_from_class(self, student_id: int, class_id: int) -> Response:
225225

226226
return r
227227

228+
def get_hubble_waiting_room_override(self, class_id: int) -> dict:
229+
r = self.request_session.get(
230+
f"{self.API_URL}/hubbles_law/waiting-room-override/{class_id}"
231+
)
232+
233+
return r.json()
234+
235+
def set_hubble_waiting_room_override(self, class_id: int, value: bool) -> Response:
236+
method = self.request_session.put if value else self.request_session.delete
237+
r = method(
238+
f"{self.API_URL}/hubbles_law/waiting-room-override",
239+
json={"class_id": class_id},
240+
)
241+
242+
return r
243+
244+
228245
@staticmethod
229246
def clear_user(state: Reactive[GlobalState]):
230247
Ref(state.fields.student.id).set(0)

0 commit comments

Comments
 (0)