diff --git a/knotmirror/adminpage.go b/knotmirror/adminpage.go
index 7db562e1..6fa3d477 100644
--- a/knotmirror/adminpage.go
+++ b/knotmirror/adminpage.go
@@ -15,6 +15,7 @@ import (
"github.com/bluesky-social/indigo/atproto/syntax"
"github.com/go-chi/chi/v5"
"tangled.org/core/appview/pagination"
+ "tangled.org/core/idresolver"
"tangled.org/core/knotmirror/db"
"tangled.org/core/knotmirror/models"
"tangled.org/core/knotmirror/xrpc"
@@ -30,14 +31,16 @@ type AdminServer struct {
resyncer *Resyncer
xrpc *xrpc.Xrpc
logger *slog.Logger
+ resolver *idresolver.Resolver
}
-func NewAdminServer(l *slog.Logger, database *sql.DB, resyncer *Resyncer, x *xrpc.Xrpc) *AdminServer {
+func NewAdminServer(l *slog.Logger, database *sql.DB, resyncer *Resyncer, x *xrpc.Xrpc, resolver *idresolver.Resolver) *AdminServer {
return &AdminServer{
db: database,
resyncer: resyncer,
xrpc: x,
logger: l,
+ resolver: resolver,
}
}
@@ -103,13 +106,30 @@ func (s *AdminServer) handleRepos() http.HandlerFunc {
}
var (
- did = r.URL.Query().Get("did")
- knot = r.URL.Query().Get("knot")
- state = r.URL.Query().Get("state")
+ didInput = r.URL.Query().Get("did")
+ knot = r.URL.Query().Get("knot")
+ state = r.URL.Query().Get("state")
name = r.URL.Query().Get("name")
)
- repos, err := db.ListRepos(r.Context(), s.db, page, did, knot, state)
+ did := didInput
+ if didInput != "" {
+ if _, err := syntax.ParseDID(didInput); err != nil {
+ // treat as a handle and resolve to DID
+ handle, herr := syntax.ParseHandle(didInput)
+ if herr != nil {
+ http.Error(w, fmt.Sprintf("invalid DID or handle: %s", didInput), http.StatusBadRequest)
+ return
+ }
+ resolved, rerr := s.resolver.ResolveHandle(r.Context(), handle.Normalize())
+ if rerr != nil {
+ http.Error(w, fmt.Sprintf("could not resolve handle %q: %s", didInput, rerr), http.StatusBadRequest)
+ return
+ }
+ did = resolved.String()
+ }
+ }
+
repos, err := db.ListRepos(r.Context(), s.db, page, did, knot, state, name)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
diff --git a/knotmirror/knotmirror.go b/knotmirror/knotmirror.go
index 567396ba..6c004c98 100644
--- a/knotmirror/knotmirror.go
+++ b/knotmirror/knotmirror.go
@@ -33,7 +33,11 @@ func Run(ctx context.Context, cfg *config.Config) error {
rdb := redis.NewClient(&redis.Options{Addr: cfg.RedisAddr})
- resolver := idresolver.DefaultResolver(cfg.PlcUrl)
+ resolver, err := idresolver.RedisResolver("redis://"+cfg.RedisAddr, cfg.PlcUrl)
+ if err != nil {
+ logger.Error("failed to create redis resolver for admin, falling back to default", "err", err)
+ resolver = idresolver.DefaultResolver(cfg.PlcUrl)
+ }
// NOTE: using plain git-cli for clone/fetch as go-git is too memory-intensive.
gitm := NewCliGitMirrorManager(cfg.GitRepoBasePath, cfg.KnotUseSSL)
@@ -56,7 +60,7 @@ func Run(ctx context.Context, cfg *config.Config) error {
crawler := NewCrawler(logger, db)
resyncer := NewResyncer(logger, db, gitm, cfg)
xrpc := xrpc.New(logger, cfg, db, rdb, resolver, knotstream)
- adminpage := NewAdminServer(logger, db, resyncer, xrpc)
+ adminpage := NewAdminServer(logger, db, resyncer, xrpc, resolver)
// maintain repository list with tap
// NOTE: this can be removed once we introduce did-for-repo because then we can just listen to KnotStream for #identity events.
diff --git a/knotmirror/templates/repos.html b/knotmirror/templates/repos.html
index 83e1f707..9fb3ebef 100644
--- a/knotmirror/templates/repos.html
+++ b/knotmirror/templates/repos.html
@@ -10,7 +10,7 @@
hx-swap="outerHTML"
hx-trigger="input delay:300ms from:input, change from:select, every 10s"
>
-
+