module Web.View.LearningDashboard.Show where import Web.View.Prelude import Data.Time (diffUTCTime, getCurrentTime, nominalDay) data ShowView = ShowView { topCorrelations :: ![OutcomeCorrelation] , patternRankings :: ![PatternPerformanceRecord] , thresholdStatus :: ![(Hub, Maybe AdaptiveThresholdConfig)] , recentInsights :: ![LearningInsight] , knowledgeHighlights :: ![InstitutionalKnowledgeEntry] } instance View ShowView where html ShowView { .. } = [hsx|

Learning Dashboard

{-- Panel 1: Top annotation predictors --}

Top Annotation Predictors

{renderCorrelationsSection topCorrelations}
{-- Panel 2: Pattern performance ranking --}

Pattern Performance Ranking

{renderPatternRankingsSection patternRankings}
{-- Panel 3: Adaptive threshold status --}

Adaptive Threshold Status

{forM_ thresholdStatus renderThresholdStatus}
{-- Panel 4: Recent learning insights --}

Recent Insights

{renderInsightsSection recentInsights}
{-- Panel 5: Knowledge base highlights --}

Knowledge Highlights

{renderKnowledgeSection knowledgeHighlights}
|] renderCorrelationsSection :: [OutcomeCorrelation] -> Html renderCorrelationsSection [] = [hsx|

No data — run correlation analysis per hub.

|] renderCorrelationsSection cs = [hsx|
{forEach cs renderCorrelation}
|] renderPatternRankingsSection :: [PatternPerformanceRecord] -> Html renderPatternRankingsSection [] = [hsx|

No data — run pattern performance per hub.

|] renderPatternRankingsSection rs = [hsx|
{forEach rs renderPatternRank}
|] renderInsightsSection :: [LearningInsight] -> Html renderInsightsSection [] = [hsx|

No insights yet.

|] renderInsightsSection is = [hsx|
{forEach is renderInsight}
|] renderKnowledgeSection :: [InstitutionalKnowledgeEntry] -> Html renderKnowledgeSection [] = [hsx|

No entries yet — distil a decision.

|] renderKnowledgeSection es = [hsx|
{forEach es renderKnowledge}
|] renderCorrelation :: OutcomeCorrelation -> Html renderCorrelation c = [hsx|
{c.annotationCategory}
show (round (c.correlationScore * 100) :: Int) <> "%"}>
{show (round (c.correlationScore * 100) :: Int)}%
|] barColor :: Double -> Text barColor s | s >= 0.7 = "h-2 rounded-full bg-green-500" | s >= 0.4 = "h-2 rounded-full bg-yellow-500" | otherwise = "h-2 rounded-full bg-red-400" renderPatternRank :: PatternPerformanceRecord -> Html renderPatternRank r = let rate = if r.totalOutcomeCount > 0 then fromIntegral r.positiveOutcomeCount / fromIntegral r.totalOutcomeCount :: Double else 0.0 in [hsx|
{maybe "-" show r.outcomeRank} {show r.widgetPatternId} {show (round (rate * 100) :: Int)}%
|] renderThresholdStatus :: (Hub, Maybe AdaptiveThresholdConfig) -> Html renderThresholdStatus (h, mCfg) = let driftClass = case mCfg of Nothing -> "text-red-500" :: Text Just _ -> "text-green-600" label = case mCfg of Nothing -> "Not calibrated" :: Text Just _ -> "Calibrated" in [hsx|
{h.name} {label}
|] renderInsight :: LearningInsight -> Html renderInsight i = [hsx|

{i.title}

{insightTypeBadge i.insightType}

|] insightTypeBadge :: Text -> Text insightTypeBadge t = case t of "annotation_predictor" -> "Annotation predictor" "threshold_calibration" -> "Threshold calibration" "pattern_ranking" -> "Pattern ranking" "routing_improvement" -> "Routing improvement" _ -> t renderKnowledge :: InstitutionalKnowledgeEntry -> Html renderKnowledge e = [hsx|
{take 80 e.summary <> if length e.summary > 80 then "…" else ""}
|]