module Web.View.Widgets.Show where
import Web.Types
import Generated.Types
import IHP.Prelude
import IHP.ViewPrelude
import Web.Routes ()
import Application.Helper.View (widgetEnvelope)
data ShowView = ShowView
{ widget :: !Widget
, hub :: !Hub
, versions :: ![WidgetVersion]
, events :: ![InteractionEvent]
, annotations :: ![Annotation]
, recentSignals :: ![OutcomeSignal]
, isRegressed :: !Bool
, cycleCount :: !Int
, mAdapterSpec :: !(Maybe WidgetAdapterSpec)
}
instance View ShowView where
html ShowView { .. } = [hsx|
Hubs
/
{hub.name}
/
{widget.name}
{renderCycleBanner cycleCount}
{if isRegressed then renderRegressionBanner else mempty}
{widgetEnvelope widget widgetHeader}
Total Events
{length events}
Annotations
{length annotations}
Versions
{length versions}
Annotations
{if length annotations >= 3 then renderDraftRequirementForm widget.id else mempty}
+ Add
{forEach rootAnnotations (renderAnnotation childrenOf)}
Annotation Breakdown
{forEach categoryBreakdown renderCategoryRow}
Interaction Events
| Event |
Actor |
Occurred |
{forEach events renderEventRow}
{renderSignalsSection recentSignals}
Version History
| Version |
Recorded |
{forEach versions renderVersionRow}
|]
where
widgetHeader = [hsx|
{widget.name}
{widget.widgetType}
{widget.policyScope}
{widget.status}
v{show widget.version}
{renderAdapterBadge mAdapterSpec}
Edit
|]
rootAnnotations = filter (\a -> isNothing a.parentId) annotations
childrenOf parent = filter (\a -> a.parentId == Just parent.id) annotations
categoryBreakdown =
[ (cat, length (filter (\a -> a.category == cat) annotations))
| cat <- ["friction","defect","wish","policy_concern","doc_gap","trust","other"]
, any (\a -> a.category == cat) annotations
]
renderAnnotation :: (Annotation -> [Annotation]) -> Annotation -> Html
renderAnnotation childrenOf a = [hsx|
{a.category}
{a.actorType}
{show a.createdAt}
{a.body}
{forEach (childrenOf a) (renderAnnotation childrenOf)}
|]
renderEventRow :: InteractionEvent -> Html
renderEventRow e = [hsx|
| {e.eventType} |
{e.actorType} |
{show e.occurredAt} |
|]
renderVersionRow :: WidgetVersion -> Html
renderVersionRow v = [hsx|
| v{show v.version} |
{show v.createdAt} |
|]
renderCategoryRow :: (Text, Int) -> Html
renderCategoryRow (cat, count) = [hsx|
{cat}
{show count}
|]
renderSignalRow :: OutcomeSignal -> Html
renderSignalRow sig = [hsx|
" text-xs px-2 py-0.5 rounded font-medium"}>
{sig.signalType}
{maybe mempty renderSignalValue sig.value}
{show sig.observedAt}
|]
signalTypeClass :: Text -> Text
signalTypeClass "improved" = "bg-green-100 text-green-800"
signalTypeClass "regressed" = "bg-red-100 text-red-800"
signalTypeClass "neutral" = "bg-gray-100 text-gray-600"
signalTypeClass "inconclusive" = "bg-yellow-100 text-yellow-800"
signalTypeClass _ = "bg-gray-100 text-gray-600"
renderCycleBanner :: Int -> Html
renderCycleBanner n | n >= 2 = [hsx|
⟳ {show n} cycles
Recurring friction — this widget has been through {show n} improvement cycles.
|]
renderCycleBanner _ = mempty
renderRegressionBanner :: Html
renderRegressionBanner = [hsx|
⚠ Regression detected
This widget had an improved signal but has since received high/critical annotations.
|]
renderDraftRequirementForm :: Id Widget -> Html
renderDraftRequirementForm wid = [hsx|
|]
renderSignalsSection :: [OutcomeSignal] -> Html
renderSignalsSection [] = mempty
renderSignalsSection sigs = [hsx|
Recent Outcome Signals
{forEach sigs renderSignalRow}
|]
renderSignalValue :: Double -> Html
renderSignalValue v = [hsx|{show v}|]
renderAdapterBadge :: Maybe WidgetAdapterSpec -> Html
renderAdapterBadge Nothing = mempty
renderAdapterBadge (Just s) = [hsx|
adapter: {s.name}
|]