aboutsummaryrefslogtreecommitdiff
path: root/webgui
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2016-02-25 18:04:49 +0100
committerGregor Kleen <gkleen@yggdrasil.li>2016-02-25 18:04:49 +0100
commitf515803694d7f8430b064f16a5a923b09ba70650 (patch)
tree1e5104f784e28a41a4d030e23e0841bb1173cb22 /webgui
parente6e3823982cb9755b7cb4727fb08171eed5b4332 (diff)
downloadthermoprint-f515803694d7f8430b064f16a5a923b09ba70650.tar
thermoprint-f515803694d7f8430b064f16a5a923b09ba70650.tar.gz
thermoprint-f515803694d7f8430b064f16a5a923b09ba70650.tar.bz2
thermoprint-f515803694d7f8430b064f16a5a923b09ba70650.tar.xz
thermoprint-f515803694d7f8430b064f16a5a923b09ba70650.zip
Job/Printer list
Diffstat (limited to 'webgui')
-rw-r--r--webgui/data/index.html32
-rw-r--r--webgui/data/style.css4
-rw-r--r--webgui/data/tabs.js2
-rw-r--r--webgui/src/Main.hs114
4 files changed, 133 insertions, 19 deletions
diff --git a/webgui/data/index.html b/webgui/data/index.html
index 3bdd047..e4a6c63 100644
--- a/webgui/data/index.html
+++ b/webgui/data/index.html
@@ -18,7 +18,7 @@
18 <ul class="tab-links"> 18 <ul class="tab-links">
19 <li class="active"><a href="#editor">Editor</a></li> 19 <li class="active"><a href="#editor">Editor</a></li>
20 <li><a href="#drafts">Drafts</a></li> 20 <li><a href="#drafts">Drafts</a></li>
21 <li><a href="#queue">Queue</a></li> 21 <li><a href="#printers">Printers & Jobs</a></li>
22 <li id="errors-tab" style="display:none;"><a href="#errors">Errors</a></li> 22 <li id="errors-tab" style="display:none;"><a href="#errors">Errors</a></li>
23 </ul> 23 </ul>
24 24
@@ -44,6 +44,7 @@
44 </div> 44 </div>
45 </div> 45 </div>
46 </div> 46 </div>
47
47 <div class="tab" id="drafts" style="text-align:center;"> 48 <div class="tab" id="drafts" style="text-align:center;">
48 <table style="width:100%;" id="draftList"> 49 <table style="width:100%;" id="draftList">
49 <thead> 50 <thead>
@@ -65,8 +66,33 @@
65 </table> 66 </table>
66 </div> 67 </div>
67 68
68 <div class="tab" id="queue"> 69 <div class="tab" id="printers" style="text-align:center;">
69 Blub. 70 <table style="width:100%;" id="printerList">
71 <thead>
72 <tr>
73 <td style="width:10em;">Printer Id</td>
74 <td style="width:10em;">Job Id</td>
75 <td style="width:20em;">Created</td>
76 <td>Status</td>
77 <td style="width:20em;">Actions</td>
78 </tr>
79 </thead>
80 <tbody id="printerListBody"></tbody>
81 <tfoot>
82 <tr>
83 <td colspan="4" style="border-style:none;"></td>
84 <td>
85 <input id="autoselectPrinter" type="radio" name="printer" value="Nothing" checked="checked" /><label for="autoselectPrinter">Have server select printer</label>
86 </td>
87 </tr>
88 <tr>
89 <td colspan="4" style="border-style:none;"></td>
90 <td>
91 <input id="allowAbortion" type="checkbox" /><label for="allowAbortion">Allow Abortion</label>
92 </td>
93 </tr>
94 </tfoot>
95 </table>
70 </div> 96 </div>
71 97
72 <ul class="tab" id="errors"> 98 <ul class="tab" id="errors">
diff --git a/webgui/data/style.css b/webgui/data/style.css
index 9946208..6ab1704 100644
--- a/webgui/data/style.css
+++ b/webgui/data/style.css
@@ -89,6 +89,10 @@ tfoot tr:first-child td {
89 width:6em; 89 width:6em;
90} 90}
91 91
92tr.focused td {
93 background-color:#d0d0d0;
94}
95
92/*----- Tabs -----*/ 96/*----- Tabs -----*/
93.tabs { 97.tabs {
94 display:block; 98 display:block;
diff --git a/webgui/data/tabs.js b/webgui/data/tabs.js
index 1d178d9..d3263c6 100644
--- a/webgui/data/tabs.js
+++ b/webgui/data/tabs.js
@@ -7,6 +7,8 @@ jQuery(document).ready(function() {
7 7
8 // Change/remove current tab to active 8 // Change/remove current tab to active
9 jQuery(this).parent('li').addClass('active').siblings().removeClass('active'); 9 jQuery(this).parent('li').addClass('active').siblings().removeClass('active');
10
11 jQuery('.focused').removeClass('focused');
10 12
11 e.preventDefault(); 13 e.preventDefault();
12 }); 14 });
diff --git a/webgui/src/Main.hs b/webgui/src/Main.hs
index cbb1a75..dbf34bc 100644
--- a/webgui/src/Main.hs
+++ b/webgui/src/Main.hs
@@ -39,14 +39,19 @@ import Control.Exception
39import Control.Monad.Catch 39import Control.Monad.Catch
40 40
41import Control.Applicative 41import Control.Applicative
42import Control.Monad 42import Control.Monad hiding (sequence)
43import Data.Maybe 43import Data.Maybe
44import Data.Monoid 44import Data.Monoid
45import Text.Read hiding (get) 45import Text.Read hiding (get)
46import Data.Either 46import Data.Either
47import Data.List (isPrefixOf) 47import Data.List (isPrefixOf, sortBy)
48import Data.Ord
49import qualified Data.Function as F
48import Data.Bool 50import Data.Bool
49 51
52import Data.Traversable (sequence)
53import Data.Foldable
54
50import Paths_thermoprint_webgui 55import Paths_thermoprint_webgui
51 56
52import Debug.Trace 57import Debug.Trace
@@ -100,8 +105,10 @@ setup Config{..} window (split -> (socketErr, dataUpdate)) = void $ do
100 onEvent socketErr handleSocketErr 105 onEvent socketErr handleSocketErr
101 106
102 getElementById window "javascriptError" >>= maybeM delete 107 getElementById window "javascriptError" >>= maybeM delete
108
109 selectedPrinter <- handleJobTable
103 110
104 changeEditorStatus <- handleEditor 111 changeEditorStatus <- handleEditor selectedPrinter
105 112
106 handleDraftTable changeEditorStatus 113 handleDraftTable changeEditorStatus
107 114
@@ -136,7 +143,7 @@ setup Config{..} window (split -> (socketErr, dataUpdate)) = void $ do
136 143
137 Client{..} = mkClient (Nat $ either (fatal . ("Error while communicating to Thermoprint.Server: " ++) . show) return <=< liftIO . runEitherT) server 144 Client{..} = mkClient (Nat $ either (fatal . ("Error while communicating to Thermoprint.Server: " ++) . show) return <=< liftIO . runEitherT) server
138 145
139 handleEditor = do 146 handleEditor selectedPrinter = do
140 title <- fatal' "Could not find editor title field" =<< getElementById window "editorTitle" 147 title <- fatal' "Could not find editor title field" =<< getElementById window "editorTitle"
141 text <- fatal' "Could not find editor text field" =<< getElementById window "editorText" 148 text <- fatal' "Could not find editor text field" =<< getElementById window "editorText"
142 status <- fatal' "Could not find editor status field" =<< getElementById window "editorStatus" 149 status <- fatal' "Could not find editor status field" =<< getElementById window "editorStatus"
@@ -202,9 +209,9 @@ setup Config{..} window (split -> (socketErr, dataUpdate)) = void $ do
202 Right po -> case associatedDraft of 209 Right po -> case associatedDraft of
203 Just dId -> do 210 Just dId -> do
204 saved <- saveAction False 211 saved <- saveAction False
205 when saved $ runFunction . focusJob =<< draftPrint dId Nothing -- FIXME 212 when saved $ runFunction . focusJob =<< draftPrint dId =<< currentValue selectedPrinter
206 Nothing -> do 213 Nothing -> do
207 runFunction . focusJob =<< jobCreate Nothing po -- FIXME 214 runFunction . focusJob =<< flip jobCreate po =<< currentValue selectedPrinter
208 Left err -> emitError $ "Could not print draft due to error parsing bbcode: " ++ show err 215 Left err -> emitError $ "Could not print draft due to error parsing bbcode: " ++ show err
209 216
210 onEvent (whenE saveDraft $ tick autoSaveTimer) (const . void $ saveAction True) 217 onEvent (whenE saveDraft $ tick autoSaveTimer) (const . void $ saveAction True)
@@ -214,6 +221,7 @@ setup Config{..} window (split -> (socketErr, dataUpdate)) = void $ do
214 return discardButton # sink UI.enabled (discardable <$> editorStatus) 221 return discardButton # sink UI.enabled (discardable <$> editorStatus)
215 222
216 return discardButton # sink UI.text (bool "Discard" "Save & Clear" <$> saveDraft) 223 return discardButton # sink UI.text (bool "Discard" "Save & Clear" <$> saveDraft)
224 return printButton # sink UI.text (maybe "Print" (\(PrinterId i) -> "Print on " ++ show i) <$> selectedPrinter)
217 225
218 on (whenE saveDraft . UI.click) saveButton . const . void $ saveAction False 226 on (whenE saveDraft . UI.click) saveButton . const . void $ saveAction False
219 on UI.click printButton $ const printAction 227 on UI.click printButton $ const printAction
@@ -268,17 +276,91 @@ setup Config{..} window (split -> (socketErr, dataUpdate)) = void $ do
268 initialContent <- toTable =<< drafts 276 initialContent <- toTable =<< drafts
269 return table # set children initialContent 277 return table # set children initialContent
270 278
271 recheckTimer <- timer 279 update <- do
272 return recheckTimer # set interval 5000 280 -- recheckTimer <- timer
273 start recheckTimer 281 -- return recheckTimer # set interval 5000
282 -- start recheckTimer
283
284 -- return $ unionWith const (() <$ filterE concernsDrafts dataUpdate) (tick recheckTimer)
285 return $ filterE concernsDrafts dataUpdate
274 286
275 onEvent (unionWith const (() <$ filterE concernsDrafts dataUpdate) (tick recheckTimer)) . const $ drafts >>= toTable >>= (\c -> return table # set children c) 287 onEvent update . const $ drafts >>= toTable >>= (\c -> return table # set children c)
276 where 288
277 concernsDrafts :: URI -> Bool 289 concernsDrafts :: URI -> Bool
278 concernsDrafts (uriPath -> p) 290 concernsDrafts (uriPath -> p)
279 | p == "drafts" = True 291 | p == "drafts" = True
280 | "draft/" `isPrefixOf` p = True 292 | "draft/" `isPrefixOf` p = True
281 | otherwise = False 293 | otherwise = False
294
295 concernsPrinters :: URI -> Bool
296 concernsPrinters (uriPath -> p)
297 | p == "printers" = True
298 | "jobs/" `isPrefixOf` p = True
299 | otherwise = False
300
301 handleJobTable = do
302 allowAbortion <- do
303 allowAbortion <- fatal' "Could not find abortion switch" =<< getElementById window "allowAbortion"
304 flip stepper (UI.checkedChange allowAbortion) =<< (allowAbortion # get UI.checked)
305
306 (selectedPrinter, updatePrinter) <- do
307 autoselectPrinter <- fatal' "Could not find printer autoselect switch" =<< getElementById window "autoselectPrinter"
308 (selectedPrinter, printerSelect) <- stepper' Nothing
309 return autoselectPrinter # sink UI.checked (isNothing <$> selectedPrinter)
310 let
311 -- getSelectedPrinter :: UI (Maybe PrinterId)
312 getSelectedPrinter = (fmap PrinterId . join . readMaybe) <$> callFunction (ffi "$('input[name=printer]:checked', '#printers').val()")
313 updatePrinterSelect = getSelectedPrinter >>= liftIO . printerSelect
314 on (domEvent "change") autoselectPrinter $ const updatePrinterSelect
315 return (selectedPrinter, updatePrinterSelect)
316
317 let
318 -- getServerState :: UI [(PrinterId, PrinterStatus, [(JobId, UTCTime, JobStatus)])]
319 getServerState = map mangleTuple . Map.toList <$> (Map.traverseWithKey (\pId status -> (,) status <$> getJobState pId) =<< printers)
320 -- getJobState :: PrinterId -> UI [(JobId, UTCTime, JobStatus)]
321 getJobState pId = toList <$> jobs (Just pId) Nothing Nothing
322 mangleTuple (a, (b, c)) = (a, b, c)
323 thrd (_, _, c) = c
324
325 -- toTable :: [(PrinterId, PrinterStatus, [(JobId, UTCTime, JobStatus)])] -> UI [Element]
326 toTable = fmap concat . mapM toSubTable
327 -- toSubTable :: (PrinterId, PrinterStatus, [(JobId, UTCTime, JobStatus)]) -> UI [Element]
328 toSubTable (rPId@(PrinterId pId), pStatus, (sortBy (queueSort `F.on` thrd) -> jobs)) = do
329 pId' <- UI.td # set UI.text (show pId)
330 pStatus' <- UI.td # set UI.text (show pStatus)
331 let selectId = "printer" ++ show pId
332 checked <- (== Just rPId) <$> currentValue selectedPrinter
333 pSelect <- UI.input # set UI.type_ "radio" # set UI.name "printer" # set UI.value (show $ Just pId) # set UI.id_ selectId # set UI.checked checked
334 on (domEvent "change") pSelect $ const updatePrinter
335 pSelectL <- UI.label # set UI.for selectId # set UI.text "Use for new jobs"
336 pSelect' <- UI.td # set children [pSelect, pSelectL]
337 pFiller <- UI.td # set UI.colspan 2
338 let
339 toLine ((JobId jId), time, status) = do
340 jPId <- UI.td
341 jId' <- UI.td # set UI.text (show jId)
342 jStatus' <- UI.td # set UI.text (show status)
343 abortButton <- UI.button # sink UI.enabled allowAbortion # set UI.text "Abort"
344 actions <- UI.td # set children [abortButton]
345 UI.tr # set UI.id_ ("job" ++ show jId) # set children [jPId, jId', jStatus', actions]
346 (:) <$> UI.tr # set children [pId', pFiller, pStatus', pSelect'] <*> mapM toLine jobs
347
348 update <- do
349 -- recheckTimer <- timer
350 -- return recheckTimer # set interval 5000
351 -- start recheckTimer
352
353 -- return $ unionWith const (() <$ filterE concernsPrinters dataUpdate) (tick recheckTimer)
354 return $ filterE concernsPrinters dataUpdate
355
356 table <- fatal' "Could not find printer table" =<< getElementById window "printerListBody"
357 initialContent <- toTable =<< getServerState
358 return table # set children initialContent
359
360 onEvent update . const $ getServerState >>= toTable >>= (\c -> return table # set children c) >> updatePrinter
361
362 return selectedPrinter
363
282 364
283focusJob :: JobId -> JSFunction () 365focusJob :: JobId -> JSFunction ()
284focusJob (JobId (fromInteger -> i)) = ffi "alert(%1)" (i :: Int) -- FIXME 366focusJob (JobId (fromInteger -> i)) = ffi "alert(%1)" (i :: Int) -- FIXME