Monorepo for Tangled tangled.org
9

Configure Feed

Select the types of activity you want to include in your feed.

knotmirror: allow did/handle input in repos filter

Signed-off-by: oppiliappan <me@oppi.li>

author
oppiliappan
committer
Tangled
date (May 15, 2026, 9:28 PM +0300) commit 2399588d parent 80487040 change-id rqwmtloo
+32 -8
+25 -5
knotmirror/adminpage.go
··· 15 15 "github.com/bluesky-social/indigo/atproto/syntax" 16 16 "github.com/go-chi/chi/v5" 17 17 "tangled.org/core/appview/pagination" 18 + "tangled.org/core/idresolver" 18 19 "tangled.org/core/knotmirror/db" 19 20 "tangled.org/core/knotmirror/models" 20 21 "tangled.org/core/knotmirror/xrpc" ··· 30 31 resyncer *Resyncer 31 32 xrpc *xrpc.Xrpc 32 33 logger *slog.Logger 34 + resolver *idresolver.Resolver 33 35 } 34 36 35 - func NewAdminServer(l *slog.Logger, database *sql.DB, resyncer *Resyncer, x *xrpc.Xrpc) *AdminServer { 37 + func NewAdminServer(l *slog.Logger, database *sql.DB, resyncer *Resyncer, x *xrpc.Xrpc, resolver *idresolver.Resolver) *AdminServer { 36 38 return &AdminServer{ 37 39 db: database, 38 40 resyncer: resyncer, 39 41 xrpc: x, 40 42 logger: l, 43 + resolver: resolver, 41 44 } 42 45 } 43 46 ··· 103 106 } 104 107 105 108 var ( 106 - did = r.URL.Query().Get("did") 107 - knot = r.URL.Query().Get("knot") 108 - state = r.URL.Query().Get("state") 109 + didInput = r.URL.Query().Get("did") 110 + knot = r.URL.Query().Get("knot") 111 + state = r.URL.Query().Get("state") 109 112 name = r.URL.Query().Get("name") 110 113 ) 111 114 112 - repos, err := db.ListRepos(r.Context(), s.db, page, did, knot, state) 115 + did := didInput 116 + if didInput != "" { 117 + if _, err := syntax.ParseDID(didInput); err != nil { 118 + // treat as a handle and resolve to DID 119 + handle, herr := syntax.ParseHandle(didInput) 120 + if herr != nil { 121 + http.Error(w, fmt.Sprintf("invalid DID or handle: %s", didInput), http.StatusBadRequest) 122 + return 123 + } 124 + resolved, rerr := s.resolver.ResolveHandle(r.Context(), handle.Normalize()) 125 + if rerr != nil { 126 + http.Error(w, fmt.Sprintf("could not resolve handle %q: %s", didInput, rerr), http.StatusBadRequest) 127 + return 128 + } 129 + did = resolved.String() 130 + } 131 + } 132 + 113 133 repos, err := db.ListRepos(r.Context(), s.db, page, did, knot, state, name) 114 134 if err != nil { 115 135 http.Error(w, err.Error(), http.StatusInternalServerError)
+6 -2
knotmirror/knotmirror.go
··· 33 33 34 34 rdb := redis.NewClient(&redis.Options{Addr: cfg.RedisAddr}) 35 35 36 - resolver := idresolver.DefaultResolver(cfg.PlcUrl) 36 + resolver, err := idresolver.RedisResolver("redis://"+cfg.RedisAddr, cfg.PlcUrl) 37 + if err != nil { 38 + logger.Error("failed to create redis resolver for admin, falling back to default", "err", err) 39 + resolver = idresolver.DefaultResolver(cfg.PlcUrl) 40 + } 37 41 38 42 // NOTE: using plain git-cli for clone/fetch as go-git is too memory-intensive. 39 43 gitm := NewCliGitMirrorManager(cfg.GitRepoBasePath, cfg.KnotUseSSL) ··· 56 60 crawler := NewCrawler(logger, db) 57 61 resyncer := NewResyncer(logger, db, gitm, cfg) 58 62 xrpc := xrpc.New(logger, cfg, db, rdb, resolver, knotstream) 59 - adminpage := NewAdminServer(logger, db, resyncer, xrpc) 63 + adminpage := NewAdminServer(logger, db, resyncer, xrpc, resolver) 60 64 61 65 // maintain repository list with tap 62 66 // NOTE: this can be removed once we introduce did-for-repo because then we can just listen to KnotStream for #identity events.
+1 -1
knotmirror/templates/repos.html
··· 10 10 hx-swap="outerHTML" 11 11 hx-trigger="input delay:300ms from:input, change from:select, every 10s" 12 12 > 13 - <input type="text" name="did" placeholder="DID" value="{{.FilterByDid}}"> 13 + <input type="text" name="did" placeholder="DID or handle" value="{{.FilterByDid}}"> 14 14 <input type="text" name="name" placeholder="Name" value="{{.FilterByName}}"> 15 15 <input type="text" name="knot" placeholder="Knot Domain" value="{{.FilterByKnot}}"> 16 16 <select name="state">