Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 67 additions & 4 deletions routers/web/org/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,12 +332,22 @@ func ViewProject(ctx *context.Context) {
return
}
assigneeID := ctx.FormString("assignee")
milestoneID := ctx.FormInt64("milestone")

// Prepare milestone IDs for filtering
var milestoneIDs []int64
if milestoneID > 0 {
milestoneIDs = []int64{milestoneID}
} else if milestoneID == -1 {
milestoneIDs = []int64{db.NoConditionID}
}

opts := issues_model.IssuesOptions{
LabelIDs: preparedLabelFilter.SelectedLabelIDs,
AssigneeID: assigneeID,
Owner: project.Owner,
Doer: ctx.Doer,
LabelIDs: preparedLabelFilter.SelectedLabelIDs,
AssigneeID: assigneeID,
MilestoneIDs: milestoneIDs,
Owner: project.Owner,
Doer: ctx.Doer,
}
Comment thread
josetduarte marked this conversation as resolved.
Comment thread
josetduarte marked this conversation as resolved.

Comment thread
josetduarte marked this conversation as resolved.
Outdated
issuesMap, err := project_service.LoadIssuesFromProject(ctx, project, &opts)
Expand Down Expand Up @@ -411,6 +421,59 @@ func ViewProject(ctx *context.Context) {
ctx.Data["Labels"] = labels
ctx.Data["NumLabels"] = len(labels)

// Get milestones for filtering
// For organization projects, we need to get milestones from all repos the user has access to
var milestones []*issues_model.Milestone
if project.RepoID > 0 {
// Repo-specific project
milestones, err = db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
RepoID: project.RepoID,
})
Comment thread
josetduarte marked this conversation as resolved.
if err != nil {
ctx.ServerError("GetRepoMilestones", err)
return
}
} else {
// Organization-wide project - get milestones from all organization repos
// Get repos owned by the organization
repos, _, err := attachment_model.GetUserRepositories(ctx, attachment_model.SearchRepoOptions{
Actor: project.Owner,
Private: true,
OwnerID: project.OwnerID,
})
Comment thread
josetduarte marked this conversation as resolved.
Outdated
if err != nil {
ctx.ServerError("GetUserRepositories", err)
return
}

repoIDs := make([]int64, 0, len(repos))
for _, repo := range repos {
repoIDs = append(repoIDs, repo.ID)
}

Comment thread
josetduarte marked this conversation as resolved.
Outdated
if len(repoIDs) > 0 {
milestones, err = db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
RepoIDs: repoIDs,
})
if err != nil {
ctx.ServerError("GetOrgMilestones", err)
return
}
}
}

openMilestones, closedMilestones := issues_model.MilestoneList{}, issues_model.MilestoneList{}
for _, milestone := range milestones {
if milestone.IsClosed {
closedMilestones = append(closedMilestones, milestone)
} else {
openMilestones = append(openMilestones, milestone)
}
}
ctx.Data["OpenMilestones"] = openMilestones
ctx.Data["ClosedMilestones"] = closedMilestones
ctx.Data["MilestoneID"] = milestoneID

