Skip to content

Commit 48583ba

Browse files
PlictoxerikmdAltGr
authored
feat(ui): teacher tab: Display last synced student's draft (≠ graded code) (#548)
* feat: test implementation * feat: working implementation * feat: internationalization and class ongoing * feat: translations * feat: css code * refactor: move draft tab Apply a tab order by decreasing importance: list (exos) → stats → report → editor (graded code) → draft (saved code) → text (subject) Note: It would suffice to reorder the buttons in student-view.html, but for consistency the other "sequences" are also reordered. * feat: comments for fr.po file * feat: fixed bug when switching exercise * feat: test implementation for the text field displaying time of sync * feat: seperate divs for sync_time & draft_editor * feat: change of id in learnocaml-student-view.ml Co-authored-by: Erik Martin-Dorel <[email protected]> * feat: change of id in student-view.html Co-authored-by: Erik Martin-Dorel <[email protected]> * feat: sync date reformatted * feat: implementation for flexible display * feat: implementation for flexible display * feat: correcting bug * feat: CSS styling * feat: CSS styling * feat: internationalization * feat: rewriting css * feat: styling & renaming id * fix: Apply fixes and improvements from PR review * feat(web-app): Make (report, editor) tabs buttons likewise * Add a CSS comment about a potential minor issue * fix: details * fix: fr.po * fix: Apply review suggestions * Update src/app/learnocaml_student_view.ml Apply code review suggestion Co-authored-by: Louis Gesbert <[email protected]> * style(fr.po): Revert the slightly-ugly unneeded newlines --------- Co-authored-by: Erik Martin-Dorel <[email protected]> Co-authored-by: Louis Gesbert <[email protected]>
1 parent 0b150b9 commit 48583ba

File tree

5 files changed

+207
-132
lines changed

5 files changed

+207
-132
lines changed

src/app/learnocaml_common.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,7 @@ let set_string_translations_view () =
835835
"learnocaml-exo-button-stats", [%i"Stats"];
836836
"learnocaml-exo-button-list", [%i"Exercises"];
837837
"learnocaml-exo-button-report", [%i"Report"];
838+
"learnocaml-exo-button-draft", [%i"Draft"];
838839
"learnocaml-exo-button-text", [%i"Subject"];
839840
"learnocaml-exo-button-editor", [%i"Answer"];
840841
] in set_inner_list translations

src/app/learnocaml_student_view.ml

Lines changed: 54 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,14 @@ module El = struct
4040
btn = snd (id ("learnocaml-exo-button-" ^ name));
4141
tab = snd (id ("learnocaml-exo-tab-" ^ name));
4242
}
43-
let stats = tid "stats"
4443
let list = tid "list"
44+
let stats = tid "stats"
4545
let report = tid "report"
4646
let editor = tid "editor"
47+
let draft = tid "draft"
4748
let text = tid "text"
4849

49-
let all = [stats; list; report; editor; text]
50+
let all = [list; stats; report; editor; draft; text]
5051
end
5152

5253
let nickname_id, nickname = id "learnocaml-student-nickname"
@@ -362,44 +363,44 @@ let _exercise_selection_updater =
362363
let previously_selected = ref None in
363364
selected_exercise_signal |> React.S.map @@ fun id ->
364365
let line id = find_component (El.Dyn.exercise_line_id id) in
365-
(match !previously_selected with
366-
| None -> ()
367-
| Some id -> Manip.removeClass (line id) "selected");
366+
Option.iter (fun id -> Manip.removeClass (line id) "selected") !previously_selected;
368367
previously_selected := id;
369-
match id with
370-
| None -> ()
371-
| Some id ->
368+
Option.iter (fun id ->
372369
Manip.addClass (line id) "selected";
373370
let selected_tab = React.S.value tab_select_signal in
374371
if selected_tab = El.Tabs.list || selected_tab = El.Tabs.stats then
375-
select_tab El.Tabs.report
372+
select_tab El.Tabs.report) id
376373

377374
let restore_report_button () =
378375
let report_button = El.Tabs.(report.btn) in
379-
Manip.removeClass report_button "success";
380-
Manip.removeClass report_button "failure";
381-
Manip.removeClass report_button "partial";
376+
let editor_button = El.Tabs.(editor.btn) in
377+
let remove_class (b1, b2) c = Manip.removeClass b1 c; Manip.removeClass b2 c in
378+
remove_class (report_button, editor_button) "success";
379+
remove_class (report_button, editor_button) "failure";
380+
remove_class (report_button, editor_button) "partial";
382381
Manip.replaceChildren report_button
383382
Tyxml_js.Html5.[ txt [%i"Report"] ]
384383

