Monorepo for Tangled tangled.org

appview/pages: add search bar to profile-repos tab #1214

merged opened by oppi.li targeting master from op/nzpklsurrukv

this search bar has language and topic as keyword filters.

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

Labels

None yet.

assignee

None yet.

Participants 1
AT URI
at://did:plc:qfpnj4og54vl56wngdriaxug/sh.tangled.repo.pull/3mhpxt77xfk22
+129 -10
Diff #0
+3
appview/pages/pages.go
··· 649 649 Repos []models.Repo 650 650 Card *ProfileCard 651 651 Active string 652 + Page pagination.Page 653 + RepoCount int 654 + FilterQuery string 652 655 } 653 656 654 657 func (p *Pages) ProfileRepos(w io.Writer, params ProfileReposParams) error {
+39 -1
appview/pages/templates/user/repos.html
··· 2 2 3 3 {{ define "profileContent" }} 4 4 <div id="all-repos" class="md:col-span-8 order-2 md:order-2"> 5 - {{ block "ownRepos" . }}{{ end }} 5 + <div class="mb-4"> 6 + <form id="search-form" class="flex relative" method="GET"> 7 + <input type="hidden" name="tab" value="repos"> 8 + <div class="flex-1 flex relative"> 9 + <input 10 + id="search-q" 11 + class="flex-1 py-1 pl-2 pr-10 mr-[-1px] rounded-r-none peer" 12 + type="text" 13 + name="q" 14 + value="{{ .FilterQuery }}" 15 + placeholder="search repos..." 16 + > 17 + <a 18 + {{ if .FilterQuery }}href="?tab=repos"{{ else }}href="#"{{ end }} 19 + class="absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 {{ if not .FilterQuery }}hidden{{ end }} peer-[:not(:placeholder-shown)]:block" 20 + > 21 + {{ i "x" "w-4 h-4" }} 22 + </a> 23 + </div> 24 + <button 25 + type="submit" 26 + class="p-2 text-gray-400 border rounded-r border-gray-300 dark:border-gray-600" 27 + > 28 + {{ i "search" "w-4 h-4" }} 29 + </button> 30 + </form> 31 + </div> 32 + 33 + {{ block "ownRepos" . }}{{ end }} 34 + 35 + {{if gt .RepoCount .Page.Limit }} 36 + {{ $handle := resolve .Card.UserDid }} 37 + {{ template "fragments/pagination" (dict 38 + "Page" .Page 39 + "TotalCount" .RepoCount 40 + "BasePath" (printf "/%s" $handle) 41 + "QueryParams" (queryParams "tab" "repos" "q" .FilterQuery) 42 + ) }} 43 + {{ end }} 6 44 </div> 7 45 {{ end }} 8 46
+87 -9
appview/state/profile.go
··· 17 17 "github.com/gorilla/feeds" 18 18 "tangled.org/core/api/tangled" 19 19 "tangled.org/core/appview/db" 20 + "tangled.org/core/appview/middleware" 20 21 "tangled.org/core/appview/models" 21 22 "tangled.org/core/appview/pages" 23 + "tangled.org/core/appview/pagination" 24 + "tangled.org/core/appview/searchquery" 22 25 "tangled.org/core/orm" 23 26 "tangled.org/core/xrpc" 24 27 ) ··· 27 30 tabVal := r.URL.Query().Get("tab") 28 31 switch tabVal { 29 32 case "repos": 30 - s.reposPage(w, r) 33 + middleware. 34 + Paginate(http.HandlerFunc(s.reposPage)). 35 + ServeHTTP(w, r) 31 36 case "followers": 32 37 s.followersPage(w, r) 33 38 case "following": ··· 228 233 } 229 234 l = l.With("profileDid", profile.UserDid) 230 235 231 - repos, err := db.GetRepos( 232 - s.db, 233 - orm.FilterEq("did", profile.UserDid), 234 - ) 235 - if err != nil { 236 - l.Error("failed to get repos", "err", err) 237 - s.pages.Error500(w) 238 - return 236 + params := r.URL.Query() 237 + page := pagination.FromContext(r.Context()) 238 + 239 + query := searchquery.Parse(params.Get("q")) 240 + 241 + var language string 242 + if lang := query.Get("language"); lang != nil { 243 + language = *lang 244 + } 245 + 246 + tf := searchquery.ExtractTextFilters(query) 247 + 248 + searchOpts := models.RepoSearchOptions{ 249 + Keywords: tf.Keywords, 250 + Phrases: tf.Phrases, 251 + NegatedKeywords: tf.NegatedKeywords, 252 + NegatedPhrases: tf.NegatedPhrases, 253 + Did: profile.UserDid, 254 + Language: language, 255 + Page: page, 256 + } 257 + 258 + var repos []models.Repo 259 + var totalRepos int64 260 + 261 + if searchOpts.HasSearchFilters() { 262 + res, err := s.indexer.Repos.Search(r.Context(), searchOpts) 263 + if err != nil { 264 + l.Error("failed to search repos", "err", err) 265 + s.pages.Error500(w) 266 + return 267 + } 268 + 269 + if len(res.Hits) > 0 { 270 + repos, err = db.GetRepos(s.db, orm.FilterIn("id", res.Hits)) 271 + if err != nil { 272 + l.Error("failed to get repos by IDs", "err", err) 273 + s.pages.Error500(w) 274 + return 275 + } 276 + 277 + // sort repos to match search result order (by relevance) 278 + repoMap := make(map[int64]models.Repo, len(repos)) 279 + for _, repo := range repos { 280 + repoMap[repo.Id] = repo 281 + } 282 + repos = make([]models.Repo, 0, len(res.Hits)) 283 + for _, id := range res.Hits { 284 + if repo, ok := repoMap[id]; ok { 285 + repos = append(repos, repo) 286 + } 287 + } 288 + } 289 + totalRepos = int64(res.Total) 290 + } else { 291 + repos, err = db.GetReposPaginated( 292 + s.db, 293 + page, 294 + orm.FilterEq("did", profile.UserDid), 295 + ) 296 + if err != nil { 297 + l.Error("failed to get repos", "err", err) 298 + s.pages.Error500(w) 299 + return 300 + } 301 + 302 + totalRepos, err = db.CountRepos( 303 + s.db, 304 + orm.FilterEq("did", profile.UserDid), 305 + ) 306 + if err != nil { 307 + l.Error("failed to count repos", "err", err) 308 + s.pages.Error500(w) 309 + return 310 + } 239 311 } 240 312 241 313 err = s.pages.ProfileRepos(w, pages.ProfileReposParams{ 242 314 LoggedInUser: s.oauth.GetMultiAccountUser(r), 243 315 Repos: repos, 244 316 Card: profile, 317 + Page: page, 318 + RepoCount: int(totalRepos), 319 + FilterQuery: query.String(), 245 320 }) 321 + if err != nil { 322 + l.Error("failed to render page", "err", err) 323 + } 246 324 } 247 325 248 326 func (s *State) starredPage(w http.ResponseWriter, r *http.Request) {

History

1 round 0 comments
sign up or login to add to the discussion
oppi.li submitted #0
1 commit
expand
appview/pages: add search bar to profile-repos tab
1/3 failed, 2/3 success
expand
expand 0 comments
pull request successfully merged