Fix caching bugs with comments in inline review UIs.

Review Request #14555 — Created Aug. 5, 2025 and submitted

Information

Review Board
release-7.1.x

Reviewers

When review UIs for binary files are rendered in "inline" mode as part
of the diff viewer, the serialized comments are included in the rendered
fragment (as opposed to comments on regular diff files, which are all
included as part of the main diff viewer page). Our ETag calculation
wasn't taking this into account, which meant that after making changes
to comments (adding, removing, editing), reloading the diff viewer could
show outdated comments coming from the browser cache.

This change reworks the fragment view to include all comment timestamps
in the ETag when the filediff in question is binary. We had an existing,
similar example in CommentDiffFragmentsView that included the latest
timestamp in the ETag, but this is broken in the case where comments are
deleted or edited on a pending review. I've changed that to include the
same behavior of including all comment timestamps rather than just the
latest.

A couple new tests have been added to verify the cache response
behavior.

  • Ran unit tests.
  • Verified that comments on binary files in the diff viewer no longer
    presented with outdated browser cache bugs.
Summary ID
Fix caching bugs with comments in inline review UIs.
When review UIs for binary files are rendered in "inline" mode as part of the diff viewer, the serialized comments are included in the rendered fragment (as opposed to comments on regular diff files, which are all included as part of the main diff viewer page). Our ETag calculation wasn't taking this into account, which meant that after making changes to comments (adding, removing, editing), reloading the diff viewer could show outdated comments coming from the browser cache. This change reworks the fragment view to include all comment timestamps in the ETag when the filediff in question is binary. We had an existing, similar example in `CommentDiffFragmentsView` that included the *latest* timestamp in the ETag, but this is broken in the case where comments are deleted or edited on a pending review. I've changed that to include the same behavior of including all comment timestamps rather than just the latest. A couple new tests have been added to verify the cache response behavior. Testing Done: - Ran unit tests. - Verified that comments on binary files in the diff viewer no longer presented with outdated browser cache bugs.
0c5ce38f202beeb5e547164ef1f1c2dcba19cca1
Description From Last Updated

continuation line under-indented for visual indent Column: 21 Error code: E128

reviewbotreviewbot

I think this should go away. We just raise errors instead of returning a HttpResponse, and we don't have HttpResponse …

maubinmaubin

This is still the same description as the previous test.

maubinmaubin

A preceding r was added here.

maubinmaubin

This should say diff comments instead of just diff

maubinmaubin

We could have a comments variable and set self.comments to that, so that we don't have to keep accessing self.comments …

maubinmaubin

Can we add a "Raises" section in the docs for this.

maubinmaubin

This should go away too.

maubinmaubin

This argument hasn't been added to the function definition, it gets pulled out of kwargs.

maubinmaubin

Can we add a "Raises" section in the docs for this.

maubinmaubin

During deprecation, new arguments must go on the end so that the decorator can do the right thing. It matches …

chipx86chipx86

Description needs to be indented 1.

chipx86chipx86

Description needs to be indented 1.

chipx86chipx86

What do you think about adding a manager method for this, so we can keep these queries in one place? …

chipx86chipx86

Might be nicer as: modified_review_ui_class: ( type[ReviewUI[Any, Any, Any]] | None ) = None,

chipx86chipx86

Can we say "Return"? "Get" doesn't imply the result, just that it's getting something.

chipx86chipx86

This needs a "Version Added"

maubinmaubin

What about super users who can access the comments?

maubinmaubin

Since we're wrapping, this should be one per line.

chipx86chipx86

Double-backticks around the parameter name.

chipx86chipx86

Missing , optional.

chipx86chipx86

Not a new problem, but noticing it now: We're passing arguments in positional form to a localized string, which won't …

chipx86chipx86

Double backticks around request.

chipx86chipx86

Swap these (alphabetical order).

chipx86chipx86

Add double-backticks around request.

chipx86chipx86

Can just be 7.1 to match the others.

chipx86chipx86
Checks run (1 failed, 1 succeeded)
flake8 failed.
JSHint passed.

flake8

