appview: add issue search endpoint #674

closed
opened by boltless.me targeting master from boltless.me/core: feat/search
Changed files
+93 -7
appview
db
issues
pages
templates
repo
issues
+57
appview/db/issues.go
··· 267 267 return &issue, nil 268 268 } 269 269 270 + // GetIssueIDs gets list of all existing issue's IDs 271 + func GetIssueIDs(e Execer, opts models.IssueSearchOptions) ([]int64, error) { 272 + var ids []int64 273 + 274 + var filters []filter 275 + openValue := 0 276 + if opts.IsOpen { 277 + openValue = 1 278 + } 279 + filters = append(filters, FilterEq("open", openValue)) 280 + if opts.RepoAt != "" { 281 + filters = append(filters, FilterEq("repo_at", opts.RepoAt)) 282 + } 283 + 284 + var conditions []string 285 + var args []any 286 + 287 + for _, filter := range filters { 288 + conditions = append(conditions, filter.Condition()) 289 + args = append(args, filter.Arg()...) 290 + } 291 + 292 + whereClause := "" 293 + if conditions != nil { 294 + whereClause = " where " + strings.Join(conditions, " and ") 295 + } 296 + query := fmt.Sprintf( 297 + ` 298 + select 299 + id 300 + from 301 + issues 302 + %s 303 + limit ? offset ?`, 304 + whereClause, 305 + ) 306 + args = append(args, opts.Page.Limit, opts.Page.Offset) 307 + rows, err := e.Query(query, args...) 308 + if err != nil { 309 + return nil, err 310 + } 311 + defer rows.Close() 312 + 313 + for rows.Next() { 314 + var id int64 315 + err := rows.Scan(&id) 316 + if err != nil { 317 + return nil, err 318 + } 319 + 320 + ids = append(ids, id) 321 + } 322 + 323 + return ids, nil 324 + } 325 + 326 + 270 327 func AddIssueComment(e Execer, c models.IssueComment) (int64, error) { 271 328 result, err := e.Exec( 272 329 `insert into issue_comments (
+27 -5
appview/issues/issues.go
··· 787 787 return 788 788 } 789 789 790 - openVal := 0 791 - if isOpen { 792 - openVal = 1 790 + keyword := params.Get("q") 791 + 792 + var ids []int64 793 + searchOpts := models.IssueSearchOptions{ 794 + Keyword: keyword, 795 + RepoAt: f.RepoAt().String(), 796 + IsOpen: isOpen, 797 + Page: page, 798 + } 799 + if keyword != "" { 800 + res, err := rp.indexer.Search(r.Context(), searchOpts) 801 + if err != nil { 802 + l.Error("failed to search for issues", "err", err) 803 + return 804 + } 805 + l.Debug("searched issues with indexer", "res.Hits", res.Hits) 806 + ids = res.Hits 807 + } else { 808 + ids, err = db.GetIssueIDs(rp.db, searchOpts) 809 + if err != nil { 810 + l.Error("failed to search for issues", "err", err) 811 + return 812 + } 813 + l.Debug("indexed all issues from the db", "ids", ids) 793 814 } 815 + 794 816 issues, err := db.GetIssuesPaginated( 795 817 rp.db, 796 818 page, 797 - db.FilterEq("repo_at", f.RepoAt()), 798 - db.FilterEq("open", openVal), 819 + db.FilterIn("id", ids), 799 820 ) 800 821 if err != nil { 801 822 l.Error("failed to get issues", "err", err) ··· 825 846 Issues: issues, 826 847 LabelDefs: defs, 827 848 FilteringByOpen: isOpen, 849 + FilterQuery: keyword, 828 850 Page: page, 829 851 }) 830 852 }
+9 -2
appview/pages/templates/repo/issues/issues.html
··· 24 24 {{ i "ban" "w-4 h-4" }} 25 25 <span>{{ .RepoInfo.Stats.IssueCount.Closed }} closed</span> 26 26 </a> 27 + <form class="flex gap-4" method="GET"> 28 + <input type="hidden" name="state" value="{{ if .FilteringByOpen }}open{{ else }}closed{{ end }}"> 29 + <input class="" type="text" name="q" value="{{ .FilterQuery }}"> 30 + <button class="btn" type="submit"> 31 + search 32 + </button> 33 + </form> 27 34 </div> 28 35 <a 29 36 href="/{{ .RepoInfo.FullName }}/issues/new" ··· 55 62 <a 56 63 class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700" 57 64 hx-boost="true" 58 - href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&offset={{ $prev.Offset }}&limit={{ $prev.Limit }}" 65 + href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&q={{ .FilterQuery }}&offset={{ $prev.Offset }}&limit={{ $prev.Limit }}" 59 66 > 60 67 {{ i "chevron-left" "w-4 h-4" }} 61 68 previous ··· 69 76 <a 70 77 class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700" 71 78 hx-boost="true" 72 - href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&offset={{ $next.Offset }}&limit={{ $next.Limit }}" 79 + href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&q={{ .FilterQuery }}&offset={{ $next.Offset }}&limit={{ $next.Limit }}" 73 80 > 74 81 next 75 82 {{ i "chevron-right" "w-4 h-4" }}