Files
inter-hub/Web/Controller/MarketplaceDashboard.hs
Bernd Worsch 2c22766cd6 fix(WP-0017/E5): Layer 3 error fixes — round 3 (24 files)
Int16→Int in score/stars functions; uuid-based readMay→UUID.fromText;
autoRefresh do-notation fix; id→\x->x ambiguity in HubRoutingRules;
MarketplaceDashboard replaced raw SQL with IHP query builder; optional
hub selector in TypeRegistry views via CanSelect (Text, Maybe Id) instance
added to Web.View.Prelude; import consolidations to Web.View.Prelude.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-12 13:11:32 +00:00

64 lines
2.4 KiB
Haskell

module Web.Controller.MarketplaceDashboard where
import Web.Types
import Web.View.MarketplaceDashboard.Show
import Generated.Types
import IHP.Prelude
import IHP.ControllerPrelude
instance Controller MarketplaceDashboardController where
beforeAction = ensureIsUser
action MarketplaceDashboardAction = autoRefresh do
let mSearch = paramOrNothing @Text "q"
let mWType = paramOrNothing @Text "widgetType"
let sortBy = paramOrDefault @Text "adopted" "sort"
-- Widget patterns: fetch then count adoptions
basePatterns <- query @WidgetPattern
|> filterWhere (#isPublished, True)
|> orderByAsc #name
|> limit 50
|> fetch
patterns <- mapM (\p -> do
cnt <- sqlQueryScalar
"SELECT COUNT(*) FROM pattern_adoptions WHERE widget_pattern_id = ?"
(Only p.id)
pure (p, fromMaybe 0 cnt)) basePatterns
-- Governance templates: fetch then count clones
baseTemplates <- query @GovernanceTemplate
|> filterWhere (#isPublished, True)
|> limit 50
|> fetch
templates <- mapM (\t -> do
cnt <- sqlQueryScalar
"SELECT COUNT(*) FROM governance_template_clones WHERE governance_template_id = ?"
(Only t.id)
pure (t, fromMaybe 0 cnt)) baseTemplates
-- Trending patterns (most adoptions in last 30 days)
trendingRaw :: [(Id WidgetPattern, Text, Text, Int)] <- sqlQuery
"SELECT wp.id, wp.name, wp.widget_type, CAST(COUNT(pa.id) AS integer) AS recent_adoptions \
\ FROM widget_patterns wp \
\ JOIN pattern_adoptions pa ON pa.widget_pattern_id = wp.id \
\ WHERE wp.is_published = TRUE \
\ AND pa.adopted_at >= NOW() - INTERVAL '30 days' \
\ GROUP BY wp.id, wp.name, wp.widget_type \
\ ORDER BY recent_adoptions DESC \
\ LIMIT 5"
()
let trending = trendingRaw
widgetTypeOptions <- sqlQuery
"SELECT name, label FROM widget_type_registry WHERE status = 'active' ORDER BY label"
()
render ShowView
{ patterns, templates, trending
, widgetTypeOptions
, searchQuery = mSearch
, selectedType = mWType
, sortOrder = sortBy
}