Skip to content

Commit

Permalink
cromwell metadata params [risk: low] (#1456)
Browse files Browse the repository at this point in the history
specify which keys to return for workflow metadata; lazy-load the workflow timing diagram
  • Loading branch information
davidangb committed Nov 14, 2018
1 parent 28c7aee commit a11a086
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 36 deletions.
25 changes: 18 additions & 7 deletions src/cljs/main/broadfcui/endpoints.cljs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
(ns broadfcui.endpoints
(:require
[clojure.string :as string]
[broadfcui.config :as config]
[broadfcui.utils :as utils]
[broadfcui.utils.ajax :as ajax]
Expand Down Expand Up @@ -140,9 +141,9 @@
(set (keys query-parameters)))
(str "Malformed query parameters: " query-parameters))
{:path (str "/workspaces/" (id-path workspace-id) "/entityQuery/" type "?"
(clojure.string/join "&" (keep (fn [[k v]]
(some->> v str not-empty (str k "=")))
query-parameters)))
(string/join "&" (keep (fn [[k v]]
(some->> v str not-empty (str k "=")))
query-parameters)))
:method :get})

(defn get-entities-by-type [workspace-id]
Expand Down Expand Up @@ -212,10 +213,20 @@
{:path (str "/workspaces/" (id-path workspace-id) "/submissions/" submission-id)
:method :get})

(defn get-workflow-details [workspace-id submission-id workflow-id]
{:path (str "/workspaces/" (id-path workspace-id) "/submissions/" submission-id
"/workflows/" workflow-id)
:method :get})
(defn get-workflow-details
;; basic form: use defaults for all query params
([workspace-id submission-id workflow-id] (get-workflow-details workspace-id submission-id workflow-id nil [] []))
;; includes form: specify which fields to include; defaults for everything else
([workspace-id submission-id workflow-id include-keys] (get-workflow-details workspace-id submission-id workflow-id nil include-keys []))
;; flexible form: specify any/all of expand-subworkflows, include-keys, exclude-keys
([workspace-id submission-id workflow-id expand-subworkflows include-keys exclude-keys]
(let [expand (when (some? expand-subworkflows) (str "&expandSubWorkflows=" expand-subworkflows))
include (string/join (mapv #(str "&includeKey=" %) include-keys))
exclude (string/join (mapv #(str "&excludeKey=" %) exclude-keys))
querystring (str expand include exclude)]
{:path (str "/workspaces/" (id-path workspace-id) "/submissions/" submission-id
"/workflows/" workflow-id "?" querystring)
:method :get})))

(defn get-workflow-cost [workspace-id submission-id workflow-id]
{:path (str "/workspaces/" (id-path workspace-id) "/submissions/" submission-id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@
:link-label link-label)]
(str gcs-uri))))

(defonce default-metadata-includes ["backendLogs" "backendStatus" "end" "executionStatus" "callCaching:hit"
"id" "inputs" "jobId" "outputs" "start" "status" "stderr" "stdout" "submission"
"submittedFiles:inputs" "workflowLog" "workflowName" "workflowRoot"])

(defonce metadata-timing-includes ["attempt" "description" "end" "endTime" "executionEvents" "executionStatus"
"shardIndex" "start" "startTime" "workflowName"])

(defn getTimingDiagramHeight [chartContainer]
(let [e (-> chartContainer (.-childNodes)
(aget 0) (.-childNodes)
Expand Down Expand Up @@ -82,34 +89,65 @@
:filterable? false}
:columns (if (:call-detail? props) columns (cons task-column columns))}}])])])})