david
maubin
  1. Thanks for fixing this :D.

  2. reviewboard/diffviewer/views.py (Diff revision 2)
     
     
     
    Show all issues

    I think this should go away. We just raise errors instead of returning a HttpResponse, and we don't have HttpResponse as a return type on the method.

  3. Show all issues

    This is still the same description as the previous test.

  4. reviewboard/reviews/views/diff_fragments.py (Diff revision 2)
     
     
     
     
     
     
     
     
     
     
    Show all issues

    We could have a comments variable and set self.comments to that, so that we don't have to keep accessing self.comments every time.

  5. Show all issues

    Can we add a "Raises" section in the docs for this.

  6. reviewboard/reviews/views/diff_fragments.py (Diff revision 2)
     
     
     
    Show all issues

    This should go away too.

  7. reviewboard/reviews/views/diff_fragments.py (Diff revision 2)
     
     
     
     
     
    Show all issues

    This argument hasn't been added to the function definition, it gets pulled out of kwargs.

  8. Show all issues

    Can we add a "Raises" section in the docs for this.

  9. 
      
david
maubin
  1. 
      
  2. reviewboard/reviews/views/diff_fragments.py (Diff revisions 2 - 3)
     
     
    Show all issues

    A preceding r was added here.

  3. reviewboard/reviews/views/diff_fragments.py (Diff revisions 2 - 3)
     
     
    Show all issues

    This should say diff comments instead of just diff

    1. Could be either. I'll reword.

  4. 
      
david
chipx86
  1. 
      
  2. reviewboard/diffviewer/views.py (Diff revision 4)
     
     
     
     
     
     
     
     
     
     
     
    Show all issues

    During deprecation, new arguments must go on the end so that the decorator can do the right thing. It matches up the positions of arguments passed to the position of keyword-only arguments in the arg list.

  3. reviewboard/reviews/views/diff_fragments.py (Diff revision 4)
     
     
     
    Show all issues

    Description needs to be indented 1.

  4. reviewboard/reviews/views/diff_fragments.py (Diff revision 4)
     
     
     
    Show all issues

    Description needs to be indented 1.

  5. reviewboard/reviews/views/diff_fragments.py (Diff revision 4)
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    Show all issues

    What do you think about adding a manager method for this, so we can keep these queries in one place? Like, FileAttachmentCommentManager.objects.for_file_attachment(), taking the attachments and a user.

    Been thinking lately that if we could consolidate more of our queries, it'd be easier to maintain and update them when working on performance, and ensure unit tests are more comprehensive.

    It's not a blocker for this change.

  6. reviewboard/reviews/views/diff_fragments.py (Diff revision 4)
     
     
     
    Show all issues

    Might be nicer as:

    modified_review_ui_class: (
        type[ReviewUI[Any, Any, Any]] |
        None
    ) = None,
    
  7. Show all issues

    Can we say "Return"? "Get" doesn't imply the result, just that it's getting something.

  8. 
      
david
maubin
  1. 
      
  2. reviewboard/reviews/managers.py (Diff revision 5)
     
     
     
    Show all issues

    This needs a "Version Added"

  3. reviewboard/reviews/managers.py (Diff revision 5)
     
     
     
    Show all issues

    What about super users who can access the comments?

    1. Oops never mind, super users aren't supposed to be able to see other people's draft reviews.

  4. 
      
david
maubin
  1. Ship It!
  2. 
      
chipx86
  1. 
      
  2. reviewboard/diffviewer/views.py (Diff revision 6)
     
     
     
    Show all issues

    Since we're wrapping, this should be one per line.

  3. reviewboard/diffviewer/views.py (Diff revision 6)
     
     
    Show all issues

    Double-backticks around the parameter name.

  4. reviewboard/diffviewer/views.py (Diff revision 6)
     
     
    Show all issues

    Missing , optional.

  5. reviewboard/diffviewer/views.py (Diff revision 6)
     
     
     
     
     
     
    Show all issues

    Not a new problem, but noticing it now: We're passing arguments in positional form to a localized string, which won't work if those get reversed.

    This should probably be a separate change, but we should fix this to use named arguments.

    1. Will handle this in my diffviewer changes for master.

  6. reviewboard/diffviewer/views.py (Diff revision 6)
     
     
    Show all issues

    Double backticks around request.

  7. Show all issues

    Swap these (alphabetical order).

  8. Show all issues

    Add double-backticks around request.

  9. Show all issues

    Can just be 7.1 to match the others.

  10. 
      
david
maubin
  1. Ship It!
  2. 
      
chipx86
  1. Ship It!
  2. 
      
david
Review request changed
Status:
Completed
Change Summary:
Pushed to release-7.1.x (02608ae)