module Web.Controller.HubRegistry where -- Hub Registry: browsable view over hub_capability_manifests + hub_health_snapshots + hubs -- No HubRegistry table — this is a view over existing Phase 9 data. import Web.Types import Web.View.HubRegistry.Index import Web.View.HubRegistry.Show import Generated.Types import IHP.Prelude import IHP.ControllerPrelude instance Controller HubRegistryController where beforeAction = ensureIsUser action HubRegistryAction = autoRefresh do hubs <- query @Hub |> orderByAsc #name |> fetch registryRows <- mapM buildRow hubs render IndexView { registryRows } action ShowHubRegistryAction { hubId } = do hub <- fetch hubId mManifest <- query @HubCapabilityManifest |> filterWhere (#hubId, hubId) |> filterWhere (#status, "active") |> fetchOneOrNothing healthHistory <- query @HubHealthSnapshot |> filterWhere (#hubId, hubId) |> orderByDesc #computedAt |> limit 10 |> fetch adoptedPatterns <- sqlQuery "SELECT wp.id, wp.name, wp.widget_type, wp.hub_id, \ \ pa.id AS adoption_id, pa.is_version_pinned, pa.adopted_at \ \ FROM pattern_adoptions pa \ \ JOIN widget_patterns wp ON wp.id = pa.widget_pattern_id \ \ WHERE pa.adopting_hub_id = ? \ \ ORDER BY pa.adopted_at DESC" (Only hubId) render ShowView { hub, mManifest, healthHistory, adoptedPatterns } -- | Build a HubRegistryRow for a hub by fetching its active manifest and latest snapshot. buildRow :: (?modelContext :: ModelContext) => Hub -> IO HubRegistryRow buildRow hub = do mManifest <- query @HubCapabilityManifest |> filterWhere (#hubId, hub.id) |> filterWhere (#status, "active") |> fetchOneOrNothing mLatestSnapshot <- query @HubHealthSnapshot |> filterWhere (#hubId, hub.id) |> orderByDesc #computedAt |> limit 1 |> fetchOneOrNothing pure HubRegistryRow { hub, mManifest, mLatestSnapshot }