3636
3737_SKIP_KEYWORDS = [
3838 "training" , "pdp" , "rmcpdp" , "osa" , "soct" , "travel" ,
39- "essentials" , "respect" , "consent" ,
39+ "essentials" , "respect" , "consent" , "osh" ,
4040]
4141
4242
@@ -49,16 +49,17 @@ def _load_courses_from_canvas() -> None:
4949 if not token :
5050 return
5151 cfg = json .load (open (config_file )) if config_file .exists () else {}
52- canvas_url = cfg .get ("CANVAS_URL" , "" ).rstrip ("/" )
52+ canvas_url = cfg .get ("CANVAS_URL" , "" ).strip ().rstrip ("/" )
53+ if canvas_url and not canvas_url .startswith (("http://" , "https://" )):
54+ canvas_url = "https://" + canvas_url
5355 if not canvas_url :
5456 return
5557 try :
5658 import requests
5759 resp = requests .get (
5860 f"{ canvas_url } /api/v1/courses" ,
5961 headers = {"Authorization" : f"Bearer { token } " },
60- params = {"enrollment_state" : "active" , "enrollment_type[]" : "student" ,
61- "per_page" : 100 },
62+ params = {"enrollment_state" : "active" , "per_page" : 100 },
6263 timeout = 10 ,
6364 )
6465 resp .raise_for_status ()
@@ -1061,7 +1062,7 @@ def _save_config(key: str, value: str) -> None:
10611062 _cfg = _load_config ()
10621063 tf_canvas_url = ft .TextField (
10631064 value = _cfg .get ("CANVAS_URL" , "" ),
1064- hint_text = "https:// canvas.yourschool.edu" , expand = True , dense = True ,
1065+ hint_text = "canvas.yourschool.edu (https:// added automatically) " , expand = True , dense = True ,
10651066 bgcolor = C_OUTPUT_BG , border_color = C_PRIMARY , text_size = 12 ,
10661067 )
10671068 tf_panopto = ft .TextField (
@@ -1128,12 +1129,31 @@ def _save_panopto(_):
11281129 bgcolor = C_OUTPUT_BG , border_color = C_PRIMARY , text_size = 12 ,
11291130 )
11301131
1132+ refresh_status = ft .Text ("" , size = 11 ,
1133+ color = ft .Colors .with_opacity (0.6 , ft .Colors .WHITE ))
1134+
1135+ def _do_refresh ():
1136+ refresh_status .value = "Refreshing…"
1137+ refresh_status .color = ft .Colors .with_opacity (0.6 , ft .Colors .WHITE )
1138+ page .update ()
1139+ # Load courses while this settings page is still attached
1140+ _load_courses_from_canvas ()
1141+ n = len (COURSES )
1142+ refresh_status .value = (
1143+ f"✓ { n } course{ 's' if n != 1 else '' } loaded."
1144+ if n else "No courses found — check token and Canvas URL."
1145+ )
1146+ refresh_status .color = C_SUCCESS if n else C_WARN
1147+ page .update ()
1148+ # Rebuild pages AFTER updating status (rebuild replaces the settings page)
1149+ if on_courses_changed :
1150+ on_courses_changed ()
1151+
11311152 def _save_canvas (_ ):
11321153 try :
11331154 canvas_file .write_text (tf_canvas .value .strip ())
11341155 _snack ("Canvas token saved." )
1135- if on_courses_changed :
1136- on_courses_changed ()
1156+ _do_refresh ()
11371157 except Exception as e :
11381158 _snack (f"Error: { e } " , ok = False )
11391159
@@ -1165,6 +1185,14 @@ def _save_gemini(_):
11651185 size = 11 , color = ft .Colors .with_opacity (0.5 , ft .Colors .WHITE )),
11661186 ft .Container (height = 4 ),
11671187 _key_row ("Canvas Token" , tf_canvas , _save_canvas ),
1188+ ft .Row (controls = [
1189+ ft .FilledButton (
1190+ "Refresh Courses" , icon = ft .Icons .REFRESH ,
1191+ on_click = lambda _ : _do_refresh (),
1192+ style = ft .ButtonStyle (bgcolor = C_SECONDARY , color = ft .Colors .BLACK ),
1193+ ),
1194+ refresh_status ,
1195+ ], spacing = 10 ),
11681196 _key_row ("OpenAI API Key" , tf_openai , _save_openai ),
11691197 _key_row ("Anthropic API Key" ,tf_anthropic , _save_anthropic ),
11701198 _key_row ("Gemini API Key" , tf_gemini , _save_gemini ),
0 commit comments