Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue dependencies ui kind of broken #4479

Open
2 tasks done
Aragur opened this issue Jul 20, 2018 · 22 comments · May be fixed by #31479, #29728 or #31510
Open
2 tasks done

Issue dependencies ui kind of broken #4479

Aragur opened this issue Jul 20, 2018 · 22 comments · May be fixed by #31479, #29728 or #31510
Labels
issue/confirmed Issue has been reviewed and confirmed to be present or accepted to be implemented topic/ui Change the appearance of the Gitea UI type/bug

Comments

@Aragur
Copy link

Aragur commented Jul 20, 2018

Description

In the dependencies list it only lists the last 8 issues relative to that one. For example issue #12 can only see issues #11 to #3. Also manual mention (for example of #1) doesn’t work.
Thanks to @Morlinest we already know more details:
Current work around is to search the exact issue name to add another.
Direct mention of the issue id is not working (but this should a thing).

Screenshots

Try to select #1 on issue #12
Try to select #1 on issue #12

@jonasfranz
Copy link
Member

Ping @kolaente

@jonasfranz jonasfranz added type/bug topic/ui Change the appearance of the Gitea UI labels Jul 20, 2018
@kolaente
Copy link
Member

kolaente commented Jul 20, 2018

This is something which should be fixed directly in the issue search, as I'm only using that (via the api). The results are the same as when you search on {projecturl}/issues.

I agree the issue search is not very good implemented.

@kolaente
Copy link
Member

I'd rather have the search return issues by their index instead of frankensteining this into the dependencies.

@stale
Copy link

stale bot commented Jan 17, 2019

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs during the next 2 weeks. Thank you for your contributions.

@stevegt
Copy link
Contributor

stevegt commented Mar 5, 2019

Just noticed that direct mention of the issue id is still not working as of 7d973ed.

@zeripath
Copy link
Contributor

zeripath commented Mar 6, 2019

@stevegt could you give a quick example of what you mean. Preferably with a try.gitea.io link?

It might be best to open another issue since this one is closed.

@stevegt
Copy link
Contributor

stevegt commented Mar 6, 2019

@zeripath A 'try' link won't help -- go to any issue you can edit and enter an issue number into the 'dependencies' field, either with or without a leading '#'. You'll see that you get an error response of 'Dependent issue does not exist.'

This issue was recently closed by stale bot due to lack of activity, not because it's been addressed. There has been no merge referencing it. Re-opening would be the normal thing to do, rather than fragment the conversation. I'll let it sit for a while to see if anyone with access re-opens. I may get to this with a fix myself at some point as well.

@zeripath zeripath reopened this Mar 7, 2019
@stale stale bot removed the issue/stale label Mar 7, 2019
@zeripath zeripath added the issue/confirmed Issue has been reviewed and confirmed to be present or accepted to be implemented label Mar 7, 2019
@nascimentolwtn
Copy link

For me is happening something similar, but it seems to be a cache problem, because if I create a sequence of issues, only old ones once shown are listed on new issues to be included as dependency. Also, it seems to show only the first page of opened issues (typing '#' would help).

A workaround: change browser or clear cache history.

@xf-
Copy link
Contributor

xf- commented May 11, 2019

@nascimentolwtn i think is is caused by service worker and caching the result

@lesh59
Copy link

lesh59 commented Dec 4, 2020

I think the dependency drop down is only showing the first page of issues. Changing the ISSUE_PAGING_NUM in app.ini to a larger number showed more issues in the drop down (and on the issues page of course). The drop down should not be affected by "pages", should be all issues, filtered as you type.

@samaust
Copy link

samaust commented Mar 8, 2021

