diff --git a/models/issues/issue_search.go b/models/issues/issue_search.go index 921dd9973..d46e1756c 100644 --- a/models/issues/issue_search.go +++ b/models/issues/issue_search.go @@ -36,6 +36,7 @@ type IssuesOptions struct { //nolint ProjectBoardID int64 IsClosed optional.Option[bool] IsPull optional.Option[bool] + IsDiscussion optional.Option[bool] LabelIDs []int64 IncludedLabelNames []string ExcludedLabelNames []string diff --git a/modules/indexer/issues/dboptions.go b/modules/indexer/issues/dboptions.go index 8f9408874..25e1c36d7 100644 --- a/modules/indexer/issues/dboptions.go +++ b/modules/indexer/issues/dboptions.go @@ -10,12 +10,14 @@ import ( ) func ToSearchOptions(keyword string, opts *issues_model.IssuesOptions) *SearchOptions { + searchOpt := &SearchOptions{ - Keyword: keyword, - RepoIDs: opts.RepoIDs, - AllPublic: opts.AllPublic, - IsPull: opts.IsPull, - IsClosed: opts.IsClosed, + Keyword: keyword, + RepoIDs: opts.RepoIDs, + AllPublic: opts.AllPublic, + IsPull: opts.IsPull, + IsDiscussion: opts.IsDiscussion, + IsClosed: opts.IsClosed, } if len(opts.LabelIDs) == 1 && opts.LabelIDs[0] == 0 { diff --git a/modules/indexer/issues/internal/model.go b/modules/indexer/issues/internal/model.go index e9c4eca55..aa00633d4 100644 --- a/modules/indexer/issues/internal/model.go +++ b/modules/indexer/issues/internal/model.go @@ -79,8 +79,9 @@ type SearchOptions struct { RepoIDs []int64 // repository IDs which the issues belong to AllPublic bool // if include all public repositories - IsPull optional.Option[bool] // if the issues is a pull request - IsClosed optional.Option[bool] // if the issues is closed + IsPull optional.Option[bool] // if the issues is a pull request + IsDiscussion optional.Option[bool] // if the issues is a discussion + IsClosed optional.Option[bool] // if the issues is closed IncludedLabelIDs []int64 // labels the issues have ExcludedLabelIDs []int64 // labels the issues don't have diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index afb860cfc..dba8cc8e1 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -1214,6 +1214,7 @@ find_tag = Find tag branches = Branches tags = Tags issues = Issues +discussions=Discussions pulls = Pull Requests project_board = Projects packages = Packages diff --git a/routers/web/repo/issue.go b/routers/web/repo/issue.go index 0c8363a16..eaa98f40c 100644 --- a/routers/web/repo/issue.go +++ b/routers/web/repo/issue.go @@ -141,7 +141,17 @@ func MustAllowPulls(ctx *context.Context) { } } -func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption optional.Option[bool]) { +func MustAllowDiscussions(ctx *context.Context) { + // var repositoryId = ctx.Repo.Repository.ID + // TODO: check enable discussions && check enable Read + var check = true + if !check { + ctx.NotFound("MustAllowDiscussions", nil) + return + } +} + +func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption optional.Option[bool], isDiscussionOption optional.Option[bool]) { var err error viewType := ctx.FormString("type") sortType := ctx.FormString("sort") @@ -213,6 +223,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt ReviewRequestedID: reviewRequestedID, ReviewedID: reviewedID, IsPull: isPullOption, + IsDiscussion: isDiscussionOption, IssueIDs: nil, } if keyword != "" { @@ -299,6 +310,7 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt ProjectID: projectID, IsClosed: isShowClosed, IsPull: isPullOption, + IsDiscussion: isDiscussionOption, LabelIDs: labelIDs, SortType: sortType, }) @@ -310,6 +322,8 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt ctx.Data["IssueIndexerUnavailable"] = true return } + + // TODO: GetIssuesByIDs를 디스커션도 조회하도록 만들기 issues, err = issues_model.GetIssuesByIDs(ctx, ids, true) if err != nil { ctx.ServerError("GetIssuesByIDs", err) @@ -486,9 +500,19 @@ func issues(ctx *context.Context, milestoneID, projectID int64, isPullOption opt } func issueIDsFromSearch(ctx *context.Context, keyword string, opts *issues_model.IssuesOptions) ([]int64, error) { - ids, _, err := issue_indexer.SearchIssues(ctx, issue_indexer.ToSearchOptions(keyword, opts)) - if err != nil { - return nil, fmt.Errorf("SearchIssues: %w", err) + + var searchOptions = issue_indexer.ToSearchOptions(keyword, opts) + var ids []int64 + var err error + + if !searchOptions.IsDiscussion.ValueOrDefault(false) { + ids, _, err = issue_indexer.SearchIssues(ctx, searchOptions) + if err != nil { + return nil, fmt.Errorf("SearchIssues: %w", err) + } + } else { + ids = []int64{1, 2} + // TODO: 특정 레포지토리의 디스커션의 아이디들을 반환할수 있도록 로직 작성 } return ids, nil } @@ -496,14 +520,26 @@ func issueIDsFromSearch(ctx *context.Context, keyword string, opts *issues_model // Issues render issues page func Issues(ctx *context.Context) { isPullList := ctx.Params(":type") == "pulls" + isDiscussion := ctx.Params(":type") == "discussions" + if isPullList { + // handle pull requests MustAllowPulls(ctx) if ctx.Written() { return } ctx.Data["Title"] = ctx.Tr("repo.pulls") ctx.Data["PageIsPullList"] = true + } else if isDiscussion { + // handle discussions + MustAllowDiscussions(ctx) + if ctx.Written() { + return + } + ctx.Data["Title"] = ctx.Tr("repo.discussions") + ctx.Data["PageIsDiscussionList"] = true } else { + // handle issuses MustEnableIssues(ctx) if ctx.Written() { return @@ -513,7 +549,7 @@ func Issues(ctx *context.Context) { ctx.Data["NewIssueChooseTemplate"] = issue_service.HasTemplatesOrContactLinks(ctx.Repo.Repository, ctx.Repo.GitRepo) } - issues(ctx, ctx.FormInt64("milestone"), ctx.FormInt64("project"), optional.Some(isPullList)) + issues(ctx, ctx.FormInt64("milestone"), ctx.FormInt64("project"), optional.Some(isPullList), optional.Some(isDiscussion)) if ctx.Written() { return } diff --git a/routers/web/repo/milestone.go b/routers/web/repo/milestone.go index 95a4fe60c..2d63df95c 100644 --- a/routers/web/repo/milestone.go +++ b/routers/web/repo/milestone.go @@ -292,7 +292,7 @@ func MilestoneIssuesAndPulls(ctx *context.Context) { ctx.Data["Title"] = milestone.Name ctx.Data["Milestone"] = milestone - issues(ctx, milestoneID, projectID, optional.None[bool]()) + issues(ctx, milestoneID, projectID, optional.None[bool](), optional.None[bool]()) ret := issue.ParseTemplatesFromDefaultBranch(ctx.Repo.Repository, ctx.Repo.GitRepo) ctx.Data["NewIssueChooseTemplate"] = len(ret.IssueTemplates) > 0 diff --git a/routers/web/web.go b/routers/web/web.go index 194a67bf0..82ce369d4 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -1162,7 +1162,7 @@ func registerRoutes(m *web.Route) { // end "/{username}/{reponame}": view milestone, label, issue, pull, etc m.Group("/{username}/{reponame}", func() { - m.Group("/{type:issues|pulls}", func() { + m.Group("/{type:issues|pulls|discussions}", func() { m.Get("", repo.Issues) m.Group("/{index}", func() { m.Get("", repo.ViewIssue) diff --git a/templates/repo/header.tmpl b/templates/repo/header.tmpl index 34f47b7d8..5cee28860 100644 --- a/templates/repo/header.tmpl +++ b/templates/repo/header.tmpl @@ -152,6 +152,11 @@ {{svg "octicon-link-external"}} {{ctx.Locale.Tr "repo.issues"}} {{end}} + + + + {{ svg "octicon-comment-discussion" }} {{ctx.Locale.Tr "repo.discussions"}} + {{if and .Repository.CanEnablePulls (.Permission.CanRead ctx.Consts.RepoUnitTypePullRequests)}} diff --git a/templates/repo/issue/openclose.tmpl b/templates/repo/issue/openclose.tmpl index eb2d6e09e..44d8007ed 100644 --- a/templates/repo/issue/openclose.tmpl +++ b/templates/repo/issue/openclose.tmpl @@ -4,6 +4,8 @@ {{svg "octicon-milestone" 16 "tw-mr-2"}} {{else if .PageIsPullList}} {{svg "octicon-git-pull-request" 16 "tw-mr-2"}} + {{else if .PageIsDiscussionList}} + {{svg "octicon-comment-discussion" 16 "tw-mr-2"}} {{else}} {{svg "octicon-issue-opened" 16 "tw-mr-2"}} {{end}}