{-# LANGUAGE BlockArguments #-} {-# LANGUAGE DerivingStrategies #-} {-# LANGUAGE DuplicateRecordFields #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE InstanceSigs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedRecordDot #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE NoImplicitPrelude #-} {-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -Wno-partial-fields #-} module Language.EO.Phi.Report.Html where import Data.FileEmbed (embedFileRelative) import Data.List (intercalate) import Data.Maybe (fromMaybe) import Data.String.Interpolate import Data.Text qualified as T import Data.Text.Encoding qualified as T import Language.EO.Phi.Metrics.Data (Metrics (..), MetricsCount, SafeNumber (..), toListMetrics) import Language.EO.Phi.Report.Data (MetricsChange, MetricsChangeCategorized, MetricsChangeCategory (..), Percent (..), ProgramReport (..), Report (..), ReportRow (..)) import Text.Blaze.Html.Renderer.String (renderHtml) import Text.Blaze.Html5 hiding (i) import Text.Blaze.Html5.Attributes (class_, colspan, id, onclick, type_, value) import Text.Printf (printf) import Prelude hiding (div, id, span) -- | JavaScript file to embed into HTML reports reportJS :: String reportJS = T.unpack $ T.decodeUtf8 $(embedFileRelative "report/main.js") -- | CSS file to embed into HTML reports reportCSS :: String reportCSS = T.unpack $ T.decodeUtf8 $(embedFileRelative "report/styles.css") metricsNames :: Metrics String metricsNames = Metrics { dataless = "Dataless formations" , applications = "Applications" , formations = "Formations" , dispatches = "Dispatches" } toHtmlReportHeader :: Html toHtmlReportHeader = thead $ toHtml [ tr $ toHtml [ th ! colspan "2" ! class_ "no-sort" $ "Attribute" , th ! colspan "4" ! class_ "no-sort" $ "Improvement = (Initial - Normalized) / Initial" , th ! colspan "4" ! class_ "no-sort" $ "Initial" , th ! colspan "4" ! class_ "no-sort" $ "Normalized" , th ! colspan "4" ! class_ "no-sort" $ "Location" ] , tr . toHtml $ th <$> [ "Attribute Initial" , "Attribute Normalized" ] <> ( concat . replicate 3 . (toHtml <$>) $ toListMetrics metricsNames ) <> [ "File Initial" , "Bindings Path Initial" , "File Normalized" , "Bindings Path Normalized" ] ] data ReportFormat = ReportFormat'Html { css :: String , js :: String } | -- | GitHub Flavored Markdown ReportFormat'Markdown deriving stock (Eq) data ReportConfig = ReportConfig { expectedMetricsChange :: MetricsChange , format :: ReportFormat } instance (ToMarkup a) => ToMarkup (SafeNumber a) where toMarkup :: SafeNumber a -> Markup toMarkup (SafeNumber'Number n) = toMarkup n toMarkup SafeNumber'NaN = toMarkup ("NaN" :: String) roundToStr :: Int -> Double -> String roundToStr = printf "%0.*f%%" instance ToMarkup Percent where toMarkup :: Percent -> Markup toMarkup Percent{..} = toMarkup $ roundToStr 2 (percent * 100) -- >>> import Text.Blaze.Html.Renderer.String (renderHtml) -- >>> reportConfig = ReportConfig { expectedMetricsChange = 0, format = ReportFormat'Markdown } -- -- >>> renderHtml $ toHtmlChange reportConfig (MetricsChange'Bad 0.2) -- "