Tested on version 1.11.6 :

  • Searching the title of an issue that is not in the choices shown in the drop-down menu works.
  • Searching the linked reference (mike/compiler#1234) does not return results.

@6543
Copy link
Member

6543 commented Mar 8, 2021

@samaust sorry, we dont support anymore v1.11.6 & you should upgrade for security reasons

@stevegt
Copy link
Contributor

stevegt commented Mar 18, 2021

@6543 The fact that @samaust is running an old version is orthogonal to this issue -- the bug still exists in 1.14.0+dev-874-ge8ad6c1ff.

@Giszmo
Copy link

Giszmo commented Apr 14, 2022

I installed from snap yesterday and ran into this same issue.

gitea 1.16.5

Not sure if bugbounties are welcome but I'd tip $50 in BTC for this to be fixed.

@Ryuno-Ki
Copy link
Contributor

Ryuno-Ki commented Jun 5, 2022

The relevant template is

{{if and .CanCreateIssueDependencies (not .Repository.IsArchived)}}
<div>
<form method="POST" action="{{.Issue.Link}}/dependency/add" id="addDependencyForm">
{{$.CsrfTokenHtml}}
<div class="ui fluid action input">
<div class="ui search selection dropdown" id="new-dependency-drop-list" data-issue-id="{{.Issue.ID}}">
<input name="newDependency" type="hidden">
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<input type="text" class="search">
<div class="default text">{{.i18n.Tr "repo.issues.dependency.add"}}</div>
</div>
<button class="ui green icon button">
{{svg "octicon-plus"}}
</button>
</div>
</form>
</div>
{{end}}

The associated JavaScript

export function initRepoIssueList() {
const repolink = $('#repolink').val();
const repoId = $('#repoId').val();
const crossRepoSearch = $('#crossRepoSearch').val();
const tp = $('#type').val();
let issueSearchUrl = `${appSubUrl}/${repolink}/issues/search?q={query}&type=${tp}`;
if (crossRepoSearch === 'true') {
issueSearchUrl = `${appSubUrl}/issues/search?q={query}&priority_repo_id=${repoId}&type=${tp}`;
}
$('#new-dependency-drop-list')
.dropdown({
apiSettings: {
url: issueSearchUrl,
onResponse(response) {
const filteredResponse = {success: true, results: []};
const currIssueId = $('#new-dependency-drop-list').data('issue-id');
// Parse the response from the api to work with our dropdown
$.each(response, (_i, issue) => {
// Don't list current issue in the dependency list.
if (issue.id === currIssueId) {
return;
}
filteredResponse.results.push({
name: `#${issue.number} ${htmlEscape(issue.title)
}<div class="text small dont-break-out">${htmlEscape(issue.repository.full_name)}</div>`,
value: issue.id,
});
});
return filteredResponse;
},
cache: false,
},
fullTextSearch: true,
});

A few questions come to my mind:

  1. Why is the JavaScript using .data() here? (see https://docs.gitea.io/en-us/guidelines-frontend/#html-attributes-and-dataset )
  2. I can see AJAX requests like /issues/search?q=some&priority_repo_id=2&type=all&_=1654452403354 Where is the associated router? (formerly using /api/v1/repos/issues/search. Changed in 783a021#diff-d39a63ccfd5f0fe703f74ce48a3624ba59a856317b0d236d7eae87dfcf6c1c20 ) The one below?
  3. Searching for something in the title or body (whole words) work. We want to reference the issue ID here, though.

func Search(ctx *context.Context) {
if !setting.Indexer.RepoIndexerEnabled {
ctx.Redirect(ctx.Repo.RepoLink)
return
}
language := ctx.FormTrim("l")
keyword := ctx.FormTrim("q")
page := ctx.FormInt("page")
if page <= 0 {
page = 1
}
queryType := ctx.FormTrim("t")
isMatch := queryType == "match"
total, searchResults, searchResultLanguages, err := code_indexer.PerformSearch(ctx, []int64{ctx.Repo.Repository.ID},
language, keyword, page, setting.UI.RepoSearchPagingNum, isMatch)
if err != nil {
if code_indexer.IsAvailable() {
ctx.ServerError("SearchResults", err)
return
}
ctx.Data["CodeIndexerUnavailable"] = true
} else {
ctx.Data["CodeIndexerUnavailable"] = !code_indexer.IsAvailable()
}
ctx.Data["Keyword"] = keyword
ctx.Data["Language"] = language
ctx.Data["queryType"] = queryType
ctx.Data["SourcePath"] = ctx.Repo.Repository.HTMLURL()
ctx.Data["SearchResults"] = searchResults
ctx.Data["SearchResultLanguages"] = searchResultLanguages
ctx.Data["PageIsViewCode"] = true
pager := context.NewPagination(total, setting.UI.RepoSearchPagingNum, page, 5)
pager.SetDefaultParams(ctx)
pager.AddParam(ctx, "l", "Language")
ctx.Data["Page"] = pager
ctx.HTML(http.StatusOK, tplSearch)
}

@Ryuno-Ki
Copy link
Contributor

Ryuno-Ki commented Jun 5, 2022

I got an explanation on routers in the chat.

The router in

m.Get("/search", repo.SearchIssues)

passes the request to SearchIssues:

// SearchIssues searches for issues across the repositories that the user has access to
func SearchIssues(ctx *context.Context) {
before, since, err := context.GetQueryBeforeSince(ctx)
if err != nil {
ctx.Error(http.StatusUnprocessableEntity, err.Error())
return
}
var isClosed util.OptionalBool
switch ctx.FormString("state") {
case "closed":
isClosed = util.OptionalBoolTrue
case "all":
isClosed = util.OptionalBoolNone
default:
isClosed = util.OptionalBoolFalse
}
// find repos user can access (for issue search)
opts := &models.SearchRepoOptions{
Private: false,
AllPublic: true,
TopicOnly: false,
Collaborate: util.OptionalBoolNone,
// This needs to be a column that is not nil in fixtures or
// MySQL will return different results when sorting by null in some cases
OrderBy: db.SearchOrderByAlphabetically,
Actor: ctx.Doer,
}
if ctx.IsSigned {
opts.Private = true
opts.AllLimited = true
}
if ctx.FormString("owner") != "" {
owner, err := user_model.GetUserByName(ctx, ctx.FormString("owner"))
if err != nil {
if user_model.IsErrUserNotExist(err) {
ctx.Error(http.StatusBadRequest, "Owner not found", err.Error())
} else {
ctx.Error(http.StatusInternalServerError, "GetUserByName", err.Error())
}
return
}
opts.OwnerID = owner.ID
opts.AllLimited = false
opts.AllPublic = false
opts.Collaborate = util.OptionalBoolFalse
}
if ctx.FormString("team") != "" {
if ctx.FormString("owner") == "" {
ctx.Error(http.StatusBadRequest, "", "Owner organisation is required for filtering on team")
return
}
team, err := organization.GetTeam(ctx, opts.OwnerID, ctx.FormString("team"))
if err != nil {
if organization.IsErrTeamNotExist(err) {
ctx.Error(http.StatusBadRequest, "Team not found", err.Error())
} else {
ctx.Error(http.StatusInternalServerError, "GetUserByName", err.Error())
}
return
}
opts.TeamID = team.ID
}
repoCond := models.SearchRepositoryCondition(opts)
repoIDs, _, err := models.SearchRepositoryIDs(opts)
if err != nil {
ctx.Error(http.StatusInternalServerError, "SearchRepositoryByName", err.Error())
return
}
var issues []*models.Issue
var filteredCount int64
keyword := ctx.FormTrim("q")
if strings.IndexByte(keyword, 0) >= 0 {
keyword = ""
}
var issueIDs []int64
if len(keyword) > 0 && len(repoIDs) > 0 {
if issueIDs, err = issue_indexer.SearchIssuesByKeyword(ctx, repoIDs, keyword); err != nil {
ctx.Error(http.StatusInternalServerError, "SearchIssuesByKeyword", err.Error())
return
}
}
var isPull util.OptionalBool
switch ctx.FormString("type") {
case "pulls":
isPull = util.OptionalBoolTrue
case "issues":
isPull = util.OptionalBoolFalse
default:
isPull = util.OptionalBoolNone
}
labels := ctx.FormTrim("labels")
var includedLabelNames []string
if len(labels) > 0 {
includedLabelNames = strings.Split(labels, ",")
}
milestones := ctx.FormTrim("milestones")
var includedMilestones []string
if len(milestones) > 0 {
includedMilestones = strings.Split(milestones, ",")
}
// this api is also used in UI,
// so the default limit is set to fit UI needs
limit := ctx.FormInt("limit")
if limit == 0 {
limit = setting.UI.IssuePagingNum
} else if limit > setting.API.MaxResponseItems {
limit = setting.API.MaxResponseItems
}
// Only fetch the issues if we either don't have a keyword or the search returned issues
// This would otherwise return all issues if no issues were found by the search.
if len(keyword) == 0 || len(issueIDs) > 0 || len(includedLabelNames) > 0 || len(includedMilestones) > 0 {
issuesOpt := &models.IssuesOptions{
ListOptions: db.ListOptions{
Page: ctx.FormInt("page"),
PageSize: limit,
},
RepoCond: repoCond,
IsClosed: isClosed,
IssueIDs: issueIDs,
IncludedLabelNames: includedLabelNames,
IncludeMilestones: includedMilestones,
SortType: "priorityrepo",
PriorityRepoID: ctx.FormInt64("priority_repo_id"),
IsPull: isPull,
UpdatedBeforeUnix: before,
UpdatedAfterUnix: since,
}
ctxUserID := int64(0)
if ctx.IsSigned {
ctxUserID = ctx.Doer.ID
}
// Filter for: Created by User, Assigned to User, Mentioning User, Review of User Requested
if ctx.FormBool("created") {
issuesOpt.PosterID = ctxUserID
}
if ctx.FormBool("assigned") {
issuesOpt.AssigneeID = ctxUserID
}
if ctx.FormBool("mentioned") {
issuesOpt.MentionedID = ctxUserID
}
if ctx.FormBool("review_requested") {
issuesOpt.ReviewRequestedID = ctxUserID
}
if issues, err = models.Issues(issuesOpt); err != nil {
ctx.Error(http.StatusInternalServerError, "Issues", err.Error())
return
}
issuesOpt.ListOptions = db.ListOptions{
Page: -1,
}
if filteredCount, err = models.CountIssues(issuesOpt); err != nil {
ctx.Error(http.StatusInternalServerError, "CountIssues", err.Error())
return
}
}
ctx.SetTotalCountHeader(filteredCount)
ctx.JSON(http.StatusOK, convert.ToAPIIssueList(issues))
}

That makes

func SearchIssuesByKeyword(ctx context.Context, repoIDs []int64, keyword string) ([]int64, error) {
var issueIDs []int64
indexer := holder.get()
if indexer == nil {
log.Error("SearchIssuesByKeyword(): unable to get indexer!")
return nil, fmt.Errorf("unable to get issue indexer")
}
res, err := indexer.Search(ctx, keyword, repoIDs, 50, 0)
if err != nil {
return nil, err
}
for _, r := range res.Hits {
issueIDs = append(issueIDs, r.ID)
}
return issueIDs, nil
}

the code that searches the issues.

Therefore, this issue is likely not of kind/ui.

@wxiaoguang
Copy link
Contributor

wxiaoguang commented Jun 6, 2022

I can answer some of your questions.

  1. Why is the JavaScript using .data() here? (see guideline )

There are a lot of legacy frontend code (as old as years ago). The rule for using attr instead of data was suggested by silverwind a few months ago and I wrote it into the guideline. For me, I am doing my best to make sure ever line of JS I touched follows the guideline.

  1. I can see AJAX requests like .. Where is the associated router?

The easiest way is just to run the code, and watch the output log. You will see the called router function in logs (zeripath and I added this feature in 1.17, to make develop & debug more easily)

  1. Searching for something in the title or body (whole words) work. We want to reference the issue ID here, though.

Yup, it's better to make the Issue Index can be searched or just loaded by hard-code (indeed, the number of the issue is called index internally, not id)

@d33pjs
Copy link

d33pjs commented Aug 10, 2022

Having (still) the same issue. Is someone working on that? Or are there any workarounds in the meantime?

@silkentrance silkentrance linked a pull request Jun 24, 2024 that will close this issue
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 24, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 24, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 25, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 25, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 25, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 25, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 25, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 25, 2024
@silkentrance
Copy link

silkentrance commented Jun 25, 2024

Partial matching of words is possible but might be expensive.

Bleve

Partial matching with bleve is a no brainer if you use camel case in your wording, which, of course, will not always work.

So, searching for 'iss' will never find 'issue'.
Yet, searching for 'foo' will find 'FooBar' or 'fooBar'.
The same goes for 't2', which can be found by a search for either 't' or '2'.

@6543
Copy link
Member

6543 commented Jun 26, 2024

I propose> create a popup template that based on usage has preset filters. (e.g. only issues/pulls of repo X)

and let issues search via keyword or number have it live updated...
... multiselect would be nice
... filter for closed and open

use that:

  • for adding issues/pulls in project board view to add to the project
  • adding dependencys

mockup:
image

silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 26, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 26, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 26, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 26, 2024
@silkentrance
Copy link

silkentrance commented Jun 26, 2024

I propose> create a popup template that based on usage has preset filters. (e.g. only issues/pulls of repo X)

and let issues search via keyword or number have it live updated... ... multiselect would be nice ... filter for closed and open

use that:

  • for adding issues/pulls in project board view to add to the project
  • adding dependencys

mockup: image

I propose> create a popup template that based on usage has preset filters. (e.g. only issues/pulls of repo X)

and let issues search via keyword or number have it live updated... ... multiselect would be nice ... filter for closed and open

use that:

  • for adding issues/pulls in project board view to add to the project
  • adding dependencys

mockup: image

I strongly believe that this is an altogether different feature request.
Please make this a different issue. The issue at hand is already complex and does not require any additional complexity.

Personally, I have a different approach in mind.
One. which will move the dependency management to below the original issue/pr "description" and right before the follow-up comments, similar to for example *ira.

@silkentrance
Copy link

silkentrance commented Jun 26, 2024

What is required here as a solution, is search by

  • Allow searching issues by ID #31479
  • any non db based indexer: fuzziness properly configured and using the proper queries on issue title
  • for db only indexer: proper like query constructs on issue title

silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 27, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 27, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 28, 2024
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 29, 2024
- Use backticks instead of double quotes

Co-authored-by: wxiaoguang <[email protected]>
silkentrance added a commit to coldrye-collaboration/gitea that referenced this issue Jun 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
issue/confirmed Issue has been reviewed and confirmed to be present or accepted to be implemented topic/ui Change the appearance of the Gitea UI type/bug
Projects
None yet