From 077b537057d94c4e94ca330a7795abd202bbe3f9 Mon Sep 17 00:00:00 2001 From: Navin Keswani Date: Tue, 28 Mar 2023 15:35:15 +1100 Subject: [PATCH] Call function to extract repro steps in jsoo. --- web-ui/jsoo/dune | 19 +++++---- web-ui/jsoo/main.ml | 21 +++++++--- web-ui/jsoo/process_chunk.ml | 23 +++++++---- web-ui/jsoo/steps_to_reproduce_build.ml | 15 ++++++++ web-ui/static/js/add-repro-steps.js | 28 -------------- web-ui/static/js/dune | 5 ++- web-ui/static/js/step-page-poll.js | 51 ++++++++++++++++++++----- web-ui/view/step.ml | 1 - 8 files changed, 102 insertions(+), 61 deletions(-) create mode 100644 web-ui/jsoo/steps_to_reproduce_build.ml delete mode 100644 web-ui/static/js/add-repro-steps.js diff --git a/web-ui/jsoo/dune b/web-ui/jsoo/dune index 0a3d077c..38fcb158 100644 --- a/web-ui/jsoo/dune +++ b/web-ui/jsoo/dune @@ -1,10 +1,15 @@ (executable + (modules process_chunk main steps_to_reproduce_build) (name main) (modes js) - (preprocess (pps js_of_ocaml-ppx)) - (libraries - js_of_ocaml - ansi - astring - brr - tyxml)) \ No newline at end of file + (preprocess + (pps js_of_ocaml-ppx)) + (libraries ansi astring brr)) + +; (executable +; (modules steps_to_reproduce_build) +; (name steps_to_reproduce_build) +; (modes js) +; (preprocess (pps js_of_ocaml-ppx)) +; (libraries +; brr)) diff --git a/web-ui/jsoo/main.ml b/web-ui/jsoo/main.ml index 1071aa87..01e0f541 100644 --- a/web-ui/jsoo/main.ml +++ b/web-ui/jsoo/main.ml @@ -19,10 +19,15 @@ let encode_parens s : Jstr.t = in Jstr.of_string s_rp_encoded -let inject_log_lines data = +let inject_log_lines first_line_repro_block last_line_repro_block data = match Document.find_el_by_id Brr.G.document (Jstr.of_string "logs-pre") with | None -> assert false - | Some scroller -> El.append_children scroller data + | Some scroller -> + El.append_children scroller data; + if !last_line_repro_block <> 0 then + Steps_to_reproduce_build.go !first_line_repro_block + !last_line_repro_block; + () let ws_path window = let location = Brr.Window.location window in @@ -50,8 +55,11 @@ let ws_path window = ~path:(encode_parens @@ Jstr.append (Jstr.of_string "ws") pathname) location *) -let go _ = +let fetch_logs = let line_number = ref 0 in + let first_line_repro_block = ref 0 in + let last_line_repro_block = ref 0 in + let window = Brr.G.window in (* this will throw an exception if the encoding fails *) let ws_path = ws_path window in @@ -61,10 +69,11 @@ let go _ = Ev.listen Brr_io.Message.Ev.message (fun e -> let data = Brr_io.Message.Ev.data (Ev.as_type e) in - inject_log_lines @@ Process_chunk.go line_number (Jstr.to_string data)) + inject_log_lines first_line_repro_block last_line_repro_block + @@ Process_chunk.go line_number first_line_repro_block + last_line_repro_block (Jstr.to_string data)) target in () -let () = - ignore (Ev.listen Ev.load go (Window.as_target Brr.G.window) : Ev.listener) +let () = ignore fetch_logs diff --git a/web-ui/jsoo/process_chunk.ml b/web-ui/jsoo/process_chunk.ml index 82221d82..cd729140 100644 --- a/web-ui/jsoo/process_chunk.ml +++ b/web-ui/jsoo/process_chunk.ml @@ -35,16 +35,20 @@ let to_element ~line_number_id ~log_line ~code_line_class : El.t = let result = El.span ~at:At.[ id (Jstr.v line_number_id) ] [ span; code ] in El.set_class (Jstr.v "tr") true result; El.set_at (Jstr.v ":class") (Some (Jstr.v colon_class_str)) result; + (* Note x-on:click is another way of doing @click + https://github.com/alpinejs/alpine/issues/396 + *) El.set_at (Jstr.v "x-on:click") (Some (Jstr.v "highlightLine")) result; result -let tabulate line_number data = +let tabulate line_number first_line_repro_block last_line_repro_block data = let last_line_blank = ref false in let aux log_line = if !last_line_blank && log_line = "" then (* Squash consecutive new lines *) None - else + else ( + line_number := !line_number + 1; let is_start_of_steps_to_reproduce = Astring.String.is_infix ~affix:"To reproduce locally:" log_line in @@ -52,20 +56,23 @@ let tabulate line_number data = Astring.String.is_infix ~affix:"END-REPRO-BLOCK" log_line in let code_line_class = - if is_start_of_steps_to_reproduce then "repro-block-start" - else if is_end_of_steps_to_reproduce then "repro-block-end" + if is_start_of_steps_to_reproduce then ( + first_line_repro_block := !line_number; + "repro-block-start") + else if is_end_of_steps_to_reproduce then ( + last_line_repro_block := !line_number; + "repro-block-end") else "" in last_line_blank := log_line = ""; - line_number := !line_number + 1; let line_number_id = Printf.sprintf "L%d" !line_number in let line = to_element ~line_number_id ~log_line ~code_line_class in - Some line + Some line) in List.filter_map aux data -let go line_number data = +let go line_number first_line_repro_block last_line_repro_block data = Astring.String.(with_range ~len:(length data - 1)) data |> Astring.String.cuts ~sep:"\n" |> List.map (fun l -> collapse_carriage_returns l |> Ansi.process ansi) - |> tabulate line_number + |> tabulate line_number first_line_repro_block last_line_repro_block diff --git a/web-ui/jsoo/steps_to_reproduce_build.ml b/web-ui/jsoo/steps_to_reproduce_build.ml new file mode 100644 index 00000000..fd4a6a2f --- /dev/null +++ b/web-ui/jsoo/steps_to_reproduce_build.ml @@ -0,0 +1,15 @@ +module Ev = Brr.Ev +module El = Brr.El +module At = Brr.At +module Document = Brr.Document +module Window = Brr.Window + +let go first_line_repro_block last_line_repro_block = + (* extractStepsToReproduce is declared in step-page-poll.js + Until it is cut across to jsoo/brr call it directly *) + let extractStepsToReproduce' = Jv.get Jv.global "extractStepsToReproduce" in + let _ = + Jv.apply extractStepsToReproduce' + [| Jv.of_int first_line_repro_block; Jv.of_int last_line_repro_block |] + in + () diff --git a/web-ui/static/js/add-repro-steps.js b/web-ui/static/js/add-repro-steps.js deleted file mode 100644 index 2e80346f..00000000 --- a/web-ui/static/js/add-repro-steps.js +++ /dev/null @@ -1,28 +0,0 @@ -function extractStepsToReproduce() { - const tables = document.getElementsByClassName("steps-table"); - const start = document.getElementsByClassName("repro-block-start"); - const finish = document.getElementsByClassName("repro-block-end"); - if ((start.length === 0) || (finish.length === 0) || (tables.length === 0)) { - document.getElementById("build-repro-container").style.display = 'none'; - return null - }; - const startIndex = parseInt(start[0].parentElement.id.split('L')[1], 10); - const finishIndex = parseInt(finish[0].parentElement.id.split('L')[1], 10); - - const br = document.createElement("br"); - const reproDiv = document.getElementById("build-repro"); - const rows = [...tables].map((t) => Array.from(t.children)).flat(1); - - document.getElementById("build-repro-container").style.removeProperty('display'); - - for (let i = (startIndex); i < (finishIndex - 1); i++) { - // Remove line-number, whitespace and possible newlines from the row - const newContent = document.createTextNode(rows[i].innerText.replace(/\s*\n?/, '')); - reproDiv.appendChild(newContent); - if (i > startIndex) { - reproDiv.appendChild(br.cloneNode()); - } - } -} - -extractStepsToReproduce(); diff --git a/web-ui/static/js/dune b/web-ui/static/js/dune index c8aa9bbf..5379df1c 100644 --- a/web-ui/static/js/dune +++ b/web-ui/static/js/dune @@ -1,6 +1,7 @@ (rule (deps ../../jsoo/main.bc.js) - (target ./step-logs.js ) + (target ./step-logs.js) (mode (promote (until-clean))) - (action (copy %{deps} %{target}))) \ No newline at end of file + (action + (copy %{deps} %{target}))) diff --git a/web-ui/static/js/step-page-poll.js b/web-ui/static/js/step-page-poll.js index dbdeb2f4..6a476a0c 100644 --- a/web-ui/static/js/step-page-poll.js +++ b/web-ui/static/js/step-page-poll.js @@ -1,3 +1,32 @@ +// Called via jsoo in the generated step-logs.js +function extractStepsToReproduce(startIndex, finishIndex) { + if ( // return if already done + !!document.getElementById("build-repro-container") && + document.getElementById("build-repro-container").style.display != "none" + ) { + return null; + } + const tables = document.getElementsByClassName("steps-table"); + const br = document.createElement("br"); + const reproDiv = document.getElementById("build-repro"); + const rows = [...tables].map((t) => Array.from(t.children)).flat(1); + + document + .getElementById("build-repro-container") + .style.removeProperty("display"); + + for (let i = startIndex; i < finishIndex - 1; i++) { + // Remove line-number, whitespace and possible newlines from the row + const newContent = document.createTextNode( + rows[i].innerText.replace(/\s*\n?/, "") + ); + reproDiv.appendChild(newContent); + if (i > startIndex) { + reproDiv.appendChild(br.cloneNode()); + } + } +} + function poll(api_path, timeout, interval) { var endTime = Number(new Date()) + (timeout || 2700000); // 45min timeout interval = interval || 10000; // 10s @@ -21,16 +50,19 @@ function poll(api_path, timeout, interval) { fetch(api_path) .then((response) => response.json()) .then((data) => { - console.log(data); - const element_created_at = document.getElementById("step-created-at"); - element_created_at.innerHTML = "Created at " + data["created_at"]; + !!data["created_at"] && + (element_created_at.innerHTML = "Created at " + data["created_at"]); const element_finished_at = document.getElementById("step-finished-at"); - element_finished_at.innerHTML = "Finished at " + data["finished_at"]; + !!data["finished_at"] && + (element_finished_at.innerHTML = + "Finished at " + data["finished_at"]); const element_ran_for = document.getElementById("step-ran-for"); - element_ran_for.innerHTML = "Ran for " + data["ran_for"]; + !!data["ran_for"] && + (element_ran_for.innerHTML = "Ran for " + data["ran_for"]); const element_queued_for = document.getElementById("step-queued-for"); - element_queued_for.innerHTML = data["queued_for"] + " in queue"; + !!data["queued_for"] && + (element_queued_for.innerHTML = data["queued_for"] + " in queue"); if ( data["status"].startsWith("passed") || @@ -47,7 +79,7 @@ function poll(api_path, timeout, interval) { .getElementById("rebuild-step") .style.removeProperty("display"); } - if (data["can_cancel"]) { + if (data["can_cancel"]) { document .getElementById("cancel-step") .style.removeProperty("display"); @@ -70,5 +102,6 @@ function poll(api_path, timeout, interval) { return new Promise(checkCondition); } -// Usage: ensure element is visible -poll(location.origin + "/api" + location.pathname); +window.onload = function () { + poll(location.origin + "/api" + location.pathname); +}; diff --git a/web-ui/view/step.ml b/web-ui/view/step.ml index 233193f9..924d99f8 100644 --- a/web-ui/view/step.ml +++ b/web-ui/view/step.ml @@ -547,6 +547,5 @@ module Make (M : Git_forge_intf.Forge) = struct ] [ steps_to_reproduce_build; logs_container ]; ]; - Tyxml.Html.script ~a:[ a_src "/js/add-repro-steps.js" ] (txt ""); ] end