385384
let display_report exo report =
386385
let score, _failed = Report.result report in
387386
let report_button = El.Tabs.(report.btn) in
387+
let editor_button = El.Tabs.(editor.btn) in
388+
let add_class (b1, b2) c = Manip.addClass b1 c; Manip.addClass b2 c in
388389
restore_report_button ();
389390
let grade =
390391
let max = Learnocaml_exercise.(access File.max_score exo) in
391392
if max = 0 then 999 else score * 100 / max
392393
in
393394
if grade >= 100 then begin
394-
Manip.addClass report_button "success" ;
395+
add_class (report_button, editor_button) "success" ;
395396
Manip.replaceChildren report_button
396397
Tyxml_js.Html5.[ txt [%i"Report"] ]
397398
end else if grade = 0 then begin
398-
Manip.addClass report_button "failure" ;
399+
add_class (report_button, editor_button) "failure" ;
399400
Manip.replaceChildren report_button
400401
Tyxml_js.Html5.[ txt [%i"Report"] ]
401402
end else begin
402-
Manip.addClass report_button "partial" ;
403+
add_class (report_button, editor_button) "partial" ;
403404
let pct = Format.asprintf "%2d%%" grade in
404405
Manip.replaceChildren report_button
405406
Tyxml_js.Html5.[ txt [%i"Report"] ;
@@ -411,13 +412,43 @@ let display_report exo report =
411412

412413
let update_answer_tab, clear_answer_tab = ace_display El.Tabs.(editor.tab)
413414

415+
let init_draft_tab () =
416+
let draft_time = H.div ~a:[H.a_id "learnocaml-exo-draft-time"]
417+
[H.txt [%i"No draft available."]] in
418+
let draft_editor = find_component "learnocaml-exo-draft-editor" in
419+
Manip.appendChild ~before:draft_editor El.Tabs.(draft.tab) draft_time;
420+
Manip.replaceChildren El.Tabs.(draft.btn) Tyxml_js.Html5.[ txt [%i"Draft"] ]
421+
422+
let update_draft, clear_draft_tab =
423+
ace_display (find_component "learnocaml-exo-draft-editor")
424+
425+
let restore_draft_button () =
426+
Manip.removeClass El.Tabs.(draft.btn) "ongoing"
427+
414428
let clear_tabs () =
415429
restore_report_button ();
430+
restore_draft_button ();
416431
List.iter (fun t ->
417432
Manip.replaceChildren El.Tabs.(t.tab) [])
418433
El.Tabs.([report; text]);
434+
clear_draft_tab ();
435+
Manip.replaceChildren (find_component "learnocaml-exo-draft-time")
436+
[H.txt [%i"No draft available."]];
419437
clear_answer_tab ()
420438

439+
let update_draft_tab syn =
440+
restore_draft_button ();
441+
let draft_button = El.Tabs.(draft.btn) in
442+
let inner_div_time, syn_draft = match syn with
443+
| Some syn ->
444+
let () = Manip.addClass draft_button "ongoing" in
445+
([H.txt [%i"Ungraded draft, synced on: "]; date ~time:true @@ fst syn], snd syn)
446+
| None ->
447+
([H.txt [%i"No draft available."]], "")
448+
in
449+
Manip.replaceChildren (find_component "learnocaml-exo-draft-time") inner_div_time;
450+
update_draft syn_draft
451+
421452
let update_text_tab meta exo =
422453
let text_iframe = Dom_html.createIframe Dom_html.document in
423454
Manip.replaceChildren El.Tabs.(text.tab) [
@@ -446,20 +477,19 @@ let update_report_tab exo ans =
446477
Manip.replaceChildren El.Tabs.(report.tab)
447478
[H.div [H.txt [%i"No report available"]]]
448479

449-
let update_tabs meta exo ans =
480+
let update_tabs meta exo ans syn =
450481
update_text_tab meta exo;
451-
match ans with
452-
| None -> ()
453-
| Some ans ->
482+
update_draft_tab syn;
483+
Option.iter (fun ans ->
454484
update_report_tab exo ans;
455-
update_answer_tab ans.Answer.solution
485+
update_answer_tab ans.Answer.solution) ans
456486

457487
let () =
458488
run_async_with_log @@ fun () ->
459489
(* set_string_translations (); *)
460490
(* Manip.setInnerText El.version ("v."^Learnocaml_api.version); *)
461491
Learnocaml_local_storage.init ();
462-
(match Js_utils.get_lang() with Some l -> Ocplib_i18n.set_lang l | None -> ());
492+
Option.iter Ocplib_i18n.set_lang (Js_utils.get_lang ());
463493
set_string_translations_view ();
464494
let teacher_token = Learnocaml_local_storage.(retrieve sync_token) in
465495
if not (Token.is_teacher teacher_token) then
@@ -470,6 +500,7 @@ let () =
470500
try Token.parse (List.assoc "token" Url.Current.arguments)
471501
with Not_found | Failure _ -> failwith "Student token missing or invalid"
472502
in
503+
init_draft_tab ();
473504
Manip.setInnerText El.token
474505
([%i"Status of student: "] ^ Token.to_string student_token);
475506
retrieve (Learnocaml_api.Fetch_save student_token)
@@ -488,7 +519,8 @@ let () =
488519
>>= fun (meta, exo, _) ->
489520
clear_tabs ();
490521
let ans = SMap.find_opt ex_id save.Save.all_exercise_states in
491-
update_tabs meta exo ans;
522+
let syn = SMap.find_opt ex_id save.Save.all_exercise_editors in
523+
update_tabs meta exo ans syn;
492524
Lwt.return_unit
493525
in
494526
Lwt.return_unit

static/css/learnocaml_student_view.css

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,22 @@
130130
background: #e80;
131131
color: white;
132132
}
133+
#learnocaml-exo-tab-buttons > #learnocaml-exo-button-editor.success {
134+
background: #0a0;
135+
color: white;
136+
}
137+
#learnocaml-exo-tab-buttons > #learnocaml-exo-button-editor.failure {
138+
background: #b00;
139+
color: white;
140+
}
141+
#learnocaml-exo-tab-buttons > #learnocaml-exo-button-editor.partial {
142+
background: #e80;
143+
color: white;
144+
}
145+
#learnocaml-exo-tab-buttons > #learnocaml-exo-button-draft.ongoing {
146+
background: #F08080;
147+
color: white;
148+
}
133149
#learnocaml-exo-button-report > .score {
134150
padding: 0 5px;
135151
float: right;
@@ -177,6 +193,25 @@
177193
background: linear-gradient(to bottom, rgba(0,0,0,0.3) 0, transparent 100%)
178194
}
179195

