Files
container-census/internal/plugins/builtin/graph/plugin.go
Self Hosters 2cf3b7c0d6 Fix module path and add build time display to UI
Backend changes:
- Updated go.mod module path from github.com/container-census to
  github.com/selfhosters-cc to match correct GitHub organization
- Updated all import paths across codebase to use new module name
- This fixes ldflags injection of BuildTime during compilation
- BuildTime now correctly shows in /api/health response

Frontend changes:
- Added build time badge next to version in header
- Shows date and time in compact format (e.g., "🔨 12/11/2025 8:06 PM")
- Hover shows full timestamp
- Only displays if build_time is not "unknown"

The build script already sets BuildTime via ldflags, but it was being
ignored because the module path in go.mod didn't match the ldflags path.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-11 20:12:10 -05:00

116 lines
2.5 KiB
Go

package graph
import (
"context"
_ "embed"
"net/http"
"github.com/selfhosters-cc/container-census/internal/plugins"
)
//go:embed frontend/bundle.js
var bundleJS []byte
//go:embed frontend/styles.css
var stylesCSS []byte
type GraphPlugin struct {
deps plugins.PluginDependencies
}
func NewGraphPlugin() *GraphPlugin {
return &GraphPlugin{}
}
func (p *GraphPlugin) Info() plugins.PluginInfo {
return plugins.PluginInfo{
ID: "graph-visualizer",
Name: "Graph Visualizer",
Version: "1.0.0",
Description: "Visualize container relationships using an interactive network graph",
Author: "Container Census Team",
BuiltIn: true,
}
}
func (p *GraphPlugin) Init(ctx context.Context, deps plugins.PluginDependencies) error {
p.deps = deps
return nil
}
func (p *GraphPlugin) Start(ctx context.Context) error {
p.deps.Logger.Info("Graph Visualizer plugin started")
return nil
}
func (p *GraphPlugin) Stop(ctx context.Context) error {
p.deps.Logger.Info("Graph Visualizer plugin stopped")
return nil
}
func (p *GraphPlugin) Routes() []plugins.Route {
return []plugins.Route{
{
Path: "/graph-data",
Method: "GET",
Handler: p.handleGraphData,
},
{
Path: "/bundle.js",
Method: "GET",
Handler: p.serveBundleJS,
},
{
Path: "/styles.css",
Method: "GET",
Handler: p.serveStylesCSS,
},
}
}
func (p *GraphPlugin) Tab() *plugins.TabDefinition {
return &plugins.TabDefinition{
ID: "graph",
Label: "Graph",
Icon: "🕸️",
Order: 15,
}
}
func (p *GraphPlugin) Badges() []plugins.BadgeProvider {
return nil
}
func (p *GraphPlugin) ContainerEnricher() plugins.ContainerEnricher {
return nil
}
func (p *GraphPlugin) Settings() *plugins.SettingsDefinition {
return nil
}
func (p *GraphPlugin) NotificationChannelFactory() plugins.ChannelFactory {
return nil
}
// serveBundleJS serves the embedded JavaScript bundle
func (p *GraphPlugin) serveBundleJS(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/javascript")
w.Header().Set("Cache-Control", "public, max-age=3600")
w.Write(bundleJS)
}
// serveStylesCSS serves the embedded CSS file
func (p *GraphPlugin) serveStylesCSS(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/css")
w.Header().Set("Cache-Control", "public, max-age=3600")
w.Write(stylesCSS)
}
// Register registers the graph plugin with the plugin manager
func Register(manager *plugins.Manager) {
manager.RegisterBuiltIn("graph-visualizer", func() plugins.Plugin {
return NewGraphPlugin()
})
}