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

Add the ability to pin Issues #24406

Merged
merged 54 commits into from
May 25, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e03f4cf
Add the abillity to pin Issues
JakobDev Apr 28, 2023
961a95f
Merge branch 'main' into issuepin
JakobDev Apr 28, 2023
4d1d1d8
Fix eslint errors
JakobDev Apr 28, 2023
7aea9d6
Rename Pin to PinOrder
JakobDev Apr 28, 2023
22c0687
Add X Button
JakobDev Apr 28, 2023
31804ab
Remove newline
JakobDev Apr 28, 2023
65dd702
Fix typo
JakobDev Apr 28, 2023
dfacb3f
Update templates/repo/issue/list.tmpl
silverwind Apr 29, 2023
8492384
Merge branch 'main' into issuepin
JakobDev May 2, 2023
8b84877
Changes requested by silverwind
JakobDev May 2, 2023
8c94178
Add limit for pinned Issues
JakobDev May 2, 2023
023820f
Add pin and unpin events to history
JakobDev May 2, 2023
a31a96a
Fix backend lint
JakobDev May 2, 2023
c0ffcdb
Add Migration
JakobDev May 2, 2023
f74d573
Add tests
JakobDev May 2, 2023
3ee07af
Merge branch 'main' into issuepin
JakobDev May 2, 2023
034c8a6
Rename v256.go to v257.go
JakobDev May 3, 2023
2b4eccb
Merge branch 'main' into issuepin
JakobDev May 3, 2023
0d1ccaa
Do requested changes
JakobDev May 3, 2023
abbe6e1
Merge branch 'main' into issuepin
JakobDev May 8, 2023
1704b6f
Changes requested by wxiaoguang
JakobDev May 8, 2023
4735026
Unpin Issue before deletion
JakobDev May 8, 2023
8f25b3a
Change Layout
JakobDev May 9, 2023
7880472
Merge branch 'main' into issuepin
JakobDev May 9, 2023
9afc05e
issue sidebar button fixes
silverwind May 9, 2023
688ace1
various display and html layout tweaks
silverwind May 9, 2023
61a2dc1
misc fixes
silverwind May 9, 2023
59a5691
Update templates/shared/issueicon.tmpl
silverwind May 10, 2023
8010a7a
Merge branch 'main' into issuepin
JakobDev May 12, 2023
706c6cc
Do requested changes
JakobDev May 12, 2023
3dc4746
Merge branch 'main' into issuepin
JakobDev May 12, 2023
9d38fad
Use new Unpin Icon
JakobDev May 12, 2023
03761ea
Fix Style of new Icon
JakobDev May 12, 2023
ea9df52
Merge branch 'main' into issuepin
JakobDev May 15, 2023
20356cf
Do requested changes
JakobDev May 15, 2023
cac50e0
Rename files for resolving conflicts
JakobDev May 22, 2023
630a9f1
Merge branch 'main' into issuepin
JakobDev May 22, 2023
d5edde7
Fix misstage from resolving conflicts
JakobDev May 22, 2023
cd194a1
Do requested changes
JakobDev May 22, 2023
cadaa48
Use err
JakobDev May 22, 2023
08c59de
Change default config to 3 and add Documentation
JakobDev May 22, 2023
ab35b5e
Fix merge problem
JakobDev May 22, 2023
3f32853
Update templates/repo/issue/view_content/comments.tmpl
silverwind May 22, 2023
1d098d5
Update templates/repo/issue/view_content/comments.tmpl
JakobDev May 22, 2023
d3e365a
Allow unpining even if Pins are disabled
JakobDev May 22, 2023
bce5ff1
Merge branch 'main' into issuepin
silverwind May 22, 2023
4aa9488
Merge branch 'main' into issuepin
silverwind May 22, 2023
8643224
Merge branch 'main' into issuepin
JakobDev May 23, 2023
76ea8d9
Merge branch 'main' into issuepin
silverwind May 23, 2023
caeae1b
Delete issueicon.tmpl
JakobDev May 25, 2023
e3c67cf
Merge branch 'main' into issuepin
JakobDev May 25, 2023
a4114f0
Run make generate-swagger
JakobDev May 25, 2023
e2b81e0
Merge branch 'main' into issuepin
GiteaBot May 25, 2023
36a5478
Remove outdated comment
JakobDev May 25, 2023
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
132 changes: 132 additions & 0 deletions models/issues/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ type Issue struct {
PullRequest *PullRequest `xorm:"-"`
NumComments int
Ref string
PinOrder int `xorm:"DEFAULT 0"`

DeadlineUnix timeutil.TimeStamp `xorm:"INDEX"`

Expand Down Expand Up @@ -2503,3 +2504,134 @@ func DeleteOrphanedIssues(ctx context.Context) error {
func (issue *Issue) HasOriginalAuthor() bool {
return issue.OriginalAuthor != "" && issue.OriginalAuthorID != 0
}

// IsPinned returns if a Issue is pinned
func (issue *Issue) IsPinned() bool {
return issue.PinOrder != 0
}

// Pin pins a Issue
func (issue *Issue) Pin() error {
// If the Issue is already pinned, we don't need to pin it twice
if issue.IsPinned() {
return nil
}

var maxPin int
_, err := db.GetEngine(db.DefaultContext).SQL("SELECT MAX(pin_order) FROM issue WHERE repo_id = ? AND is_pull = ?", issue.RepoID, issue.IsPull).Get(&maxPin)
if err != nil {
return err
}

_, err = db.GetEngine(db.DefaultContext).Table("issue").
Where("id = ?", issue.ID).
Update(map[string]interface{}{
"pin_order": maxPin + 1,
})

return err
}

// UnpinIssue unpins a Issue
func (issue *Issue) Unpin() error {
// If the Issue is not pinned, we don't need to unpin it
if !issue.IsPinned() {
return nil
}

// This sets the Pin for all Issues that come after the unpined Issue to the correct value
_, err := db.GetEngine(db.DefaultContext).Exec("UPDATE issue SET pin_order = pin_order - 1 WHERE repo_id = ? AND is_pull = ? AND pin_order > ?", issue.RepoID, issue.IsPull, issue.PinOrder)
if err != nil {
return err
}

_, err = db.GetEngine(db.DefaultContext).Table("issue").
Where("id = ?", issue.ID).
Update(map[string]interface{}{
"pin_order": 0,
})

return err
}

// PinOrUnpin pins or unpins a Issue
func (issue *Issue) PinOrUnpin() error {
if !issue.IsPinned() {
return issue.Pin()
}

return issue.Unpin()
}

// MovePin moves a Pinned Issue to a new Position
func (issue *Issue) MovePin(newPosition int) error {
// If the Issue is not pinned, we can't move them
if !issue.IsPinned() {
return nil
}

if newPosition < 1 {
return fmt.Errorf("The Position can't be lower than 1")
}

var (
err error
maxPin int
)

_, err = db.GetEngine(db.DefaultContext).SQL("SELECT MAX(pin_order) FROM issue WHERE repo_id = ? AND is_pull = ?", issue.RepoID, issue.IsPull).Get(&maxPin)

if err != nil {
return err
}

// If the new Position bigger than the current Maximum, set it to the Maximum
if newPosition > maxPin+1 {
newPosition = maxPin + 1
}

// TODO: Run the following commands in a Transaction and Rollback, if one fails

// Lower the Position of all Pinned Issue that came after the current Position
_, err = db.GetEngine(db.DefaultContext).Exec("UPDATE issue SET pin_order = pin_order - 1 WHERE repo_id = ? AND is_pull = ? AND pin_order > ?", issue.RepoID, issue.IsPull, issue.PinOrder)
if err != nil {
return err
}

// Higher the Position of all Pinned Issues that comes after the new Position
_, err = db.GetEngine(db.DefaultContext).Exec("UPDATE issue SET pin_order = pin_order + 1 WHERE repo_id = ? AND is_pull = ? AND pin_order >= ?", issue.RepoID, issue.IsPull, newPosition)
if err != nil {
return err
}

_, err = db.GetEngine(db.DefaultContext).Table("issue").
JakobDev marked this conversation as resolved.
Show resolved Hide resolved
Where("id = ?", issue.ID).
Update(map[string]interface{}{
"pin_order": newPosition,
})

return err
}

// GetPinnedIssues returns the pinned Issues for the given Repo and type
func GetPinnedIssues(repoID int64, isPull bool) ([]*Issue, error) {
issues := make([]*Issue, 0)

err := db.GetEngine(db.DefaultContext).
Table("issue").
Where("repo_id = ?", repoID).
And("is_pull = ?", isPull).
And("pin_order > 0").
OrderBy("pin_order").
Find(&issues)
if err != nil {
return nil, err
}

err = IssueList(issues).LoadAttributes()
if err != nil {
return nil, err
}

return issues, nil
}
2 changes: 2 additions & 0 deletions modules/structs/issue.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ type Issue struct {

PullRequest *PullRequestMeta `json:"pull_request"`
Repo *RepositoryMeta `json:"repository"`

PinOrder int `json:"pin_order"`
}

// CreateIssueOption options to create one issue
Expand Down
2 changes: 2 additions & 0 deletions modules/structs/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ type PullRequest struct {
Updated *time.Time `json:"updated_at"`
// swagger:strfmt date-time
Closed *time.Time `json:"closed_at"`

PinOrder int `json:"pin_order"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait, pinned PRs?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you can pin Pull Requests

}

// PRBranchInfo information about a branch
Expand Down
3 changes: 3 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -1463,6 +1463,9 @@ issues.attachment.open_tab = `Click to see "%s" in a new tab`
issues.attachment.download = `Click to download "%s"`
issues.subscribe = Subscribe
issues.unsubscribe = Unsubscribe
issues.pin = Pin
issues.unpin = Unpin
JakobDev marked this conversation as resolved.
Show resolved Hide resolved
issues.unpin_issue = Unpin Issue
issues.lock = Lock conversation
issues.unlock = Unlock conversation
issues.lock.unknown_reason = Cannot lock an issue with an unknown reason.
Expand Down
8 changes: 8 additions & 0 deletions routers/api/v1/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,7 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Group("/issues", func() {
m.Combo("").Get(repo.ListIssues).
Post(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.CreateIssueOption{}), repo.CreateIssue)
m.Get("/pinned", repo.ListPinnedIssues)
m.Group("/comments", func() {
m.Get("", repo.ListRepoIssueComments)
m.Group("/{id}", func() {
Expand Down Expand Up @@ -1045,6 +1046,12 @@ func Routes(ctx gocontext.Context) *web.Route {
Get(repo.GetIssueBlocks).
Post(reqToken(auth_model.AccessTokenScopeRepo), bind(api.IssueMeta{}), repo.CreateIssueBlocking).
Delete(reqToken(auth_model.AccessTokenScopeRepo), bind(api.IssueMeta{}), repo.RemoveIssueBlocking)
m.Group("/pin", func() {
m.Combo("").
Post(reqToken(auth_model.AccessTokenScopeRepo), reqAdmin(), repo.PinIssue).
Delete(reqToken(auth_model.AccessTokenScopeRepo), reqAdmin(), repo.UnpinIssue)
m.Patch("/{position}", reqToken(auth_model.AccessTokenScopeRepo), reqAdmin(), repo.MoveIssuePin)
})
})
}, mustEnableIssuesOrPulls)
m.Group("/labels", func() {
Expand Down Expand Up @@ -1107,6 +1114,7 @@ func Routes(ctx gocontext.Context) *web.Route {
m.Group("/pulls", func() {
m.Combo("").Get(repo.ListPullRequests).
Post(reqToken(auth_model.AccessTokenScopeRepo), mustNotBeArchived, bind(api.CreatePullRequestOption{}), repo.CreatePullRequest)
m.Get("/pinned", repo.ListPinnedPullRequests)
m.Group("/{index}", func() {
m.Combo("").Get(repo.GetPullRequest).
Patch(reqToken(auth_model.AccessTokenScopeRepo), bind(api.EditPullRequestOption{}), repo.EditPullRequest)
Expand Down
Loading