// Get assignees.
assigneeUsers, err := org_model.GetOrgAssignees(ctx, project.OwnerID)
if err != nil {
Expand Down
36 changes: 33 additions & 3 deletions routers/web/repo/projects.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,11 +313,20 @@ func ViewProject(ctx *context.Context) {
preparedLabelFilter := issue.PrepareFilterIssueLabels(ctx, ctx.Repo.Repository.ID, ctx.Repo.Owner)
Comment thread
josetduarte marked this conversation as resolved.

assigneeID := ctx.FormString("assignee")
milestoneID := ctx.FormInt64("milestone")

var milestoneIDs []int64
if milestoneID > 0 {
milestoneIDs = []int64{milestoneID}
} else if milestoneID == -1 {
Comment thread
josetduarte marked this conversation as resolved.
Outdated
milestoneIDs = []int64{db.NoConditionID}
}

issuesMap, err := project_service.LoadIssuesFromProject(ctx, project, &issues_model.IssuesOptions{
RepoIDs: []int64{ctx.Repo.Repository.ID},
LabelIDs: preparedLabelFilter.SelectedLabelIDs,
AssigneeID: assigneeID,
RepoIDs: []int64{ctx.Repo.Repository.ID},
LabelIDs: preparedLabelFilter.SelectedLabelIDs,
AssigneeID: assigneeID,
MilestoneIDs: milestoneIDs,
})
Comment thread
josetduarte marked this conversation as resolved.
if err != nil {
ctx.ServerError("LoadIssuesOfColumns", err)
Expand Down Expand Up @@ -408,6 +417,27 @@ func ViewProject(ctx *context.Context) {
ctx.Data["Assignees"] = shared_user.MakeSelfOnTop(ctx.Doer, assigneeUsers)
ctx.Data["AssigneeID"] = assigneeID

// Get milestones
milestones, err := db.Find[issues_model.Milestone](ctx, issues_model.FindMilestoneOptions{
RepoID: ctx.Repo.Repository.ID,
})
if err != nil {
Comment thread
josetduarte marked this conversation as resolved.
Outdated
ctx.ServerError("GetMilestones", err)
return
}

openMilestones, closedMilestones := issues_model.MilestoneList{}, issues_model.MilestoneList{}
for _, milestone := range milestones {
if milestone.IsClosed {
closedMilestones = append(closedMilestones, milestone)
} else {
openMilestones = append(openMilestones, milestone)
}
}
ctx.Data["OpenMilestones"] = openMilestones
ctx.Data["ClosedMilestones"] = closedMilestones
ctx.Data["MilestoneID"] = milestoneID

rctx := renderhelper.NewRenderContextRepoComment(ctx, ctx.Repo.Repository)
project.RenderedContent, err = markdown.RenderString(rctx, project.Description)
if err != nil {
Expand Down
38 changes: 37 additions & 1 deletion templates/projects/view.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<h2>{{.Project.Title}}</h2>
<div class="tw-flex-1"></div>
<div class="ui secondary menu tw-m-0">
{{$queryLink := QueryBuild "?" "labels" .SelectLabels "assignee" $.AssigneeID "archived_labels" (Iif $.ShowArchivedLabels "true")}}
{{$queryLink := QueryBuild "?" "labels" .SelectLabels "assignee" $.AssigneeID "milestone" $.MilestoneID "archived_labels" (Iif $.ShowArchivedLabels "true")}}
{{template "repo/issue/filter_item_label" dict "Labels" .Labels "QueryLink" $queryLink "SupportArchivedLabel" true}}
{{template "repo/issue/filter_item_user_assign" dict
"QueryParamKey" "assignee"
Expand All @@ -16,6 +16,42 @@
"TextFilterMatchNone" (ctx.Locale.Tr "repo.issues.filter_assignee_no_assignee")
"TextFilterMatchAny" (ctx.Locale.Tr "repo.issues.filter_assignee_any_assignee")
}}
<!-- Milestone -->
<div class="item ui dropdown jump {{if not (or .OpenMilestones .ClosedMilestones)}}disabled{{end}}">
<span class="text">
{{ctx.Locale.Tr "repo.issues.filter_milestone"}}
</span>
{{svg "octicon-triangle-down" 14 "dropdown icon"}}
<div class="menu">
<div class="ui icon search input">
<i class="icon">{{svg "octicon-search" 16}}</i>
<input type="text" placeholder="{{ctx.Locale.Tr "repo.issues.filter_milestone"}}">
</div>
<div class="divider"></div>
<a class="{{if not $.MilestoneID}}active selected {{end}}item" href="{{QueryBuild $queryLink "milestone" NIL}}">{{ctx.Locale.Tr "repo.issues.filter_milestone_all"}}</a>
<a class="{{if eq $.MilestoneID -1}}active selected {{end}}item" href="{{QueryBuild $queryLink "milestone" -1}}">{{ctx.Locale.Tr "repo.issues.filter_milestone_none"}}</a>
{{if .OpenMilestones}}
<div class="divider"></div>
<div class="header">{{ctx.Locale.Tr "repo.issues.filter_milestone_open"}}</div>
{{range .OpenMilestones}}
<a class="{{if eq $.MilestoneID .ID}}active selected {{end}}item" href="{{QueryBuild $queryLink "milestone" .ID}}">
{{svg "octicon-milestone" 16 "mr-2"}}
{{.Name}}
</a>
{{end}}
{{end}}
{{if .ClosedMilestones}}
<div class="divider"></div>
<div class="header">{{ctx.Locale.Tr "repo.issues.filter_milestone_closed"}}</div>
{{range .ClosedMilestones}}
<a class="{{if eq $.MilestoneID .ID}}active selected {{end}}item" href="{{QueryBuild $queryLink "milestone" .ID}}">
{{svg "octicon-milestone" 16 "mr-2"}}
{{.Name}}
</a>
{{end}}
{{end}}
</div>
Comment thread
josetduarte marked this conversation as resolved.
Outdated
</div>
</div>
{{if $canWriteProject}}
<div class="ui compact mini menu">
Expand Down
Loading