Skip to content
Permalink
b3a4236922
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
360 lines (327 sloc) 11.6 KB
(ns ulysses.pages.builder
(:require [re-frame.core :as re-frame :refer [subscribe dispatch]]
[re-com.core :refer [selection-list]]
[ulysses.components.basic :refer [hink
link
loading-or-no-results
fa
tabs
range-slider
text-input]]
[ulysses.components.misc :refer [grant-op-meta]]
[ulysses.components.word-cloud :refer [word-cloud]]
[ulysses.utils :refer [map-subels map-lookup str->int classes-attr]]
[ulysses.lib.packer :as packer]
[ulysses.lib.moment :as m]
[reagent.core :as r]
[clojure.string :as string]
[cljs.pprint :as pprint]
[ulysses.extra :refer [select_values]]))
;; ----------------------------------------------------------------------------
; helpers
;; ----------------------------------------------------------------------------
(defn- get-grant-op-id [page-with-args]
(-> page-with-args second :grant-op-id str->int))
;; ----------------------------------------------------------------------------
; components
;; ----------------------------------------------------------------------------
(defn faculty-years-uconn
[{:keys [faculty-years-uconn]}]
[:select
{:value faculty-years-uconn
:on-change (fn [e]
(dispatch [:builder-filter-faculty-years-uconn
(->> e
(.-target)
(select_values)
(js->clj))]))}
(map-subels
(fn [t] [:option {:value t} (str t "+")])
(range 0 (inc 30)))])
(defn faculty-title-multiselect
[faculty-titles {:keys [faculty-title-set]}]
[selection-list
:multi-select? true
:hide-border? true
:required? true
:max-height "200px"
:choices
(mapv #(hash-map :id % :label %) faculty-titles)
:model
faculty-title-set
:on-change
(fn [v]
(dispatch [:builder-filter-faculty-title-set v]))])
(defn metric-slider
[metric filters]
(let [value (get-in filters [:metrics metric])]
[:div.relative
[:div.absolute.small.color-gray.right-below-bottom value "%"]
[range-slider
:min 0 :max 100 :value value
:on-change
(fn [v]
(dispatch [:builder-filter-faculty-metric metric v]))]]))
(defn sidebar-section
[title & body]
[:div.builder-panel-sidebar-section
[:h4 title]
(into [:div] body)])
(defn sidebar-slider-section
[filters title filter-name]
[sidebar-section
title
[metric-slider
filter-name
filters]])
(defn sidebar
[faculty-titles filters]
[:div.builder-panel-sidebar
[:h3 "Filters"]
[sidebar-section
"Titles"
[faculty-title-multiselect
faculty-titles
filters]]
[sidebar-section
"Years at UConn"
[faculty-years-uconn
filters]]
[sidebar-slider-section
filters
"Publication Count"
:publicationCount]
[sidebar-slider-section
filters
"Grant Count"
:grantCount]
[sidebar-slider-section
filters
"Grant Funds"
:grantFunds]
[sidebar-slider-section
filters
"Recent Grant Count"
:recentGrantCount]
[sidebar-slider-section
filters
"Recent Grant Funds"
:recentGrantFunds]
[:br]])
(defn workspace-row [faculty]
(let [{:keys [id name title year_hired]} faculty]
[:tr.faculty-row
{:on-mouse-over #(dispatch [:builder-workspace-faculty-hover id])
:on-mouse-leave #(dispatch [:nil-builder-workspace-faculty-hover])}
[:td.first-col
[hink
(partial dispatch [:remove-working-faculty id])
{:class :g-plus}
[fa :minus-square-o]]]
[:td name]
[:td (string/capitalize title)]
[:td year_hired]]))
(defn workspace [faculties]
(if (empty? faculties)
[loading-or-no-results
:not-found-message
"Your workspace is empty. Add faculty from the pool to the right."]
[:div.faculties-pool.table-responsive
[:table.table.table-striped.table-bordered.table-sm
[:thead
[:tr [:th nil] [:th "Name"] [:th "Title"] [:th "Year Hired"]]]
[:tbody
(map-subels workspace-row faculties)]]]))
(defn workspace-header-tabs [workspaces workspace-current]
[tabs
(map
(fn [{:keys [id name]}]
; make tab-map
{:name (if-not (string/blank? name) name (str "untitled #" id))
:on-click #(dispatch [:workspace-switch id])
:is-active (= id (:id workspace-current))})
workspaces)])
(defn workspace-header [workspaces workspace-current]
(let [btn-attrs (classes-attr :btn :btn-sm :btn-primary)]
[:div
[:div.workspace-header-first
[:h3 "Working Team"]
[:div.workspace-actions
[hink #(dispatch [:workspace-new-blank]) btn-attrs "New Blank"]
[hink #(dispatch [:workspace-new-default]) btn-attrs "New from Default"]
[hink #(dispatch [:workspace-new-duplicate]) btn-attrs "Duplicate"]]]
[workspace-header-tabs workspaces workspace-current]]))
(defn workspace-last-saved [workspace-current workspaces-saved-timestamps]
(let [n-updates (r/atom 0)]
(fn [workspace-current workspaces-saved-timestamps]
(let [_ @n-updates]) ; subscribe; not used
(when-let [timestamp (get workspaces-saved-timestamps (:id workspace-current))]
(when (m/is-valid timestamp)
; set timeout for next self-update
(js/setTimeout
(fn []
(swap! n-updates inc))
(* 2 1000))
[:span.workspace-last-saved
"last saved "
(m/from-now timestamp)])))))
(defn workspace-rename [workspace-current]
(let [new-name (r/atom (str))]
(fn [workspace-current]
[hink
(fn []
(reset! new-name (:name workspace-current))
(dispatch
[:modal
{:title [:span "Rename Workspace " [:i (:name workspace-current)]]
:action-label "Rename"
:on-action #(dispatch [:workspace-rename @new-name])
:children
[:div
[text-input
:placeholder "Name"
:value new-name]]}]))
(classes-attr :btn :btn-sm :btn-info)
"Rename"])))
(defn workspace-save []
[hink
(partial dispatch [:workspace-save])
(classes-attr :btn :btn-sm :btn-primary)
"Save"])
(defn workspace-delete [workspace-current]
[hink
(fn []
(dispatch
[:modal
{:title [:span "Delete Workspace " [:i (:name workspace-current)]]
:action-label "Delete"
:action-brand :danger
:on-action #(dispatch [:workspace-delete])
:children "Are you sure you want to delete this workspace?"}]))
(classes-attr :btn :btn-sm :btn-danger)
"Delete"])
(defn workspace-footer [workspace-current workspaces-saved-timestamps]
(when workspace-current
[:div.workspace-footer
[workspace-last-saved workspace-current workspaces-saved-timestamps]
[workspace-rename workspace-current]
[workspace-delete workspace-current]
[workspace-save]]))
(defn pool-row [fam]
(let [{:keys [faculty fundingCoverageScore]} fam
{:keys [id name title year_hired]} faculty]
[:tr.faculty-row
[:td.first-col
[hink
(partial dispatch [:add-working-faculty id])
{:class :g-plus}
[fa :plus-square-o]]]
[:td name]
[:td (string/capitalize title)]
[:td year_hired]
[:td (pprint/cl-format nil "~,4f" fundingCoverageScore)]
[:td
[link [:profile :person-id id] {}
[:span.label.label-default "View Profile"]]]]))
(defn pool [faculties-and-metrics]
(if (empty? faculties-and-metrics)
[loading-or-no-results]
[:div.faculties-pool.table-responsive
[:table.table.table-striped.table-bordered.table-sm
[:thead
[:tr [:th nil] [:th "Name"] [:th "Title"] [:th "Year Hired"] [:th "Score"] [:th ""]]]
[:tbody
(map-subels pool-row faculties-and-metrics)]]]))
(defn builder-panel
[op
faculties faculty-titles faculties-pool
workspaces workspace-current workspace-faculty-hover
workspaces-saved-timestamps
filters]
[:div.builder-panel
[sidebar faculty-titles filters]
[:div.builder-panel-main
[:div.builder-panel-half-section
[:div.inner
[workspace-header workspaces workspace-current]
[workspace (map-lookup faculties (or (:faculties workspace-current) []))]
[workspace-footer workspace-current workspaces-saved-timestamps]]
[:div.inner
[:h3 "Word Cloud"]
(when workspace-faculty-hover
[word-cloud 20 (:keywords workspace-faculty-hover)])]]
[:div.builder-panel-half-section
[:div.inner
[:h3 "Results"]
[pool faculties-pool]]
[:div.inner
[:h3 "Word Cloud"]]]]])
(defn builder-header
[{:keys [title purpose] :as op}]
[:div.builder-header
[:div.container-fluid
[:div.row
[:div.col-md-12
[:h3.text-xs-center.mb-15 title]
[:div.text-xs-center
[grant-op-meta true op]]
[:p purpose]]]]])
;; ----------------------------------------------------------------------------
;; main
;; ----------------------------------------------------------------------------
(defn main []
(let [page-with-args (subscribe [:page-with-args])
grant-op (subscribe [:builder-grant-op])
faculties (subscribe [:faculties])
faculty-titles (subscribe [:faculty-titles])
faculties-pool (subscribe [:builder-faculties-pool-filtered])
workspaces (subscribe [:workspaces-current])
workspace (subscribe [:builder-workspace])
workspace-faculty-hover (subscribe [:builder-workspace-faculty-hover])
workspaces-saved-timestamps (subscribe [:builder-workspaces-saved-timestamps])
filters (subscribe [:builder-filters])
last-id (atom nil)]
(r/create-class
{:component-will-mount
(fn []
(let [id (get-grant-op-id @page-with-args)]
(reset! last-id id)
(dispatch [:nil-builder])
(dispatch [:request-faculty-titles])
; common with will-update:
(dispatch [:request-builder-grant-op id])
(dispatch [:workspace-load-from-op id])
(dispatch [:request-faculties-pool])))
:component-will-update
(fn []
(let [pwa @page-with-args
id (get-grant-op-id pwa)]
(when (and (not= id @last-id) (= :builder (first pwa)))
(dispatch [:nil-builder])
(dispatch [:request-builder-grant-op id])
(dispatch [:workspace-load-from-op id])
(dispatch [:request-faculties-pool]))
(reset! last-id id)))
:component-will-unmount
(fn []
(dispatch [:nil-builder]))
:reagent-render
(fn []
(let [op @grant-op
_ @page-with-args]
(if op
[:div
[builder-header op]
[builder-panel
op
@faculties
@faculty-titles
@faculties-pool
@workspaces
@workspace
@workspace-faculty-hover
@workspaces-saved-timestamps
@filters]]
[loading-or-no-results
:not-found-message
"The requested grant opportunity was not found."])))})))