From cdb6329b6acaab0a15441554412d8f5ececece1b Mon Sep 17 00:00:00 2001 From: stuebinm Date: Thu, 10 Feb 2022 00:14:43 +0100 Subject: server: simple servant-lucid stuff --- lib/CheckDir.hs | 3 +-- package.yaml | 3 +++ server/Main.hs | 25 +++++++++++++++++------- server/Orphans.hs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ server/Server.hs | 21 +++++++++++++++++++- stack.yaml | 2 +- stack.yaml.lock | 7 +++++++ walint.cabal | 5 ++++- 8 files changed, 111 insertions(+), 12 deletions(-) create mode 100644 server/Orphans.hs diff --git a/lib/CheckDir.hs b/lib/CheckDir.hs index f876084..eeb94a8 100644 --- a/lib/CheckDir.hs +++ b/lib/CheckDir.hs @@ -7,7 +7,7 @@ {-# LANGUAGE TypeFamilies #-} -- | Module that contains high-level checking for an entire directory -module CheckDir (recursiveCheckDir, DirResult(..), resultIsFatal) where +module CheckDir (maximumLintLevel, recursiveCheckDir, DirResult(..), MissingAsset(..), MissingDep(..), resultIsFatal) where import CheckMap (MapResult (..), loadAndLintMap) import Control.Monad (void) @@ -38,7 +38,6 @@ import Types (Dep (Local, LocalMap), Hint (Hint), Level (..), hintLevel) import Util (PrettyPrint (prettyprint), ellipsis) - -- based on the startling observation that Data.Map has lower complexity -- for difference than Data.Set, but the same complexity for fromList type Set a = Map a () diff --git a/package.yaml b/package.yaml index a4681bc..6a3abc0 100644 --- a/package.yaml +++ b/package.yaml @@ -34,6 +34,7 @@ library: - HList exposed-modules: - CheckDir + - CheckMap - WriteRepo - Util - Types @@ -74,3 +75,5 @@ executables: - microlens - microlens-th - tomland + - lucid + - servant-lucid diff --git a/server/Main.hs b/server/Main.hs index 0fbc4b4..00b4689 100644 --- a/server/Main.hs +++ b/server/Main.hs @@ -22,14 +22,15 @@ import Network.Wai.Handler.Warp (run) import Servant (Application, Capture, Get, Handler, HasServer (ServerT), JSON, NoContent, Post, Proxy (Proxy), - ReqBody, ServerError (errBody), - err500, hoistServer, serve, - throwError, type (:<|>) (..), - type (:>)) + Raw, ReqBody, + ServerError (errBody), err500, + hoistServer, serve, throwError, + type (:<|>) (..), type (:>)) +import Servant.HTML.Lucid (HTML) +import Servant.Server.StaticFiles (serveDirectoryWebApp) import Server (Config (..), JobStatus, RemoteRef (..), State, defaultState, loadConfig) - {- Needed: - admin overview (perhaps on seperate port?) @@ -48,6 +49,10 @@ type API format = :<|> "status" :> Capture "jobid" UUID :> Get '[format] JobStatus :<|> "relint" :> Capture "jobid" UUID :> Get '[format] NoContent +type Routes = + "api" :> API JSON + :<|> "status" :> Capture "jobid" UUID :> Get '[HTML] JobStatus + :<|> Raw -- | API's implementation jsonAPI :: Config True -> MVar State -> ServerT (API JSON) App @@ -56,11 +61,17 @@ jsonAPI config state = :<|> statusImpl state :<|> relintImpl config state +server :: Config True -> MVar State -> ServerT Routes App +server config state = + jsonAPI config state + :<|> statusImpl state + :<|> serveDirectoryWebApp "./static" + -- | make an application; convert any cli errors into a 500 app :: Config True -> MVar State -> Application app config = - serve api . hoistServer api conv . jsonAPI config - where api = Proxy @(API JSON) + serve api . hoistServer api conv . server config + where api = Proxy @Routes conv :: App a -> Handler a conv m = do config <- liftIO $ mkDefaultCliConfig [] diff --git a/server/Orphans.hs b/server/Orphans.hs new file mode 100644 index 0000000..b46f728 --- /dev/null +++ b/server/Orphans.hs @@ -0,0 +1,57 @@ + +{-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE RecordWildCards #-} + + +module Orphans where + + +import Control.Monad (forM_, unless) +import qualified Data.Map as M +import Data.Text (Text) +import Lucid (ToHtml) +import Lucid.Base (ToHtml (toHtml)) +import Lucid.Html5 + +import CheckDir +import CheckMap +import Types +import Util (prettyprint) + +instance ToHtml Hint where + toHtml (Hint l m) = do + span_ [class_ "level"] $ toHtml (show l) + toHtml m + + +instance ToHtml DirResult where + toHtml res@DirResult { .. } = do + h3_ $ toHtml (show $ maximumLintLevel res) + unless (null dirresultMissingAssets && null dirresultDeps) $ do + h2_ "Dependencies" + ul_ $ do + forM_ dirresultMissingAssets $ \(MissingAsset missing) -> do + li_ $ toHtml (prettyprint missing) + forM_ dirresultDeps $ \missing -> do + li_ $ toHtml (prettyprint missing) + unless (null dirresultMaps) $ do + h2_ "Maps" + flip M.foldMapWithKey dirresultMaps $ \name MapResult { .. } -> do + h3_ (toHtml name) + ul_ $ do + forM_ mapresultGeneral $ \lint -> + li_ (toHtml lint) + flip M.foldMapWithKey mapresultLayer $ \lint layers -> + li_ $ do + toHtml lint + toHtml ("(in layer" :: Text) + forM_ layers $ \layer -> + span_ [class_ "layer"] (toHtml layer) + toHtml (")" :: Text) + flip M.foldMapWithKey mapresultTileset $ \lint tilesets -> + li_ $ do + toHtml lint + toHtml ("( in layer" :: Text) + forM_ tilesets $ \tileset -> + span_ [class_ "tileset"] (toHtml tileset) + toHtml (")" :: Text) diff --git a/server/Server.hs b/server/Server.hs index a5a820a..536350f 100644 --- a/server/Server.hs +++ b/server/Server.hs @@ -27,12 +27,14 @@ import GHC.Generics (Generic) import Lens.Micro (over) import Lens.Micro.TH import LintConfig (LintConfig') +import Lucid (ToHtml (..)) +import Lucid.Html5 +import Orphans () import System.Exit.Compat (exitFailure) import Toml (TomlCodec) import qualified Toml import Toml.Codec ((.=)) - -- | a reference in a remote git repository data RemoteRef = RemoteRef { repourl :: Text @@ -69,6 +71,23 @@ data State = State , _registry :: Map UUID RemoteRef } +instance ToHtml JobStatus where + toHtml status = html_ $ do + head_ $ do + title_ "Job Status" + link_ [rel_ "stylesheet", type_ "text/css", href_ "/styles.css"] + body_ $ div_ [class_ "main-content"] $ case status of + Pending -> do + h2_ "Pending …" + p_ "(please note that this site won't auto-reload, you'll have to refresh it yourself)" + Linted res -> do + p_ "Linted" + toHtml res + Failed err -> do + h2_ "System Error" + p_ $ "error: " <> toHtml err + p_ "you should probably ping an admin about this or sth" + makeLenses ''State defaultState :: State diff --git a/stack.yaml b/stack.yaml index 738b3ad..428eea3 100644 --- a/stack.yaml +++ b/stack.yaml @@ -27,7 +27,7 @@ extra-deps: - logging-effect-1.3.12@sha256:72d168dd09887649ba9501627219b6027cbec2d5541931555b7885b133785ce3,1679 - which-0.2@sha256:db82ca7d83d64cce8ad579756f02d27c5bd289806ee02474726f7fafb87318e8,858 - cli-git-0.1.0.2@sha256:4e62e6b7357e4fe698df8b58ba53919f9d4a056e9617dbc00c869a365e316387,1122 - + - servant-lucid-0.9.0.4@sha256:698db96903a145fdef40cc897f8790728642af917c37b941a98b2da872b65f08,1787 allow-newer: true # use aeson with a non-hash-floodable implementation diff --git a/stack.yaml.lock b/stack.yaml.lock index a7bbaf3..93443e4 100644 --- a/stack.yaml.lock +++ b/stack.yaml.lock @@ -74,6 +74,13 @@ packages: sha256: 1e81c51e2b60db2b1784901cf0af33c67384f5412ad8edaad8a7068135f5217f original: hackage: cli-git-0.1.0.2@sha256:4e62e6b7357e4fe698df8b58ba53919f9d4a056e9617dbc00c869a365e316387,1122 +- completed: + hackage: servant-lucid-0.9.0.4@sha256:698db96903a145fdef40cc897f8790728642af917c37b941a98b2da872b65f08,1787 + pantry-tree: + size: 392 + sha256: 39e0e7b2b25980bfe4df036e89959188f9ef9e8c78c85e241fa9a682d1d78cf3 + original: + hackage: servant-lucid-0.9.0.4@sha256:698db96903a145fdef40cc897f8790728642af917c37b941a98b2da872b65f08,1787 snapshots: - completed: size: 586286 diff --git a/walint.cabal b/walint.cabal index b9982d1..1129e23 100644 --- a/walint.cabal +++ b/walint.cabal @@ -15,13 +15,13 @@ build-type: Simple library exposed-modules: CheckDir + CheckMap WriteRepo Util Types LintConfig other-modules: Badges - CheckMap Dirgraph KindLinter LayerData @@ -61,6 +61,7 @@ executable server main-is: Main.hs other-modules: Handlers + Orphans Server Paths_walint hs-source-dirs: @@ -79,11 +80,13 @@ executable server , filepath , http-media , logging-effect + , lucid , microlens , microlens-th , mtl , process , servant + , servant-lucid , servant-server , string-conversions , text -- cgit v1.2.3