appview: add issue search endpoint #496

merged
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
···
return &issue, nil
}
+
// GetIssueIDs gets list of all existing issue's IDs
+
func GetIssueIDs(e Execer, opts models.IssueSearchOptions) ([]int64, error) {
+
var ids []int64
+
+
var filters []filter
+
openValue := 0
+
if opts.IsOpen {
+
openValue = 1
+
}
+
filters = append(filters, FilterEq("open", openValue))
+
if opts.RepoAt != "" {
+
filters = append(filters, FilterEq("repo_at", opts.RepoAt))
+
}
+
+
var conditions []string
+
var args []any
+
+
for _, filter := range filters {
+
conditions = append(conditions, filter.Condition())
+
args = append(args, filter.Arg()...)
+
}
+
+
whereClause := ""
+
if conditions != nil {
+
whereClause = " where " + strings.Join(conditions, " and ")
+
}
+
query := fmt.Sprintf(
+
`
+
select
+
id
+
from
+
issues
+
%s
+
limit ? offset ?`,
+
whereClause,
+
)
+
args = append(args, opts.Page.Limit, opts.Page.Offset)
+
rows, err := e.Query(query, args...)
+
if err != nil {
+
return nil, err
+
}
+
defer rows.Close()
+
+
for rows.Next() {
+
var id int64
+
err := rows.Scan(&id)
+
if err != nil {
+
return nil, err
+
}
+
+
ids = append(ids, id)
+
}
+
+
return ids, nil
+
}
+
+
func AddIssueComment(e Execer, c models.IssueComment) (int64, error) {
result, err := e.Exec(
`insert into issue_comments (
+27 -5
appview/issues/issues.go
···
return
}
-
openVal := 0
-
if isOpen {
-
openVal = 1
+
keyword := params.Get("q")
+
+
var ids []int64
+
searchOpts := models.IssueSearchOptions{
+
Keyword: keyword,
+
RepoAt: f.RepoAt().String(),
+
IsOpen: isOpen,
+
Page: page,
+
}
+
if keyword != "" {
+
res, err := rp.indexer.Search(r.Context(), searchOpts)
+
if err != nil {
+
l.Error("failed to search for issues", "err", err)
+
return
+
}
+
l.Debug("searched issues with indexer", "res.Hits", res.Hits)
+
ids = res.Hits
+
} else {
+
ids, err = db.GetIssueIDs(rp.db, searchOpts)
+
if err != nil {
+
l.Error("failed to search for issues", "err", err)
+
return
+
}
+
l.Debug("indexed all issues from the db", "ids", ids)
}
+
issues, err := db.GetIssuesPaginated(
rp.db,
page,
-
db.FilterEq("repo_at", f.RepoAt()),
-
db.FilterEq("open", openVal),
+
db.FilterIn("id", ids),
)
if err != nil {
l.Error("failed to get issues", "err", err)
···
Issues: issues,
LabelDefs: defs,
FilteringByOpen: isOpen,
+
FilterQuery: keyword,
Page: page,
})
}
+9 -2
appview/pages/templates/repo/issues/issues.html
···
{{ i "ban" "w-4 h-4" }}
<span>{{ .RepoInfo.Stats.IssueCount.Closed }} closed</span>
</a>
+
<form class="flex gap-4" method="GET">
+
<input type="hidden" name="state" value="{{ if .FilteringByOpen }}open{{ else }}closed{{ end }}">
+
<input class="" type="text" name="q" value="{{ .FilterQuery }}">
+
<button class="btn" type="submit">
+
search
+
</button>
+
</form>
</div>
<a
href="/{{ .RepoInfo.FullName }}/issues/new"
···
<a
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
hx-boost="true"
-
href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&offset={{ $prev.Offset }}&limit={{ $prev.Limit }}"
+
href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&q={{ .FilterQuery }}&offset={{ $prev.Offset }}&limit={{ $prev.Limit }}"
>
{{ i "chevron-left" "w-4 h-4" }}
previous
···
<a
class="btn flex items-center gap-2 no-underline hover:no-underline dark:text-white dark:hover:bg-gray-700"
hx-boost="true"
-
href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&offset={{ $next.Offset }}&limit={{ $next.Limit }}"
+
href = "/{{ $.RepoInfo.FullName }}/issues?state={{ $currentState }}&q={{ .FilterQuery }}&offset={{ $next.Offset }}&limit={{ $next.Limit }}"
>
next
{{ i "chevron-right" "w-4 h-4" }}