feat: Add Search to Releases Page
This commit is contained in:
parent
e5e2860221
commit
86546fe63e
7 changed files with 69 additions and 3 deletions
|
@ -249,6 +249,7 @@ type FindReleasesOptions struct {
|
||||||
IsDraft optional.Option[bool]
|
IsDraft optional.Option[bool]
|
||||||
TagNames []string
|
TagNames []string
|
||||||
HasSha1 optional.Option[bool] // useful to find draft releases which are created with existing tags
|
HasSha1 optional.Option[bool] // useful to find draft releases which are created with existing tags
|
||||||
|
Keyword string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (opts FindReleasesOptions) ToConds() builder.Cond {
|
func (opts FindReleasesOptions) ToConds() builder.Cond {
|
||||||
|
@ -276,6 +277,15 @@ func (opts FindReleasesOptions) ToConds() builder.Cond {
|
||||||
cond = cond.And(builder.Eq{"sha1": ""})
|
cond = cond.And(builder.Eq{"sha1": ""})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if opts.Keyword != "" {
|
||||||
|
keywordCond := builder.NewCond()
|
||||||
|
keywordCond = keywordCond.Or(builder.Like{"lower_tag_name", strings.ToLower(opts.Keyword)})
|
||||||
|
keywordCond = keywordCond.Or(db.BuildCaseInsensitiveLike("title", opts.Keyword))
|
||||||
|
keywordCond = keywordCond.Or(db.BuildCaseInsensitiveLike("note", opts.Keyword))
|
||||||
|
cond = cond.And(keywordCond)
|
||||||
|
}
|
||||||
|
|
||||||
return cond
|
return cond
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -136,6 +136,10 @@ func ListReleases(ctx *context.APIContext) {
|
||||||
// in: query
|
// in: query
|
||||||
// description: filter (exclude / include) pre-releases
|
// description: filter (exclude / include) pre-releases
|
||||||
// type: boolean
|
// type: boolean
|
||||||
|
// - name: q
|
||||||
|
// in: query
|
||||||
|
// description: Search string
|
||||||
|
// type: string
|
||||||
// - name: page
|
// - name: page
|
||||||
// in: query
|
// in: query
|
||||||
// description: page number of results to return (1-based)
|
// description: page number of results to return (1-based)
|
||||||
|
@ -158,6 +162,7 @@ func ListReleases(ctx *context.APIContext) {
|
||||||
IsDraft: ctx.FormOptionalBool("draft"),
|
IsDraft: ctx.FormOptionalBool("draft"),
|
||||||
IsPreRelease: ctx.FormOptionalBool("pre-release"),
|
IsPreRelease: ctx.FormOptionalBool("pre-release"),
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
Keyword: ctx.FormTrim("q"),
|
||||||
}
|
}
|
||||||
|
|
||||||
releases, err := db.Find[repo_model.Release](ctx, opts)
|
releases, err := db.Find[repo_model.Release](ctx, opts)
|
||||||
|
|
|
@ -168,6 +168,10 @@ func Releases(ctx *context.Context) {
|
||||||
// Disable the showCreateNewBranch form in the dropdown on this page.
|
// Disable the showCreateNewBranch form in the dropdown on this page.
|
||||||
ctx.Data["CanCreateBranch"] = false
|
ctx.Data["CanCreateBranch"] = false
|
||||||
ctx.Data["HideBranchesInDropdown"] = true
|
ctx.Data["HideBranchesInDropdown"] = true
|
||||||
|
ctx.Data["ShowReleaseSearch"] = true
|
||||||
|
|
||||||
|
keyword := ctx.FormTrim("q")
|
||||||
|
ctx.Data["Keyword"] = keyword
|
||||||
|
|
||||||
listOptions := db.ListOptions{
|
listOptions := db.ListOptions{
|
||||||
Page: ctx.FormInt("page"),
|
Page: ctx.FormInt("page"),
|
||||||
|
@ -188,6 +192,7 @@ func Releases(ctx *context.Context) {
|
||||||
// only show draft releases for users who can write, read-only users shouldn't see draft releases.
|
// only show draft releases for users who can write, read-only users shouldn't see draft releases.
|
||||||
IncludeDrafts: writeAccess,
|
IncludeDrafts: writeAccess,
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
Keyword: keyword,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctx.ServerError("getReleaseInfos", err)
|
ctx.ServerError("getReleaseInfos", err)
|
||||||
|
@ -258,6 +263,10 @@ func TagsList(ctx *context.Context) {
|
||||||
ctx.Data["CanCreateBranch"] = false
|
ctx.Data["CanCreateBranch"] = false
|
||||||
ctx.Data["HideBranchesInDropdown"] = true
|
ctx.Data["HideBranchesInDropdown"] = true
|
||||||
ctx.Data["CanCreateRelease"] = ctx.Repo.CanWrite(unit.TypeReleases) && !ctx.Repo.Repository.IsArchived
|
ctx.Data["CanCreateRelease"] = ctx.Repo.CanWrite(unit.TypeReleases) && !ctx.Repo.Repository.IsArchived
|
||||||
|
ctx.Data["ShowReleaseSearch"] = true
|
||||||
|
|
||||||
|
keyword := ctx.FormTrim("q")
|
||||||
|
ctx.Data["Keyword"] = keyword
|
||||||
|
|
||||||
listOptions := db.ListOptions{
|
listOptions := db.ListOptions{
|
||||||
Page: ctx.FormInt("page"),
|
Page: ctx.FormInt("page"),
|
||||||
|
@ -278,6 +287,7 @@ func TagsList(ctx *context.Context) {
|
||||||
IncludeTags: true,
|
IncludeTags: true,
|
||||||
HasSha1: optional.Some(true),
|
HasSha1: optional.Some(true),
|
||||||
RepoID: ctx.Repo.Repository.ID,
|
RepoID: ctx.Repo.Repository.ID,
|
||||||
|
Keyword: keyword,
|
||||||
}
|
}
|
||||||
|
|
||||||
releases, err := db.Find[repo_model.Release](ctx, opts)
|
releases, err := db.Find[repo_model.Release](ctx, opts)
|
||||||
|
|
|
@ -5,15 +5,20 @@
|
||||||
<div class="tw-flex">
|
<div class="tw-flex">
|
||||||
<div class="tw-flex-1 tw-flex tw-items-center">
|
<div class="tw-flex-1 tw-flex tw-items-center">
|
||||||
<h2 class="ui compact small menu small-menu-items">
|
<h2 class="ui compact small menu small-menu-items">
|
||||||
<a class="{{if and .PageIsReleaseList (not .PageIsSingleTag)}}active {{end}}item" href="{{.RepoLink}}/releases">{{ctx.Locale.TrN .NumReleases "repo.n_release_one" "repo.n_release_few" (ctx.Locale.PrettyNumber .NumReleases)}}</a>
|
<a class="{{if and .PageIsReleaseList (not .PageIsSingleTag)}}active {{end}}item" href="{{.RepoLink}}/releases{{if .Keyword}}?q={{.Keyword}}{{end}}">{{ctx.Locale.TrN .NumReleases "repo.n_release_one" "repo.n_release_few" (ctx.Locale.PrettyNumber .NumReleases)}}</a>
|
||||||
{{if $canReadCode}}
|
{{if $canReadCode}}
|
||||||
<a class="{{if or .PageIsTagList .PageIsSingleTag}}active {{end}}item" href="{{.RepoLink}}/tags">{{ctx.Locale.TrN .NumTags "repo.n_tag_one" "repo.n_tag_few" (ctx.Locale.PrettyNumber .NumTags)}}</a>
|
<a class="{{if or .PageIsTagList .PageIsSingleTag}}active {{end}}item" href="{{.RepoLink}}/tags{{if .Keyword}}?q={{.Keyword}}{{end}}">{{ctx.Locale.TrN .NumTags "repo.n_tag_one" "repo.n_tag_few" (ctx.Locale.PrettyNumber .NumTags)}}</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
{{if .ShowReleaseSearch}}
|
||||||
|
<form class="ignore-dirty tw-w-1/5 tw-mr-3" method="get">
|
||||||
|
{{template "shared/search/combo" dict "Value" .Keyword}}
|
||||||
|
</form>
|
||||||
|
{{end}}
|
||||||
<div class="button-row">
|
<div class="button-row">
|
||||||
{{if .EnableFeed}}
|
{{if .EnableFeed}}
|
||||||
<a class="ui small button" href="{{.RepoLink}}/{{if .PageIsTagList}}tags{{else}}releases{{end}}.rss">
|
<a class="ui small button tw-h-full" href="{{.RepoLink}}/{{if .PageIsTagList}}tags{{else}}releases{{end}}.rss">
|
||||||
{{svg "octicon-rss" 16}} {{ctx.Locale.Tr "rss_feed"}}
|
{{svg "octicon-rss" 16}} {{ctx.Locale.Tr "rss_feed"}}
|
||||||
</a>
|
</a>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
6
templates/swagger/v1_json.tmpl
generated
6
templates/swagger/v1_json.tmpl
generated
|
@ -14163,6 +14163,12 @@
|
||||||
"name": "pre-release",
|
"name": "pre-release",
|
||||||
"in": "query"
|
"in": "query"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "string",
|
||||||
|
"description": "Search string",
|
||||||
|
"name": "q",
|
||||||
|
"in": "query"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"description": "page number of results to return (1-based)",
|
"description": "page number of results to return (1-based)",
|
||||||
|
|
|
@ -76,6 +76,7 @@ func TestAPIListReleases(t *testing.T) {
|
||||||
testFilterByLen(true, url.Values{"draft": {"false"}, "pre-release": {"false"}}, 1, "exclude drafts and pre-releases")
|
testFilterByLen(true, url.Values{"draft": {"false"}, "pre-release": {"false"}}, 1, "exclude drafts and pre-releases")
|
||||||
testFilterByLen(true, url.Values{"pre-release": {"true"}}, 1, "only get pre-release")
|
testFilterByLen(true, url.Values{"pre-release": {"true"}}, 1, "only get pre-release")
|
||||||
testFilterByLen(true, url.Values{"draft": {"true"}, "pre-release": {"true"}}, 0, "there is no pre-release draft")
|
testFilterByLen(true, url.Values{"draft": {"true"}, "pre-release": {"true"}}, 0, "there is no pre-release draft")
|
||||||
|
testFilterByLen(true, url.Values{"q": {"release"}}, 3, "keyword")
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNewReleaseUsingAPI(t *testing.T, token string, owner *user_model.User, repo *repo_model.Repository, name, target, title, desc string) *api.Release {
|
func createNewReleaseUsingAPI(t *testing.T, token string, owner *user_model.User, repo *repo_model.Repository, name, target, title, desc string) *api.Release {
|
||||||
|
|
|
@ -272,6 +272,35 @@ func TestViewReleaseListLogin(t *testing.T) {
|
||||||
}, links)
|
}, links)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestViewReleaseListKeyword(t *testing.T) {
|
||||||
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
repo := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
|
||||||
|
|
||||||
|
link := repo.Link() + "/releases?q=testing"
|
||||||
|
|
||||||
|
session := loginUser(t, "user1")
|
||||||
|
req := NewRequest(t, "GET", link)
|
||||||
|
rsp := session.MakeRequest(t, req, http.StatusOK)
|
||||||
|
|
||||||
|
htmlDoc := NewHTMLParser(t, rsp.Body)
|
||||||
|
releases := htmlDoc.Find("#release-list li.ui.grid")
|
||||||
|
assert.Equal(t, 1, releases.Length())
|
||||||
|
|
||||||
|
links := make([]string, 0, 5)
|
||||||
|
releases.Each(func(i int, s *goquery.Selection) {
|
||||||
|
link, exist := s.Find(".release-list-title a").Attr("href")
|
||||||
|
if !exist {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
links = append(links, link)
|
||||||
|
})
|
||||||
|
|
||||||
|
assert.EqualValues(t, []string{
|
||||||
|
"/user2/repo1/releases/tag/v1.1",
|
||||||
|
}, links)
|
||||||
|
}
|
||||||
|
|
||||||
func TestReleaseOnCommit(t *testing.T) {
|
func TestReleaseOnCommit(t *testing.T) {
|
||||||
defer tests.PrepareTestEnv(t)()
|
defer tests.PrepareTestEnv(t)()
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue