diff --git a/models/issues/issue_list.go b/models/issues/issue_list.go index 6ddadd27ed442..f5a73770b3d00 100644 --- a/models/issues/issue_list.go +++ b/models/issues/issue_list.go @@ -229,6 +229,15 @@ func (issues IssueList) loadMilestones(ctx context.Context) error { return nil } +func (issues IssueList) GetProjects() (pl project_model.ProjectList) { + for _, issue := range issues { + if issue.Project != nil { + pl = append(pl, issue.Project) + } + } + return pl +} + func (issues IssueList) getProjectIDs() []int64 { ids := make(container.Set[int64], len(issues)) for _, issue := range issues { diff --git a/models/project/project.go b/models/project/project.go index 931ef44675afd..e28e858f488d4 100644 --- a/models/project/project.go +++ b/models/project/project.go @@ -10,6 +10,7 @@ import ( "code.gitea.io/gitea/models/db" repo_model "code.gitea.io/gitea/models/repo" user_model "code.gitea.io/gitea/models/user" + "code.gitea.io/gitea/modules/container" "code.gitea.io/gitea/modules/log" "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/timeutil" @@ -33,6 +34,9 @@ type ( // Type is used to identify the type of project in question and ownership Type uint8 + + // ProjectList defines a list of projects + ProjectList []*Project //nolint ) const ( @@ -144,6 +148,25 @@ func (p *Project) Link() string { return "" } +// Name return the project's name which is combined with owner/repo/project's name +func (p *Project) Name() string { + if p.OwnerID > 0 { + if err := p.LoadOwner(db.DefaultContext); err != nil { + log.Error("LoadOwner: %v", err) + return "" + } + return fmt.Sprintf("%s/-/%s", p.Owner.Name, p.Title) + } + if p.RepoID > 0 { + if err := p.LoadRepo(db.DefaultContext); err != nil { + log.Error("LoadRepo: %v", err) + return "" + } + return fmt.Sprintf("%s/%s/%s", p.Repo.OwnerName, p.Repo.Name, p.Title) + } + return "" +} + func (p *Project) IsOrganizationProject() bool { return p.Type == TypeOrganization } @@ -192,20 +215,20 @@ type SearchOptions struct { func (opts *SearchOptions) toConds() builder.Cond { cond := builder.NewCond() if opts.RepoID > 0 { - cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) + cond = cond.And(builder.Eq{"project.repo_id": opts.RepoID}) } switch opts.IsClosed { case util.OptionalBoolTrue: - cond = cond.And(builder.Eq{"is_closed": true}) + cond = cond.And(builder.Eq{"project.is_closed": true}) case util.OptionalBoolFalse: - cond = cond.And(builder.Eq{"is_closed": false}) + cond = cond.And(builder.Eq{"project.is_closed": false}) } if opts.Type > 0 { - cond = cond.And(builder.Eq{"type": opts.Type}) + cond = cond.And(builder.Eq{"project.type": opts.Type}) } if opts.OwnerID > 0 { - cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) + cond = cond.And(builder.Eq{"project.owner_id": opts.OwnerID}) } return cond } @@ -216,9 +239,9 @@ func CountProjects(ctx context.Context, opts SearchOptions) (int64, error) { } // FindProjects returns a list of all projects that have been created in the repository -func FindProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, error) { +func FindProjects(ctx context.Context, opts SearchOptions) (ProjectList, int64, error) { e := db.GetEngine(ctx) - projects := make([]*Project, 0, setting.UI.IssuePagingNum) + projects := make(ProjectList, 0, setting.UI.IssuePagingNum) cond := opts.toConds() count, err := e.Where(cond).Count(new(Project)) @@ -246,6 +269,65 @@ func FindProjects(ctx context.Context, opts SearchOptions) ([]*Project, int64, e return projects, count, e.Find(&projects) } +type ProjectsTmplData struct { + ProjectRepos map[int64]*repo_model.Repository + ProjectOwners map[int64]*user_model.User +} + +func (pl ProjectList) getRepoIDs() []int64 { + ids := make(container.Set[int64], len(pl)) + for _, p := range pl { + if p.RepoID > 0 { + ids.Add(p.RepoID) + } + } + return ids.Values() +} + +func (pl ProjectList) getOwnerIDs() []int64 { + ids := make(container.Set[int64], len(pl)) + for _, p := range pl { + if p.OwnerID > 0 { + ids.Add(p.OwnerID) + } + } + return ids.Values() +} + +func GetProjectTmplData(ps ProjectList) (*ProjectsTmplData, error) { + var err error + ptd := new(ProjectsTmplData) + + ptd.ProjectRepos, err = repo_model.GetRepositoriesMapByIDs(ps.getRepoIDs()) + if err != nil { + return nil, err + } + + ptd.ProjectOwners, err = user_model.GetUsersMapByIDs(ps.getOwnerIDs()) + if err != nil { + return nil, err + } + fmt.Println(ptd) + return ptd, nil +} + +func (ptd *ProjectsTmplData) RenderFullTitle(p *Project) string { + if p.RepoID > 0 { + repo, ok := ptd.ProjectRepos[p.RepoID] + if ok { + return fmt.Sprintf("%s/%s/%s", repo.OwnerName, repo.Name, p.Title) + } + } + if p.OwnerID > 0 { + fmt.Println(ptd.ProjectOwners) + owner, ok := ptd.ProjectOwners[p.OwnerID] + if ok { + return fmt.Sprintf("%s/-/%s", owner.Name, p.Title) + } + } + return "" +} + // NewProject creates a new Project func NewProject(p *Project) error { if !IsBoardTypeValid(p.BoardType) { diff --git a/models/user/list.go b/models/user/list.go index 6b3b7bea9ad38..386ea78c8b6e0 100644 --- a/models/user/list.go +++ b/models/user/list.go @@ -81,3 +81,9 @@ func GetUsersByIDs(ids []int64) (UserList, error) { Find(&ous) return ous, err } + +// GetUsersMapByIDs returns all resolved users from a list of Ids. +func GetUsersMapByIDs(ids []int64) (map[int64]*User, error) { + usm := make(map[int64]*User, len(ids)) + return usm, db.GetEngine(db.DefaultContext).In("id", ids).Find(&usm) +} diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 05ba26a70cda6..4fc75086b4628 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -379,11 +379,19 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption uti return 0 } - retrieveProjects(ctx, repo) + ps := retrieveProjects(ctx, repo) if ctx.Written() { return } + // Get ProjectTmplData + ps = append(ps, issueList.GetProjects()...) + ctx.Data["ProjectTmplData"], err = project_model.GetProjectTmplData(ps) + if err != nil { + ctx.ServerError("GetProjectTmplData", err) + return + } + ctx.Data["IssueStats"] = issueStats ctx.Data["SelLabelIDs"] = labelIDs ctx.Data["SelectLabels"] = selectLabels @@ -483,53 +491,55 @@ func RetrieveRepoMilestonesAndAssignees(ctx *context.Context, repo *repo_model.R handleTeamMentions(ctx) } -func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) { +func retrieveProjects(ctx *context.Context, repo *repo_model.Repository) project_model.ProjectList { var err error - projects, _, err := project_model.FindProjects(ctx, project_model.SearchOptions{ + ops, _, err := project_model.FindProjects(ctx, project_model.SearchOptions{ RepoID: repo.ID, Page: -1, IsClosed: util.OptionalBoolFalse, Type: project_model.TypeRepository, }) if err != nil { - ctx.ServerError("GetProjects", err) - return + ctx.ServerError("FindProjects", err) + return nil } - projects2, _, err := project_model.FindProjects(ctx, project_model.SearchOptions{ + ops2, _, err := project_model.FindProjects(ctx, project_model.SearchOptions{ OwnerID: repo.OwnerID, Page: -1, IsClosed: util.OptionalBoolFalse, Type: project_model.TypeOrganization, }) if err != nil { - ctx.ServerError("GetProjects", err) - return + ctx.ServerError("FindProjects", err) + return nil } + ops = append(ops, ops2...) + ctx.Data["OpenProjects"] = ops - ctx.Data["OpenProjects"] = append(projects, projects2...) - - projects, _, err = project_model.FindProjects(ctx, project_model.SearchOptions{ + cps, _, err := project_model.FindProjects(ctx, project_model.SearchOptions{ RepoID: repo.ID, Page: -1, IsClosed: util.OptionalBoolTrue, Type: project_model.TypeRepository, }) if err != nil { - ctx.ServerError("GetProjects", err) - return + ctx.ServerError("FindProjects", err) + return nil } - projects2, _, err = project_model.FindProjects(ctx, project_model.SearchOptions{ + cps2, _, err := project_model.FindProjects(ctx, project_model.SearchOptions{ OwnerID: repo.OwnerID, Page: -1, IsClosed: util.OptionalBoolTrue, Type: project_model.TypeOrganization, }) if err != nil { - ctx.ServerError("GetProjects", err) - return + ctx.ServerError("FindProjects", err) + return nil } + cps = append(cps, cps2...) + ctx.Data["ClosedProjects"] = cps - ctx.Data["ClosedProjects"] = append(projects, projects2...) + return append(ops, cps...) } // repoReviewerSelection items to bee shown @@ -750,10 +760,15 @@ func RetrieveRepoMetas(ctx *context.Context, repo *repo_model.Repository, isPull return nil } - retrieveProjects(ctx, repo) + ps := retrieveProjects(ctx, repo) if ctx.Written() { return nil } + ctx.Data["ProjectTmplData"], err = project_model.GetProjectTmplData(ps) + if err != nil { + ctx.ServerError("GetProjectTmplData", err) + return nil + } brs, _, err := ctx.Repo.GitRepo.GetBranchNames(0, 0) if err != nil { @@ -1376,13 +1391,20 @@ func ViewIssue(ctx *context.Context) { ctx.Data["HasSelectedLabel"] = hasSelected // Check milestone and assignee. + var ps project_model.ProjectList if ctx.Repo.CanWriteIssuesOrPulls(issue.IsPull) { RetrieveRepoMilestonesAndAssignees(ctx, repo) - retrieveProjects(ctx, repo) - + ps = retrieveProjects(ctx, repo) if ctx.Written() { return } + + } + + ctx.Data["ProjectTmplData"], err = project_model.GetProjectTmplData(append(ps, issue.Project)) + if err != nil { + ctx.ServerError("GetProjectTmplData", err) + return } if issue.IsPull { diff --git a/routers/web/user/home.go b/routers/web/user/home.go index 4f45c1d5c3149..41c105a891cf9 100644 --- a/routers/web/user/home.go +++ b/routers/web/user/home.go @@ -18,6 +18,7 @@ import ( "code.gitea.io/gitea/models/db" issues_model "code.gitea.io/gitea/models/issues" "code.gitea.io/gitea/models/organization" + project_model "code.gitea.io/gitea/models/project" repo_model "code.gitea.io/gitea/models/repo" "code.gitea.io/gitea/models/unit" user_model "code.gitea.io/gitea/models/user" @@ -609,6 +610,13 @@ func buildIssueOverview(ctx *context.Context, unitType unit.Type) { ctx.Data["Issues"] = issues + projects := issues_model.IssueList(issues).GetProjects() + ctx.Data["ProjectTmplData"], err = project_model.GetProjectTmplData(projects) + if err != nil { + ctx.ServerError("GetProjectTmplData", err) + return + } + approvalCounts, err := issues_model.IssueList(issues).GetApprovalCounts(ctx) if err != nil { ctx.ServerError("ApprovalCounts", err) diff --git a/templates/repo/issue/list.tmpl b/templates/repo/issue/list.tmpl index 2b1bea822fbf0..570e60fa762fb 100644 --- a/templates/repo/issue/list.tmpl +++ b/templates/repo/issue/list.tmpl @@ -101,7 +101,7 @@ {{range .OpenProjects}} {{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "gt-mr-3"}}{{else}}{{svg "octicon-project" 18 "gt-mr-3"}}{{end}} - {{.Title}} + {{$.ProjectTmplData.RenderFullTitle .}} {{end}} {{end}} @@ -113,7 +113,7 @@ {{range .ClosedProjects}} {{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "gt-mr-3"}}{{else}}{{svg "octicon-project" 18 "gt-mr-3"}}{{end}} - {{.Title}} + {{$.ProjectTmplData.RenderFullTitle .}} {{end}} {{end}} @@ -273,7 +273,7 @@ {{range .OpenProjects}}
{{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "gt-mr-3"}}{{else}}{{svg "octicon-project" 18 "gt-mr-3"}}{{end}} - {{.Title}} + {{$.ProjectTmplData.RenderFullTitle .}}
{{end}} {{end}} @@ -285,7 +285,7 @@ {{range .ClosedProjects}}
{{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "gt-mr-3"}}{{else}}{{svg "octicon-project" 18 "gt-mr-3"}}{{end}} - {{.Title}} + {{$.ProjectTmplData.RenderFullTitle .}}
{{end}} {{end}} diff --git a/templates/repo/issue/new_form.tmpl b/templates/repo/issue/new_form.tmpl index 8346d07a13c66..74135a78425d1 100644 --- a/templates/repo/issue/new_form.tmpl +++ b/templates/repo/issue/new_form.tmpl @@ -176,9 +176,9 @@ {{.locale.Tr "repo.issues.new.open_projects"}} {{range .OpenProjects}} - + {{svg "octicon-project" 18 "gt-mr-3"}} - {{.Title}} + {{$.ProjectTmplData.RenderFullTitle .}} {{end}} {{end}} @@ -188,9 +188,9 @@ {{.locale.Tr "repo.issues.new.closed_projects"}} {{range .ClosedProjects}} - + {{svg "octicon-project" 18 "gt-mr-3"}} - {{.Title}} + {{$.ProjectTmplData.RenderFullTitle .}} {{end}} {{end}} diff --git a/templates/repo/issue/view_content/comments.tmpl b/templates/repo/issue/view_content/comments.tmpl index b81c3c7f0351b..9ee9dc8e9150b 100644 --- a/templates/repo/issue/view_content/comments.tmpl +++ b/templates/repo/issue/view_content/comments.tmpl @@ -720,12 +720,12 @@ {{template "shared/user/authorlink" .Poster}} {{if gt .OldProjectID 0}} {{if gt .ProjectID 0}} - {{$.locale.Tr "repo.issues.change_project_at" (.OldProject.Title|Escape) (.Project.Title|Escape) $createdStr | Safe}} + {{$.locale.Tr "repo.issues.change_project_at" (.OldProject.Name|Escape) (.Project.Name|Escape) $createdStr | Safe}} {{else}} - {{$.locale.Tr "repo.issues.remove_project_at" (.OldProject.Title|Escape) $createdStr | Safe}} + {{$.locale.Tr "repo.issues.remove_project_at" (.OldProject.Name|Escape) $createdStr | Safe}} {{end}} {{else if gt .ProjectID 0}} - {{$.locale.Tr "repo.issues.add_project_at" (.Project.Title|Escape) $createdStr | Safe}} + {{$.locale.Tr "repo.issues.add_project_at" (.Project.Name|Escape) $createdStr | Safe}} {{end}} diff --git a/templates/repo/issue/view_content/sidebar.tmpl b/templates/repo/issue/view_content/sidebar.tmpl index 2b24825b5f7bd..2189d10ca9d7c 100644 --- a/templates/repo/issue/view_content/sidebar.tmpl +++ b/templates/repo/issue/view_content/sidebar.tmpl @@ -240,7 +240,7 @@ {{range .OpenProjects}} {{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "gt-mr-3"}}{{else}}{{svg "octicon-project" 18 "gt-mr-3"}}{{end}} - {{.Title}} + {{$.ProjectTmplData.RenderFullTitle .}} {{end}} {{end}} @@ -250,9 +250,9 @@ {{.locale.Tr "repo.issues.new.closed_projects"}} {{range .ClosedProjects}} - - {{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "gt-mr-3"}}{{else}}{{svg "octicon-project" 18 "gt-mr-3"}}{{end}} - {{.Title}} + + {{if .Project.IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "gt-mr-3"}}{{else}}{{svg "octicon-project" 18 "gt-mr-3"}}{{end}} + {{$.ProjectTmplData.RenderFullTitle .}} {{end}} {{end}} @@ -263,8 +263,8 @@
{{if .Issue.ProjectID}} - {{if .IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "gt-mr-3"}}{{else}}{{svg "octicon-project" 18 "gt-mr-3"}}{{end}} - {{.Issue.Project.Title}} + {{if .Issue.Project.IsOrganizationProject}}{{svg "octicon-project-symlink" 18 "gt-mr-3"}}{{else}}{{svg "octicon-project" 18 "gt-mr-3"}}{{end}} + {{$.ProjectTmplData.RenderFullTitle .Issue.Project}} {{end}}
diff --git a/templates/shared/issuelist.tmpl b/templates/shared/issuelist.tmpl index a43047c79de91..a59ba65f0c55b 100644 --- a/templates/shared/issuelist.tmpl +++ b/templates/shared/issuelist.tmpl @@ -87,8 +87,8 @@ {{end}} {{if .Project}} - - {{svg "octicon-project" 14 "gt-mr-2"}}{{.Project.Title}} + + {{svg "octicon-project" 14 "gt-mr-2"}}{{$.ProjectTmplData.RenderFullTitle .Project}} {{end}} {{if .Ref}}