forked from tangled.org/core
Monorepo for Tangled

appview: add issue search endpoint

Signed-off-by: Seongmin Lee <boltlessengineer@proton.me>

authored by boltless.me and committed by Tangled 552fa4b9 fc9517ce

Changed files
+93 -9
appview
db
issues
pages
templates
repo
issues
+56
appview/db/issues.go
··· 250 250 return GetIssuesPaginated(e, pagination.Page{}, filters...) 251 251 } 252 252 253 + // GetIssueIDs gets list of all existing issue's IDs 254 + func GetIssueIDs(e Execer, opts models.IssueSearchOptions) ([]int64, error) { 255 + var ids []int64 256 + 257 + var filters []filter 258 + openValue := 0 259 + if opts.IsOpen { 260 + openValue = 1 261 + } 262 + filters = append(filters, FilterEq("open", openValue)) 263 + if opts.RepoAt != "" { 264 + filters = append(filters, FilterEq("repo_at", opts.RepoAt)) 265 + } 266 + 267 + var conditions []string 268 + var args []any 269 + 270 + for _, filter := range filters { 271 + conditions = append(conditions, filter.Condition()) 272 + args = append(args, filter.Arg()...) 273 + } 274 + 275 + whereClause := "" 276 + if conditions != nil { 277 + whereClause = " where " + strings.Join(conditions, " and ") 278 + } 279 + query := fmt.Sprintf( 280 + ` 281 + select 282 + id 283 + from 284 + issues 285 + %s 286 + limit ? offset ?`, 287 + whereClause, 288 + ) 289 + args = append(args, opts.Page.Limit, opts.Page.Offset) 290 + rows, err := e.Query(query, args...) 291 + if err != nil { 292 + return nil, err 293 + } 294 + defer rows.Close() 295 + 296 + for rows.Next() { 297 + var id int64 298 + err := rows.Scan(&id) 299 + if err != nil { 300 + return nil, err 301 + } 302 + 303 + ids = append(ids, id) 304 + } 305 + 306 + return ids, nil 307 + } 308 + 253 309 func AddIssueComment(e Execer, c models.IssueComment) (int64, error) { 254 310 result, err := e.Exec( 255 311 `insert into issue_comments (
+28 -7
appview/issues/issues.go
··· 783 783 return 784 784 } 785 785 786 - openVal := 0 787 - if isOpen { 788 - openVal = 1 786 + keyword := params.Get("q") 787 + 788 + var ids []int64 789 + searchOpts := models.IssueSearchOptions{ 790 + Keyword: keyword, 791 + RepoAt: f.RepoAt().String(), 792 + IsOpen: isOpen, 793 + Page: page, 794 + } 795 + if keyword != "" { 796 + res, err := rp.indexer.Search(r.Context(), searchOpts) 797 + if err != nil { 798 + l.Error("failed to search for issues", "err", err) 799 + return 800 + } 801 + ids = res.Hits 802 + l.Debug("searched issues with indexer", "count", len(ids)) 803 + } else { 804 + ids, err = db.GetIssueIDs(rp.db, searchOpts) 805 + if err != nil { 806 + l.Error("failed to search for issues", "err", err) 807 + return 808 + } 809 + l.Debug("indexed all issues from the db", "count", len(ids)) 789 810 } 790 - issues, err := db.GetIssuesPaginated( 811 + 812 + issues, err := db.GetIssues( 791 813 rp.db, 792 - page, 793 - db.FilterEq("repo_at", f.RepoAt()), 794 - db.FilterEq("open", openVal), 814 + db.FilterIn("id", ids), 795 815 ) 796 816 if err != nil { 797 817 l.Error("failed to get issues", "err", err) ··· 821 841 Issues: issues, 822 842 LabelDefs: defs, 823 843 FilteringByOpen: isOpen, 844 + FilterQuery: keyword, 824 845 Page: page, 825 846 }) 826 847 }
+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" }}