-
-
Notifications
You must be signed in to change notification settings - Fork 5.8k
Allow to mark files in a PR as viewed #19007
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
Merged
Merged
Changes from 58 commits
Commits
Show all changes
60 commits
Select commit
Hold shift + click to select a range
2754203
Extract file folding into its own function
delvh eb22ccb
Add automatic frontend file folding on load
delvh 20791c7
Add "Viewed" checkbox and "Already changed" label in the frontend
delvh 0574ee9
Remove unneeded function
delvh e24b55c
Finish frontend completely except for sending the event to the backend
delvh 35afb82
Inform the server about view changes - frontend is now complete
delvh 59f945d
Persist PR Reviews in the database
delvh f23d8c7
Add (yet untested) complete functionality
delvh e4c8d36
Set PageData data for the frontend
delvh 8d11769
Move GetUserSpecificDiff into services as originally planned
delvh 0a634dd
Various visual improvements
delvh 72d59de
Fix all critical errors - works now
delvh 5b254b8
Fix bug showing viewed file visually
delvh bd95a12
Lint code
delvh 536b956
Move pr review into models/pulls and add listener for dynamically loa…
delvh 4aa207c
Move error check in the correct location
delvh 9f068e7
Lint code
delvh 7379510
Update models/migrations/migrations.go
delvh dc4c3c4
Fix update logic resulting in huge performance boost and simulate form
delvh 13b1a82
Remove redundant selector
delvh d579daa
Next attempt at fixing the update logic - this time I'm optimistic
delvh fdb4bd0
Format code
delvh 411da2e
Remove "Has Changed" Label when the file is marked as viewed
delvh 6728aed
Lint Code (again)
delvh 42517c4
Sanitize files containing a \" at the cost of those containing "%22"
delvh c8e68d0
Add missing case when updating
delvh 7fde944
Update number of viewed files on dynamic file loading
delvh 336de98
Fix incorrect calculation of number of viewed files
delvh 1d78ff3
Improve updating performance
delvh 5fe0234
Apply suggestions
delvh 73775ec
Apply suggestions from code review
delvh 0713d1d
Merge branch 'main' into viewed-files
6543 7be9000
Apply suggestions from code review
delvh 9b03c63
Merge branch 'master' into viewed-files
6543 0f929dd
Keep "Has Changed" Label until the file has been viewed explicitly
delvh aa6e879
Merge branch 'main' into viewed-files
6543 7a95857
Restore compilability, add default value for PR IDs, cleanup code a bit
delvh 5d24624
Apply suggestions, refactor variable name, add not-null constraint an…
delvh d87700c
Add more logging
delvh b38c7b7
use optional chaining, fix bug introduced in previous commit
delvh 2059b0b
Merge branch 'main' into viewed-files
delvh 4365447
Merge branch 'main' into viewed-files
6543 4f8aab0
Merge branch 'main' into viewed-files
delvh 7ccf2e4
Merge branch 'main' into viewed-files
delvh 0f36756
Use OOP update-review approach instead of loop-parsing
delvh 1a2288e
Apply suggestions
delvh 300254a
Merge branch 'main' into viewed-files
delvh a840ec1
Fix typo
delvh 4cedc7d
Define styleclasses at the correct location
delvh aef5056
Merge branch 'main' into viewed-files
delvh 6aca232
Fix lint?
delvh 2ee241f
Merge branch 'main' into viewed-files
6543 243b824
Fix bug disallowing seeing changed files in PRs from forks
delvh 7d59180
Merge branch 'main' into viewed-files
delvh 90d5417
Move package models/pulls to models/pull
delvh e0f9dd6
Fix lint
delvh f618ce0
Merge branch 'main' into viewed-files
delvh 9acfe6f
Merge branch 'main' into viewed-files
6543 758dfa7
Merge branch 'master' into viewed-files
6543 18c4913
LONGTEXT
6543 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
// Copyright 2022 The Gitea Authors. All rights reserved. | ||
// Use of this source code is governed by a MIT-style | ||
// license that can be found in the LICENSE file. | ||
|
||
package migrations | ||
|
||
import ( | ||
"code.gitea.io/gitea/models/pull" | ||
"code.gitea.io/gitea/modules/timeutil" | ||
|
||
"xorm.io/xorm" | ||
) | ||
|
||
func addReviewViewedFiles(x *xorm.Engine) error { | ||
type ReviewState struct { | ||
ID int64 `xorm:"pk autoincr"` | ||
UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"` | ||
PullID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user) DEFAULT 0"` | ||
CommitSHA string `xorm:"NOT NULL VARCHAR(40) UNIQUE(pull_commit_user)"` | ||
UpdatedFiles map[string]pull.ViewedState `xorm:"NOT NULL TEXT JSON"` | ||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` | ||
} | ||
|
||
return x.Sync2(new(ReviewState)) | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
// Copyright 2022 The Gitea Authors. All rights reserved. | ||
// Use of this source code is governed by a MIT-style | ||
// license that can be found in the LICENSE file. | ||
package pull | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"code.gitea.io/gitea/models/db" | ||
"code.gitea.io/gitea/modules/log" | ||
"code.gitea.io/gitea/modules/timeutil" | ||
) | ||
|
||
// ViewedState stores for a file in which state it is currently viewed | ||
type ViewedState uint8 | ||
|
||
const ( | ||
Unviewed ViewedState = iota | ||
HasChanged // cannot be set from the UI/ API, only internally | ||
Viewed | ||
) | ||
|
||
func (viewedState ViewedState) String() string { | ||
switch viewedState { | ||
case Unviewed: | ||
return "unviewed" | ||
case HasChanged: | ||
return "has-changed" | ||
case Viewed: | ||
return "viewed" | ||
default: | ||
return fmt.Sprintf("unknown(value=%d)", viewedState) | ||
} | ||
} | ||
|
||
// ReviewState stores for a user-PR-commit combination which files the user has already viewed | ||
type ReviewState struct { | ||
ID int64 `xorm:"pk autoincr"` | ||
UserID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user)"` | ||
PullID int64 `xorm:"NOT NULL UNIQUE(pull_commit_user) DEFAULT 0"` // Which PR was the review on? | ||
CommitSHA string `xorm:"NOT NULL VARCHAR(40) UNIQUE(pull_commit_user)"` // Which commit was the head commit for the review? | ||
UpdatedFiles map[string]ViewedState `xorm:"NOT NULL TEXT JSON"` // Stores for each of the changed files of a PR whether they have been viewed, changed since last viewed, or not viewed | ||
UpdatedUnix timeutil.TimeStamp `xorm:"updated"` // Is an accurate indicator of the order of commits as we do not expect it to be possible to make reviews on previous commits | ||
} | ||
|
||
func init() { | ||
db.RegisterModel(new(ReviewState)) | ||
} | ||
|
||
// GetReviewState returns the ReviewState with all given values prefilled, whether or not it exists in the database. | ||
// If the review didn't exist before in the database, it won't afterwards either. | ||
// The returned boolean shows whether the review exists in the database | ||
func GetReviewState(ctx context.Context, userID, pullID int64, commitSHA string) (*ReviewState, bool, error) { | ||
review := &ReviewState{UserID: userID, PullID: pullID, CommitSHA: commitSHA} | ||
has, err := db.GetEngine(ctx).Get(review) | ||
return review, has, err | ||
} | ||
|
||
// UpdateReviewState updates the given review inside the database, regardless of whether it existed before or not | ||
// The given map of files with their viewed state will be merged with the previous review, if present | ||
func UpdateReviewState(ctx context.Context, userID, pullID int64, commitSHA string, updatedFiles map[string]ViewedState) error { | ||
log.Trace("Updating review for user %d, repo %d, commit %s with the updated files %v.", userID, pullID, commitSHA, updatedFiles) | ||
|
||
review, exists, err := GetReviewState(ctx, userID, pullID, commitSHA) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if exists { | ||
review.UpdatedFiles = mergeFiles(review.UpdatedFiles, updatedFiles) | ||
} else if previousReview, err := getNewestReviewStateApartFrom(ctx, userID, pullID, commitSHA); err != nil { | ||
return err | ||
|
||
// Overwrite the viewed files of the previous review if present | ||
} else if previousReview != nil { | ||
review.UpdatedFiles = mergeFiles(previousReview.UpdatedFiles, updatedFiles) | ||
} else { | ||
review.UpdatedFiles = updatedFiles | ||
} | ||
|
||
// Insert or Update review | ||
engine := db.GetEngine(ctx) | ||
if !exists { | ||
log.Trace("Inserting new review for user %d, repo %d, commit %s with the updated files %v.", userID, pullID, commitSHA, review.UpdatedFiles) | ||
_, err := engine.Insert(review) | ||
return err | ||
} | ||
log.Trace("Updating already existing review with ID %d (user %d, repo %d, commit %s) with the updated files %v.", review.ID, userID, pullID, commitSHA, review.UpdatedFiles) | ||
_, err = engine.ID(review.ID).Update(&ReviewState{UpdatedFiles: review.UpdatedFiles}) | ||
return err | ||
} | ||
|
||
// mergeFiles merges the given maps of files with their viewing state into one map. | ||
// Values from oldFiles will be overridden with values from newFiles | ||
func mergeFiles(oldFiles, newFiles map[string]ViewedState) map[string]ViewedState { | ||
if oldFiles == nil { | ||
return newFiles | ||
} else if newFiles == nil { | ||
return oldFiles | ||
} | ||
|
||
for file, viewed := range newFiles { | ||
oldFiles[file] = viewed | ||
} | ||
return oldFiles | ||
} | ||
|
||
// GetNewestReviewState gets the newest review of the current user in the current PR. | ||
// The returned PR Review will be nil if the user has not yet reviewed this PR. | ||
func GetNewestReviewState(ctx context.Context, userID, pullID int64) (*ReviewState, error) { | ||
var review ReviewState | ||
has, err := db.GetEngine(ctx).Where("user_id = ?", userID).And("pull_id = ?", pullID).OrderBy("updated_unix DESC").Get(&review) | ||
if err != nil || !has { | ||
return nil, err | ||
} | ||
return &review, err | ||
} | ||
|
||
// getNewestReviewStateApartFrom is like GetNewestReview, except that the second newest review will be returned if the newest review points at the given commit. | ||
// The returned PR Review will be nil if the user has not yet reviewed this PR. | ||
func getNewestReviewStateApartFrom(ctx context.Context, userID, pullID int64, commitSHA string) (*ReviewState, error) { | ||
var reviews []ReviewState | ||
err := db.GetEngine(ctx).Where("user_id = ?", userID).And("pull_id = ?", pullID).OrderBy("updated_unix DESC").Limit(2).Find(&reviews) | ||
// It would also be possible to use ".And("commit_sha != ?", commitSHA)" instead of the error handling below | ||
// However, benchmarks show drastically improved performance by not doing that | ||
|
||
// Error cases in which no review should be returned | ||
if err != nil || len(reviews) == 0 || (len(reviews) == 1 && reviews[0].CommitSHA == commitSHA) { | ||
return nil, err | ||
|
||
// The first review points at the commit to exclude, hence skip to the second review | ||
} else if len(reviews) >= 2 && reviews[0].CommitSHA == commitSHA { | ||
return &reviews[1], nil | ||
} | ||
|
||
// As we have no error cases left, the result must be the first element in the list | ||
return &reviews[0], nil | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.