ide/providers.go
Snider b9500bf866
Some checks failed
Security Scan / security (push) Successful in 9s
Test / test (push) Failing after 52s
feat(frontend): wire app shell framework with dynamic providers
Replace the standalone IDE/Tray components with the framework shell from
core/gui/ui. The IDE frontend is now minimal routing config that uses:

- ApplicationFrameComponent as the HLCRF layout (header, sidebar, content, footer)
- ProviderHostComponent for dynamic custom element rendering via :provider route
- SystemTrayFrameComponent for the 380x480 tray panel

Go side: add GET /api/v1/providers endpoint (ProvidersAPI) that returns all
registered providers from the Registry plus runtime providers from the
RuntimeManager. The Angular frontend calls this on startup to populate
navigation and load custom elements.

Also bumps @angular/build and @angular/cli to 21.x to match @angular/core.

Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-14 12:41:55 +00:00

98 lines
2.4 KiB
Go

// SPDX-Licence-Identifier: EUPL-1.2
package main
import (
"net/http"
"forge.lthn.ai/core/api/pkg/provider"
"github.com/gin-gonic/gin"
)
// ProvidersAPI exposes registered provider information via GET /api/v1/providers.
// The Angular frontend uses this endpoint to discover providers and load their
// custom elements dynamically.
type ProvidersAPI struct {
registry *provider.Registry
runtime *RuntimeManager
}
func NewProvidersAPI(reg *provider.Registry, rm *RuntimeManager) *ProvidersAPI {
return &ProvidersAPI{registry: reg, runtime: rm}
}
func (p *ProvidersAPI) Name() string { return "providers-api" }
func (p *ProvidersAPI) BasePath() string { return "/api/v1/providers" }
func (p *ProvidersAPI) RegisterRoutes(rg *gin.RouterGroup) {
rg.GET("", p.list)
}
// list godoc
//
// @Summary List registered providers
// @Description Returns all registered providers with their capabilities
// @Tags providers
// @Produce json
// @Success 200 {object} providersResponse
// @Router /api/v1/providers [get]
func (p *ProvidersAPI) list(c *gin.Context) {
registryInfo := p.registry.Info()
runtimeInfo := p.runtime.List()
// Merge runtime provider info with registry info
providers := make([]providerDTO, 0, len(registryInfo)+len(runtimeInfo))
for _, info := range registryInfo {
dto := providerDTO{
Name: info.Name,
BasePath: info.BasePath,
Channels: info.Channels,
Status: "active",
}
if info.Element != nil {
dto.Element = &elementDTO{
Tag: info.Element.Tag,
Source: info.Element.Source,
}
}
providers = append(providers, dto)
}
// Add runtime providers not already in registry
for _, ri := range runtimeInfo {
found := false
for _, p := range providers {
if p.Name == ri.Code {
found = true
break
}
}
if !found {
providers = append(providers, providerDTO{
Name: ri.Code,
BasePath: ri.Namespace,
Status: "active",
})
}
}
c.JSON(http.StatusOK, providersResponse{Providers: providers})
}
type providersResponse struct {
Providers []providerDTO `json:"providers"`
}
type providerDTO struct {
Name string `json:"name"`
BasePath string `json:"basePath"`
Status string `json:"status,omitempty"`
Element *elementDTO `json:"element,omitempty"`
Channels []string `json:"channels,omitempty"`
}
type elementDTO struct {
Tag string `json:"tag"`
Source string `json:"source"`
}