diff --git a/src/Core/BuildStatuses.hs b/src/Core/BuildStatuses.hs
index afa19dc..a159448 100644
--- a/src/Core/BuildStatuses.hs
+++ b/src/Core/BuildStatuses.hs
@@ -26,6 +26,7 @@ module Core.BuildStatuses
ProjectNamespace (..),
ProjectNamespaceFullPath (..),
isHealthy,
+ isBroken,
toResult,
)
where
@@ -148,6 +149,21 @@ isHealthy Successful = True
isHealthy SuccessfulWithWarnings = False
isHealthy WaitingForResource = True
+isBroken :: BuildStatus -> Bool
+isBroken Unknown = True
+isBroken Cancelled = True
+isBroken Created = False
+isBroken Failed = True
+isBroken Manual = False
+isBroken Pending = False
+isBroken Preparing = False
+isBroken Running = False
+isBroken Scheduled = False
+isBroken Skipped = True
+isBroken Successful = False
+isBroken SuccessfulWithWarnings = True
+isBroken WaitingForResource = False
+
toResult :: Project -> Maybe (BuildStatus, Url Pipeline) -> Result
toResult Project {..} Nothing = Result projectId projectName (projectNamespaceFullPath projectNamespace) Unknown (Left projectWebUrl)
toResult Project {..} (Just (status, url)) = Result projectId projectName (projectNamespaceFullPath projectNamespace) status (Right url)
diff --git a/src/Ports/Inbound/HTTP/BuildStatuses/Html.hs b/src/Ports/Inbound/HTTP/BuildStatuses/Html.hs
index ed55a60..149fae9 100644
--- a/src/Ports/Inbound/HTTP/BuildStatuses/Html.hs
+++ b/src/Ports/Inbound/HTTP/BuildStatuses/Html.hs
@@ -30,13 +30,14 @@ import Relude
import Servant
import Servant.HTML.Lucid
-type API = "statuses" :> QueryParam "view" ViewMode :> QueryFlag "norefresh" :> QueryParam "filter" FilterMode :> Get '[HTML] (Html ())
+type API = "statuses" :> QueryParam "view" ViewMode :> QueryFlag "norefresh" :> QueryParam "filter" FilterMode :> QueryParam "ui" UiMode :> Get '[HTML] (Html ())
type Frontend = HtmlT (Reader FrontendState) ()
data FrontendState = FrontendState
{ frontendStateViewMode :: ViewMode,
frontendStateFilterMode :: FilterMode,
+ frontendStateUiMode :: UiMode,
frontendStateJobsView :: JobsView,
frontendStateBuildStatuses :: BuildStatuses,
frontendStateDataUpdateInterval :: DataUpdateIntervalSeconds,
@@ -56,10 +57,11 @@ template ::
) =>
ViewMode ->
FilterMode ->
+ UiMode ->
AutoRefresh ->
Sem r (Html ())
-template viewMode filterMode autoRefresh = do
- frontendState <- FrontendState viewMode filterMode <$> R.ask <*> getStatuses <*> R.ask <*> R.ask <*> pure autoRefresh <*> R.ask <*> Time.now
+template viewMode filterMode uiMode autoRefresh = do
+ frontendState <- FrontendState viewMode filterMode uiMode <$> R.ask <*> getStatuses <*> R.ask <*> R.ask <*> pure autoRefresh <*> R.ask <*> Time.now
pure $ usingReader frontendState $ commuteHtmlT $ do
pageHeader
pageBody
@@ -102,10 +104,11 @@ pageBody = body_ $ do
ShowAll -> buildStatuses
DontShowSuccessful -> filterResults buildStatuses (\res -> buildStatus res /= Successful)
(if viewMode == Plain then section_ [class_ "statuses"] else Relude.id) $ statusesToHtml viewMode dataUpdateInterval now buildStatusesFiltered
- section_ [class_ "statuses"] $ do
+ section_ [classes_ ["statuses", "controls"]] $ do
linkToViewToggle
linkToAutoRefreshToggle
linkToFilterModeToggle
+ linkToUiModeToggle
linkToJobs
statusesToHtml :: ViewMode -> DataUpdateIntervalSeconds -> UTCTime -> BuildStatuses -> Frontend
@@ -123,9 +126,17 @@ statusesToHtml Plain dataUpdateInterval now (Statuses (lastUpdated, results)) =
traverse_ resultToHtml results
lastUpdatedToHtml dataUpdateInterval now lastUpdated
-resultToHtml :: (Monad m) => Result -> HtmlT m ()
-resultToHtml Result {..} =
- a_ [href_ (either show show url), target_ "_blank", classesForStatus buildStatus, title_ (buildStatusToString buildStatus)] $ div_ (toHtml name)
+resultToHtml :: Result -> Frontend
+resultToHtml result = do
+ uiMode <- asks frontendStateUiMode
+ case uiMode of
+ Colored -> resultToHtml' result
+ NoColor -> resultToHtml'' result
+
+resultToHtml' :: (Monad m) => Result -> HtmlT m ()
+resultToHtml' Result {..} =
+ a_ [href_ (either show show url), target_ "_blank", classesForStatus buildStatus, title_ (buildStatusToString buildStatus)] $ do
+ div_ [class_ "status-content"] $ p_ (toHtml name)
where
classesForStatus Unknown = class_ "status unknown"
classesForStatus Cancelled = class_ "status cancelled"
@@ -141,19 +152,34 @@ resultToHtml Result {..} =
classesForStatus SuccessfulWithWarnings = class_ "status passed-with-warnings"
classesForStatus WaitingForResource = class_ "status waiting-for-resource"
- buildStatusToString Unknown = "unknown"
- buildStatusToString Cancelled = "cancelled"
- buildStatusToString Created = "created"
- buildStatusToString Failed = "failed"
- buildStatusToString Manual = "manual"
- buildStatusToString Pending = "pending"
- buildStatusToString Preparing = "preparing"
- buildStatusToString Running = "running"
- buildStatusToString Scheduled = "scheduled"
- buildStatusToString Skipped = "skipped"
- buildStatusToString Successful = "successful"
- buildStatusToString SuccessfulWithWarnings = "successful with warnings"
- buildStatusToString WaitingForResource = "waiting for resource"
+resultToHtml'' :: (Monad m) => Result -> HtmlT m ()
+resultToHtml'' Result {..} =
+ a_ [href_ (either show show url), target_ "_blank", classes_ ["status", "no-color"], title_ (buildStatusToString buildStatus), style_ "position: relative"] $ do
+ div_ [class_ "status-content"] $ do
+ p_ (toHtml name)
+ p_ [class_ "textual-status"] (buildStatusToString buildStatus)
+ section_ [class_ "icon-box", style_ "position: absolute; height: 100%; width: 100%; display: grid; grid-template-columns: repeat(4, 1fr); grid-auto-rows: 48px;"] $ do
+ if isBroken buildStatus
+ then replicateM_ 16 (toHtmlRaw ("" :: String))
+ else pure ()
+ if isHealthy buildStatus
+ then replicateM_ 16 (toHtmlRaw ("" :: String))
+ else pure ()
+
+buildStatusToString :: (IsString a) => BuildStatus -> a
+buildStatusToString Unknown = "unknown"
+buildStatusToString Cancelled = "cancelled"
+buildStatusToString Created = "created"
+buildStatusToString Failed = "failed"
+buildStatusToString Manual = "manual"
+buildStatusToString Pending = "pending"
+buildStatusToString Preparing = "preparing"
+buildStatusToString Running = "running"
+buildStatusToString Scheduled = "scheduled"
+buildStatusToString Skipped = "skipped"
+buildStatusToString Successful = "successful"
+buildStatusToString SuccessfulWithWarnings = "successful with warnings"
+buildStatusToString WaitingForResource = "waiting for resource"
emptyResults :: Frontend
emptyResults = do
@@ -203,5 +229,16 @@ linkToFilterModeToggle = do
DontShowSuccessful -> "Show all pipelines"
div_ [class_ "status"] $ div_ $ a_ [class_ "link-control", href_ (toUrlPiece (linkForState (frontendState {frontendStateFilterMode = toggle filterMode})))] txt
+linkToUiModeToggle :: Frontend
+linkToUiModeToggle = do
+ frontendState <- ask
+ let uiMode = frontendStateUiMode frontendState
+ toggle Colored = NoColor
+ toggle NoColor = Colored
+ txt = case uiMode of
+ Colored -> "Switch to accessibility mode"
+ NoColor -> "Switch to colored mode"
+ div_ [class_ "status"] $ div_ $ a_ [class_ "link-control", href_ (toUrlPiece (linkForState (frontendState {frontendStateUiMode = toggle uiMode})))] txt
+
linkForState :: FrontendState -> Link
-linkForState frontendState = safeLink (Proxy @API) (Proxy @API) (Just (frontendStateViewMode frontendState)) (frontendStateAutoRefresh frontendState == NoRefresh) (Just (frontendStateFilterMode frontendState))
+linkForState frontendState = safeLink (Proxy @API) (Proxy @API) (Just (frontendStateViewMode frontendState)) (frontendStateAutoRefresh frontendState == NoRefresh) (Just (frontendStateFilterMode frontendState)) (Just (frontendStateUiMode frontendState))
diff --git a/src/Ports/Inbound/HTTP/Server.hs b/src/Ports/Inbound/HTTP/Server.hs
index 9efbeb2..75c9dc1 100644
--- a/src/Ports/Inbound/HTTP/Server.hs
+++ b/src/Ports/Inbound/HTTP/Server.hs
@@ -48,7 +48,7 @@ server = s :<|> s
where
s =
getCurrentHealthStatus
- :<|> (\mvm b mfm -> BuildStatuses.template (fromMaybe Plain mvm) (fromMaybe ShowAll mfm) (norefreshFlag b))
+ :<|> (\mvm b mfm mum -> BuildStatuses.template (fromMaybe Plain mvm) (fromMaybe ShowAll mfm) (fromMaybe Colored mum) (norefreshFlag b))
:<|> (Runners.template . norefreshFlag)
:<|> serveDirectoryWebApp "/service/static"
diff --git a/src/Ports/Inbound/HTTP/Util.hs b/src/Ports/Inbound/HTTP/Util.hs
index d05b2ed..d2db85b 100644
--- a/src/Ports/Inbound/HTTP/Util.hs
+++ b/src/Ports/Inbound/HTTP/Util.hs
@@ -1,7 +1,7 @@
{-# LANGUAGE OverloadedStrings #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
-module Ports.Inbound.HTTP.Util (AutoRefresh (..), ViewMode (..), FilterMode (..), lastUpdatedToHtml) where
+module Ports.Inbound.HTTP.Util (AutoRefresh (..), ViewMode (..), FilterMode (..), UiMode (..), lastUpdatedToHtml) where
import Core.Shared
import Data.Time (UTCTime, diffUTCTime)
@@ -42,6 +42,18 @@ instance ToHtml (Id a) where
deriving newtype instance ToHtml (Name a)
+data UiMode = Colored | NoColor deriving stock (Bounded, Eq, Enum)
+
+uiModeToText :: UiMode -> Text
+uiModeToText Colored = "colored"
+uiModeToText NoColor = "no-color"
+
+instance FromHttpApiData UiMode where
+ parseQueryParam = maybeToRight "can't parse UiMode param" . inverseMap uiModeToText
+
+instance ToHttpApiData UiMode where
+ toQueryParam = uiModeToText
+
lastUpdatedToHtml :: (Monad m) => DataUpdateIntervalSeconds -> UTCTime -> UTCTime -> HtmlT m ()
lastUpdatedToHtml (DataUpdateIntervalSeconds updateInterval) now lastUpdate = div_ ([class_ classes] <> staleDataTitle) $ div_ $ do
p_ "Last Update at:"
diff --git a/static/statuses-11c70488b8.css b/static/statuses-11c70488b8.css
index 73bd76d..b010294 100644
--- a/static/statuses-11c70488b8.css
+++ b/static/statuses-11c70488b8.css
@@ -6,6 +6,21 @@ a {
color: black;
}
+a.status > div > p:first-child {
+ margin-bottom: 0;
+}
+
+p.textual-status {
+ font-weight: normal;
+ font-size: smaller;
+ margin-top: 0;
+}
+
+a.no-color > div {
+ background-color: white;
+ padding: 5px;
+}
+
html {
height: 100%;
font-family: 'Noto Sans', sans-serif;
@@ -24,6 +39,10 @@ body {
display: grid;
}
+.status.no-color {
+ border: 1px solid white;
+}
+
.status::before {
content: "";
padding-bottom: 60%;
@@ -76,6 +95,10 @@ a.link-to-jobs, a.link-control {
background-color: #8936b2;
}
+.unknown {
+ background-color: white;
+}
+
.statuses {
width: 100%;
display: grid;
@@ -93,4 +116,21 @@ a.link-to-jobs, a.link-control {
grid-auto-rows: 1fr;
grid-template-columns: repeat(auto-fill, minmax(11em, 10fr));
margin-bottom: 0.4em
-}
\ No newline at end of file
+}
+
+.icon-box {
+ overflow-y: hidden;
+}
+
+.controls {
+ padding-top: 8px;
+}
+
+.status-content {
+ z-index: 1;
+}
+
+.status-content > p {
+ margin-top: 0;
+ margin-bottom: 0;
+}