· 4 years ago · Jun 22, 2021, 11:06 AM
1(defnc demo3
2 []
3 {:helix/features {:fast-refresh true}}
4 (let [[options set-options] (hooks/use-state nil)
5 [view set-view] (hooks/use-state (common/new-empty-view {:view-type "time-chart"
6 :label "New view"}))
7 [selected-level set-selected-level] (hooks/use-state "site")
8 [containers set-containers] (hooks/use-state [])
9 [selected-container set-selected-container] (hooks/use-state "all-sites")
10 [template-mode set-template-mode] (hooks/use-state false)
11 [selected-template set-selected-template] (hooks/use-state nil)
12 [templates set-templates] (hooks/use-state [])
13 [objects set-objects] (hooks/use-state [])
14 [indicators set-indicators] (hooks/use-state [])
15 [selected-objects set-selected-objects] (hooks/use-state [])
16 [selected-indicators set-selected-indicators] (hooks/use-state [])
17 [datasets set-datasets] (hooks/use-state [])
18 [parameter-options set-parameter-options] (hooks/use-state {})]
19
20 ;; main level dropdown
21 (hooks/use-effect
22 [selected-level]
23 (-> (common/get-containers selected-level)
24 (p/then (fn [containers]
25 (set-containers containers)))))
26
27 ;; available templates given level and device
28 (hooks/use-effect
29 [view selected-level selected-container]
30 (-> (common/get-templates view {:selectedLevel selected-level
31 :selectedContainer selected-container})
32 (p/then (fn [templates]
33 (println templates)
34 (set-templates templates)))))
35
36 ;; get available objects given level and device (enum mode)
37 (hooks/use-effect
38 [selected-level selected-container]
39 (-> (api (str "/logical_devices?" (uri/buildQueryDataFromMap
40 (clj->js {:filter (concat [(str "ld_type:" selected-level)]
41 (when (and selected-container
42 (not (re-matches #"all-.*" selected-container)))
43 [(str "container:" selected-container)]))
44 ;; ONLY FOR DEMO: DO NOT USE THIS TECHNIQUE, USE THE PAGING API
45 :limit 10000}))))
46 (p/then (fn [response]
47 (set-objects response)))))
48
49 ;; reset object indicator list on template mode change
50 (hooks/use-effect
51 [template-mode]
52 (set-selected-objects [])
53 (set-selected-indicators [])
54 (set-indicators []))
55
56 ;; get indicators given mode and selected objects
57 (hooks/use-effect
58 [template-mode selected-objects selected-level]
59 (-> (api (str "/indicators?" (uri/buildQueryDataFromMap #js {:ld_type selected-level
60 :locale "en"})))
61 (p/then (fn [response]
62 (let [indicator-map (->> (for [{:keys [key label]} (js->clj response :keywordize-keys true)]
63 [key label])
64 (into {}))]
65 (if template-mode
66 (set-indicators (->> (for [[k v] indicator-map]
67 {:value k
68 :label v})
69 (sort-by :label)))
70
71 ;; if we have selected objects, use ld_indicators to filter just the applicable ones.
72 (when (seq selected-objects)
73 (-> (api (str "/ld_indicators?" (uri/buildQueryDataFromMap #js {:object (into-array selected-objects)})))
74 (p/then (fn [response]
75 (set-indicators (->> (for [{:keys [indicator_key]} (js->clj response :keywordize-keys true)
76 :let [label (get indicator-map indicator_key)]]
77 {:value indicator_key
78 :label label})
79 (distinct)
80 (sort-by :label)))))))))))))
81
82 ;; when the view changes, refresh the basket, the parameter options and the visualization
83 (hooks/use-effect
84 [view]
85 (let [cancel-fetch (volatile! nil)]
86 (when view
87 (-> (common/get-datasets view)
88 (p/then (fn [datasets]
89 (set-datasets datasets))))
90
91
92 ;; get the parameter options
93 (-> (for [{:keys [ldType container] :as parameter} (common/get-object-parameters view)]
94 (-> (api (str "/logical_devices?" (uri/buildQueryDataFromMap
95 (clj->js {:filter (concat [(str "ld_type:" (name ldType))]
96 (when container
97 [(str "container:" container)]))
98 ;; *** ONLY FOR DEMO: DO NOT USE THIS TECHNIQUE IN REAL APPLICATION, USE THE PAGING API ***
99 :limit 10000}))))
100 (p/then (fn [response]
101 (merge parameter {:options (for [{:keys [logical_device]} (js->clj response :keywordize-keys true)
102 :let [{:keys [ref label]} logical_device]]
103 {:value ref
104 :label label})})))))
105 p/all
106 (p/then (fn [parameter-options]
107 (set-parameter-options parameter-options))))
108
109 ;; show the visualization of there are no object parameters or they have all been set
110 (when (or (empty? (common/get-object-parameters view))
111 (every? :value (common/get-object-parameters view)))
112 (-> (common/get-visualization view)
113 (p/then (fn [visualization]
114 (set-options (clj->js (:spec visualization)))
115 (vreset! cancel-fetch
116 (common/populate-visualization
117 visualization
118 (fn [visualization]
119 (set-options (clj->js (:spec visualization))))))))
120 (p/catch js/console.log)))
121
122 (fn []
123 (when-let [cancel @cancel-fetch]
124 (cancel))))))
125
126 ;; Main interface
127 (d/div
128 (d/div {:style {:display "flex"
129 :alignItems "center"
130 :flexDirection "row"
131 :margin "10px 0"}}
132
133 ;; Level selector dropdown
134 (d/span {:style {:marginRight "10px"}} "Level")
135 (d/select {:value selected-level
136 :onChange (fn [ev]
137 (set-selected-level (.. ev -target -value)))
138 :style {:marginRight "10px"}}
139 (for [{:keys [value label]} common/levels]
140 (d/option {:key value
141 :value value} label)))
142
143 ;; Container selector dropdown
144 (when (seq containers)
145 (<>
146 (d/span {:style {:marginRight "10px"}} "In")
147 (d/div {:style {:display "flex"
148 :flexDirection "row"}}
149 (d/select {:value selected-container
150 :onChange (fn [ev]
151 (set-selected-container (.. ev -target -value)))}
152 (for [{:keys [value label]} containers]
153 (d/option {:key value
154 :value value} label)))))))
155 ;; "Template mode" toggle
156 (d/div {:style {:display "flex"
157 :alignItems "center"
158 :flexDirection "row"}}
159 (d/input {:type "checkbox"
160 :id "template-mode"
161 :name "template-mode"
162 :checked template-mode
163 :onChange (fn [ev]
164 (set-template-mode (.. ev -target -checked)))})
165 (d/label {:for "template-mode"} "Template mode"))
166
167 ;; Object set selection
168 (d/div {:style {:display "flex"
169 :flexDirection "row"}}
170
171 (d/div {:style {:display "flex"
172 :flexDirection "row"}}
173 (d/div {:style {:width "20rem"
174 :display "flex"
175 :flexDirection "column"}}
176 (d/span {:style {:margin "10px 0"}} "Object set")
177 (if template-mode
178 ;; Template selector
179 (d/form {:style {:display "flex"
180 :flexDirection "column"
181 :justifyContent "flex-start"
182 :borderWidth "1px"
183 :borderStyle "solid"
184 :borderColor "grey"}}
185 (for [{:keys [value label]} templates]
186 (d/div {:style {:display "flex"
187 :flexDireciton "row"
188 :alignItems "center"
189 :margin "3px 0"}}
190 (d/input {:type "radio"
191 :key value
192 :id value
193 :value value
194 :onChange (fn [ev]
195 (set-selected-template (.. ev -target -value)))
196 :name "template"})
197 (d/label {:for value} label))))
198
199 ;; Object selector (for enums)
200 (d/select {:multiple true
201 :style {:height "10rem"
202 :width "100%"}
203 :onChange (fn [ev]
204 (set-selected-objects
205 (for [option (js->clj (.. ev -target -selectedOptions))]
206 (.-value option))))}
207 (for [device (js->clj objects :keywordize-keys true)
208 :let [{:keys [logical_device]} device
209 {:keys [ref label]} logical_device]]
210 (d/option {:key ref
211 :value ref} label)))))
212
213 ;; indicator selection
214 (d/div {:style {:display "flex"
215 :flexDirection "column"
216 :marginLeft "1rem"}}
217 (d/span {:style {:margin "10px 0"}} "Indicators")
218 (d/select {:multiple true
219 :value (clj->js selected-indicators)
220 :style {:height "10rem"
221 :width "10rem"}
222 :onChange (fn [ev]
223 (set-selected-indicators
224 (for [option (js->clj (.. ev -target -selectedOptions))]
225 (.-value option))))}
226 (for [{:keys [value label]} indicators]
227 (d/option {:key value
228 :value value} label)))
229
230 ;; add button
231 (d/button {:style {:margin "10px 0px"
232 :height "20px"
233 :alignSelf "flex-end"}
234 :disabled (not (seq selected-indicators))
235 :onClick (fn []
236 (let [new-view (reduce
237 (fn [view indicator]
238 (cond
239 (and template-mode
240 selected-level
241 selected-template)
242 , (common/add-template-dataset
243 view
244 {:selectedLevel selected-level
245 :selectedContainer selected-container
246 :selectedTemplate selected-template}
247 [indicator]
248 {:graphicalRepresentation "line"})
249 (not template-mode)
250 , (common/add-enum-dataset
251 view
252 selected-objects
253 [indicator]
254 {:graphicalRepresentation "line"})
255 :else view))
256 view
257 selected-indicators)]
258 (set-view new-view)))}
259 "Add")))
260
261 ;; dataset list
262 (when (seq datasets)
263 (d/div {:style {:display "flex"
264 :flexDirection "column"
265 :marginLeft "1rem"}}
266 (d/span {:style {:margin "10px 0"}} "Object/indicator selection")
267 (d/table {:border 1
268 :style {:borderCollapse "collapse"
269 :fontSize "12px"
270 :alignSelf "flex-start"}}
271 (d/thead
272 (d/tr
273 (d/th {:style {:padding "5px" :width "150px"}} "Objects")
274 (d/th {:style {:padding "5px" :width "250px"}} "Indicator")
275 (d/th {:style {:padding "5px" :width "50px"}} "Representation")
276 (d/th {:style {:padding "5px" :width "50px"}} "Actions")))
277 (d/tbody
278 (for [{:keys [id objectSet objectSetLabel indicators representation]} datasets
279 :let [{:keys [objects]} objectSet]]
280 (d/tr {:key id}
281 (d/td {:style {:padding "5px"}}
282 (str objectSetLabel
283 (when (> (count objects) 1)
284 (str " (+" (dec (count objects)) ")"))))
285 (d/td {:style {:padding "5px"}}
286 (-> indicators first :label))
287 (d/td {:style {:padding "5px"}}
288 representation)
289 (d/td {:style {:padding "5px"}}
290 (d/button {:onClick (fn []
291 (set-view (common/remove-dataset view id)))}
292 "Delete")))))))))
293 (when (seq parameter-options)
294 (d/div (for [{:keys [label value id options]} parameter-options]
295 (d/div
296 {:style {:display "flex"
297 :flexDirection "row"
298 :alignItems "center"}}
299 (d/label {:for id} label)
300 (d/select
301 {:value value
302 :id id
303 :onChange (fn [ev]
304 (when (.. ev -target -value)
305 (set-view (common/set-object-parameter view id (.. ev -target -value)))))
306 :style {:marginLeft "1rem"}}
307 (concat
308 [(d/option "- ")]
309 (for [{:keys [value label]} options]
310 (d/option {:key value
311 :value value} label))))))))
312 (when (and (seq datasets)
313 (every? :value parameter-options)
314 options)
315 ($ HighchartsReact {:highcharts Highcharts
316 :options options})))))
317