mirror of
https://github.com/Dvorinka/Dash.git
synced 2026-10-29 00:01:24 +00:00
feat: phase 2 widgets — registry, fetchers, clock, config dialog
Backend: internal/widget registry (type metadata + Fetcher), Pi-hole v5 / AdGuard / Immich fetchers, /api/widgets/types + /api/widgets/:id/data with 30s TTL cache (failures cached too), kind+config on item create/patch. Config secrets are never logged or echoed in errors. Frontend: WidgetContent host maps config.type to a component, polls /data every 30s for server-backed types; clock renders client-side. Generic WidgetDialog builds its form from the registry's field list. Widget tiles are sortable items in both renderers. Generated with [Devin](https://devin.ai) Authored By: TDvorak <[email protected]> Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
6004105038
commit
8afc7df53b
21 files changed
+1072
-40
No files matched your search
@@ -0,0 +1,62 @@
|
||||
package widget
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Pi-hole v5 HTTP API: /admin/api.php?summaryRaw&auth=<token>.
|
||||
// jarvis: v5 only for now — v6 (/api/...) lands when someone runs it.
|
||||
type pihole struct{}
|
||||
|
||||
func init() { register(pihole{}) }
|
||||
|
||||
func (pihole) Meta() Type {
|
||||
return Type{
|
||||
Type: "pihole",
|
||||
Name: "Pi-hole",
|
||||
Description: "Queries and block rate",
|
||||
Fields: []Field{
|
||||
{Key: "endpoint", Label: "Endpoint", Placeholder: "http://pi.hole", Required: true},
|
||||
{Key: "token", Label: "API token", Secret: true, Placeholder: "web password / api token"},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type piholeData struct {
|
||||
QueriesToday int `json:"queriesToday"`
|
||||
BlockedToday int `json:"blockedToday"`
|
||||
BlockedPercent float64 `json:"blockedPercent"`
|
||||
GravitySize int `json:"gravitySize"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
|
||||
func (pihole) Fetch(ctx context.Context, cfg json.RawMessage) (any, error) {
|
||||
endpoint := strings.TrimRight(cfgStr(cfg, "endpoint"), "/")
|
||||
if endpoint == "" {
|
||||
return nil, fmt.Errorf("endpoint required")
|
||||
}
|
||||
u := endpoint + "/admin/api.php?summaryRaw"
|
||||
if tok := cfgStr(cfg, "token"); tok != "" {
|
||||
u += "&auth=" + tok
|
||||
}
|
||||
var raw struct {
|
||||
DNSQueriesToday int `json:"dns_queries_today"`
|
||||
AdsBlockedToday int `json:"ads_blocked_today"`
|
||||
AdsPercentToday float64 `json:"ads_percentage_today"`
|
||||
DomainsBlocked int `json:"domains_being_blocked"`
|
||||
Status string `json:"status"`
|
||||
}
|
||||
if err := getJSON(ctx, u, nil, &raw); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return piholeData{
|
||||
QueriesToday: raw.DNSQueriesToday,
|
||||
BlockedToday: raw.AdsBlockedToday,
|
||||
BlockedPercent: raw.AdsPercentToday,
|
||||
GravitySize: raw.DomainsBlocked,
|
||||
Status: raw.Status,
|
||||
}, nil
|
||||
}
|
||||
Reference in new issue
Block a user