(react/defc- WorkflowTiming
(react/defc- WorkflowTimingDiagram
{:render
(fn [{:keys [props state refs]}]
(let [{:keys [error? expanded? metadata-response]} @state
{:keys [workspace-id submission-id workflow]} props
workflow-name (workflow "workflowName")
workflow-id (workflow "id")]
(cond
(nil? metadata-response)
(spinner "Loading timing diagram...")
(not (:success? metadata-response))
(style/create-inline-error-message (str "Error loading timing data: " (:response metadata-response)))
:else
(let [data (:raw-response metadata-response)]
[:div {}
(if error?
(style/create-inline-error-message "Error loading charts.")
[ScriptLoader
{:on-error #(swap! state assoc :error? true)
:on-load (fn []
(js/google.charts.load "current" (clj->js {"packages" ["timeline"]}))
(js/google.charts.setOnLoadCallback
(fn []
(let [chart-container (@refs "chart-container")]
(.timingDiagram js/window chart-container data workflow-name 100)
(let [height (getTimingDiagramHeight chart-container)]
(.timingDiagram js/window chart-container data workflow-name (+ 75 height)))))))
:path "https://www.gstatic.com/charts/loader.js"}])
[:div {:ref "chart-container" :style {:paddingTop "0.5rem"}}]]))))
:component-did-mount
(fn [{:keys [props state]}]
(let [{:keys [workspace-id submission-id workflow]} props
workflow-name (workflow "name")
workflow-id (workflow "id")]
(endpoints/call-ajax-orch
{:endpoint
(endpoints/get-workflow-details workspace-id submission-id workflow-id metadata-timing-includes)
:on-done (fn [{:keys [success? get-parsed-response status-text raw-response]}]
(swap! state assoc :metadata-response
{:success? success?
:response (if success? (get-parsed-response false) status-text)
:raw-response raw-response}))})))})

(react/defc- WorkflowTimingContainer
{:render
(fn [{:keys [props state refs]}]
(let [{:keys [error? expanded?]} @state
{:keys [label data]} props]
(let [{:keys [expanded?]} @state
{:keys [workspace-id submission-id workflow label]} props]
[:div {}
(create-field
label
(if (empty? data)
"Not Available"
(links/create-internal {:onClick #(swap! state update :expanded? not)}
(if expanded? "Hide" "Show"))))
(when expanded?
[:div {}
(if error?
(style/create-server-error-message "Error loading charts.")
[ScriptLoader
{:on-error #(swap! state assoc :error? true)
:on-load (fn []
(js/google.charts.load "current" (clj->js {"packages" ["timeline"]}))
(js/google.charts.setOnLoadCallback
(fn []
(let [chart-container (@refs "chart-container")]
(.timingDiagram js/window chart-container data workflow-name 100)
(let [height (getTimingDiagramHeight chart-container)]
(.timingDiagram js/window chart-container data workflow-name (+ 75 height)))))))
:path "https://www.gstatic.com/charts/loader.js"}])
[:div {:ref "chart-container" :style {:paddingTop "0.5rem"}}]])]))})
(create-field label
(links/create-internal {:onClick #(swap! state update :expanded? not)}
(if expanded? "Hide" "Show")))
;; use expanded? to show/hide the WorkflowTimingDiagram component via the DOM
[:div {:style {:display (if expanded? "block" "none")}}
(when (some? expanded?)
;; as long as the user has clicked to show the WorkflowTimingDiagram at least once,
;; render it. After the first render, show/hide it via the DOM so we don't trigger
;; its ajax call more than once.
[WorkflowTimingDiagram (utils/restructure workspace-id submission-id workflow)])]]))})

(defn- backend-logs [data workspace-id]
(when-let [log-map (data "backendLogs")]
Expand Down Expand Up @@ -196,7 +234,7 @@
:backgroundColor (:background-light style/colors)}}
(create-field "Subworkflow ID" (links/create-external {:href (render-gcs-path subworkflow-path-components)} (workflow "id")))
(when (seq (workflow "calls"))
[WorkflowTiming {:label "Workflow Timing" :data raw-data :workflow-name workflow-name}])
[WorkflowTimingContainer (merge {:label "Workflow Timing"} (utils/restructure workspace-id submission-id workflow))])
(when-let [failures (workflow "failures")]
[Failures {:data failures}])
(when (seq (workflow "calls"))
Expand Down Expand Up @@ -224,7 +262,7 @@
(endpoints/call-ajax-orch
{:endpoint
(endpoints/get-workflow-details
(:workspace-id props) (:submission-id props) (:workflow-id props))
(:workspace-id props) (:submission-id props) (:workflow-id props) default-metadata-includes)
:on-done (fn [{:keys [success? get-parsed-response status-text raw-response]}]
(swap! state assoc :server-response
{:success? success?
Expand Down Expand Up @@ -349,7 +387,7 @@
(when-let [workflowLog (workflow "workflowLog")]
(create-field "Workflow Log" (display-value (:namespace workspace-id) workflowLog (str "workflow." (workflow "id") ".log"))))
(when (seq (workflow "calls"))
[WorkflowTiming {:label "Workflow Timing" :data raw-data :workflow-name workflow-name}])
[WorkflowTimingContainer (merge {:label "Workflow Timing"} (utils/restructure workspace-id submission-id workflow))])
(when-let [failures (workflow "failures")]
[Failures {:data failures}])
(when (seq (workflow "calls"))
Expand Down Expand Up @@ -380,7 +418,7 @@
(endpoints/call-ajax-orch
{:endpoint
(endpoints/get-workflow-details
(:workspace-id props) (:submission-id props) (:workflow-id props))
(:workspace-id props) (:submission-id props) (:workflow-id props) default-metadata-includes)
:on-done (fn [{:keys [success? get-parsed-response status-text raw-response]}]
(swap! state assoc :metadata-response
{:success? success?
Expand Down

0 comments on commit a11a086

Please sign in to comment.