196+
#learnocaml-exo-tab-draft {
197+
display: flex;
198+
flex-flow: column;
199+
}
200+
#learnocaml-exo-draft-time {
201+
flex: 0 1 auto;
202+
border-bottom: 1px solid black;
203+
padding: 5px;
204+
font-family: 'Inconsolata', monospace;
205+
font-size: 18px;
206+
background: #eee;
207+
}
208+
#learnocaml-exo-draft-editor {
209+
flex: 1 1 auto;
210+
z-index: 997;
211+
background: #eee;
212+
padding: 0;
213+
}
214+
180215
/* -------------------- two columns mode -------------------------- */
181216
@media (min-width: 1200px) {
182217
#learnocaml-exo-toolbar {
@@ -228,6 +263,14 @@
228263
background: linear-gradient(to bottom, #444 0, #444 5px,
229264
rgba(0,0,0,0.5) 5px, transparent 10px) ;
230265
}
266+
#learnocaml-exo-draft-editor::after {
267+
position: absolute;
268+
z-index: 1005;
269+
left: 0; top: 0; height: 10px; width: 100%;
270+
content: "";
271+
background: linear-gradient(to bottom, #444 0, #444 5px,
272+
rgba(0,0,0,0.5) 5px, transparent 10px) ;
273+
}
231274
}
232275
@media (min-width: 550px) and (max-width: 1199px) {
233276
#learnocaml-exo-tab-buttons {
@@ -335,6 +378,8 @@ tr.exercise-highlight {
335378
}
336379

337380
/* -------------------- ACE overriding ---------------------------- */
381+
/* XXX Erik: this section looks like dead CSS code
382+
See https://github.com/ocaml-sf/learn-ocaml/issues/556 */
338383
#learnocaml-exo-editor-pane {
339384
font-size: 16px;
340385
font-family: 'Inconsolata', monospace;

static/student-view.html

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,27 +53,31 @@
5353
</div>
5454
</div>
5555
<div id="learnocaml-exo-tab-buttons">
56+
<button id="learnocaml-exo-button-list">Exercises</button>
5657
<button id="learnocaml-exo-button-stats" class="front-tab" disabled="">
5758
Stats
5859
</button>
59-
<button id="learnocaml-exo-button-list">Exercises</button>
6060
<button id="learnocaml-exo-button-report">
6161
Report
6262
</button>
6363
<button id="learnocaml-exo-button-editor">Answer</button>
64+
<button id="learnocaml-exo-button-draft">Draft</button>
6465
<button id="learnocaml-exo-button-text">Subject</button>
6566
</div>
6667
<div id="learnocaml-exo-tabs">
67-
<div id="learnocaml-exo-tab-stats" class="front-tab"></div>
6868
<div id="learnocaml-exo-tab-list"></div>
69+
<div id="learnocaml-exo-tab-stats" class="front-tab"></div>
70+
<div id="learnocaml-exo-tab-report"></div>
6971
<div id="learnocaml-exo-tab-editor">
7072
<div id="learnocaml-exo-prelude"></div>
7173
<div id="learnocaml-exo-editor-pane" class="pane"></div>
7274
<div id="learnocaml-exo-editor-toolbar" class="buttons">
7375
</div>
7476
</div>
77+
<div id="learnocaml-exo-tab-draft">
78+
<div id="learnocaml-exo-draft-editor"></div>
79+
</div>
7580
<div id="learnocaml-exo-tab-text"></div>
76-
<div id="learnocaml-exo-tab-report"></div>
7781
</div>
7882
</body>
7983
</html>

0 commit comments

Comments
 (0)