Added capability-gated comment dislike UI#28021
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughAdds dislike reactions across the stack: extends comment types and counts, adds CommentDislike and updated CommentLike shapes, adds dislike API methods and a useBrowseCommentDislikes hook, makes read/thread hooks conditional on a dislikesEnabled include string, implements optimistic dislike actions with rollback and mutual-exclusion handling in state/actions, threads capabilities and ordering (likes vs net score) through app state and components, updates UI (buttons, counts, metrics, modal tabs), adjusts tests/mocks/fixtures, and adds i18n keys for dislike labels. Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/admin-x-framework/src/api/comments.ts`:
- Around line 105-114: memberThreadCommentIncludes currently uses
commentDislikeIncludes which only adds count.dislikes, so nested/thread comments
lack the current member's disliked flag; update memberThreadCommentIncludes to
use commentDislikeMemberIncludes (the same used by memberCommentIncludes) when
dislikesEnabled is true so the returned includes include both count.dislikes and
disliked; locate memberThreadCommentIncludes and replace the conditional spread
from commentDislikeIncludes to commentDislikeMemberIncludes (or append the
'disliked' field) to ensure the UI can detect whether the current member has
disliked a reply.
In `@apps/comments-ui/src/components/content/buttons/like-button.tsx`:
- Around line 31-42: The click handler currently sets setDisabled(true) but only
resets it after awaited dispatchAction calls, so if
dispatchAction('likeComment', comment) or dispatchAction('unlikeComment',
comment) throws the button remains disabled; wrap the async/await blocks inside
a try/finally so setDisabled(false) is always executed (keep the like animation
logic inside the try so it only runs on success), and apply the same try/finally
pattern to the other identical handler around dispatchAction calls at the other
occurrence (the block that uses dispatchAction('likeComment'...) /
dispatchAction('unlikeComment'...) and setLikeAnimation).
In `@apps/comments-ui/test/utils/mocked-api.ts`:
- Around line 448-449: When decrementing dislike counts in the mock API, avoid
negative values by clamping after the decrement; replace the current decrement
logic that sets comment.count.dislikes = (comment.count.dislikes ?? 0) - 1 and
comment.disliked = false with a clamped assignment using Math.max(0,
(comment.count.dislikes ?? 0) - 1). Apply the same clamp to the other occurrence
referenced (lines around the second instance at 499-500) so both
reaction-removal/swap paths never produce negative comment.count.dislikes.
In `@apps/posts/src/views/comments/components/comment-likes-modal.tsx`:
- Around line 24-25: The "remaining" counters can go negative when aggregate
counts are stale; update the computations (e.g., likesRemaining and
dislikesRemaining and the equivalent calculations at the other spots) to clamp
at zero by replacing count - array.length with Math.max(0, count - array.length)
(or an equivalent clamp) so the UI never renders negative "and -N more" values.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 360afee5-2b4f-4c65-aa58-44e150040794
⛔ Files ignored due to path filters (2)
apps/comments-ui/src/images/icons/thumbs-down.svgis excluded by!**/*.svgapps/comments-ui/src/images/icons/thumbs-up.svgis excluded by!**/*.svg
📒 Files selected for processing (83)
apps/admin-x-framework/src/api/comments.tsapps/admin-x-framework/src/utils/api/hooks.tsapps/comments-ui/src/actions.tsapps/comments-ui/src/app-context.tsapps/comments-ui/src/app.tsxapps/comments-ui/src/components/content/buttons/like-button.tsxapps/comments-ui/src/components/content/buttons/like-count.tsxapps/comments-ui/src/components/content/comment.tsxapps/comments-ui/src/components/content/forms/sorting-form.tsxapps/comments-ui/src/utils/api.tsapps/comments-ui/test/unit/actions.test.jsapps/comments-ui/test/unit/components/content/comment.test.jsxapps/comments-ui/test/utils/fixtures.tsapps/comments-ui/test/utils/mocked-api.tsapps/posts/src/views/comments/comments.tsxapps/posts/src/views/comments/components/comment-likes-modal.tsxapps/posts/src/views/comments/components/comment-metrics.tsxapps/posts/src/views/comments/components/comment-thread-list.tsxapps/posts/src/views/comments/components/comment-thread-sidebar.tsxapps/posts/src/views/comments/components/comments-list.tsxghost/i18n/locales/af/comments.jsonghost/i18n/locales/ar/comments.jsonghost/i18n/locales/bg/comments.jsonghost/i18n/locales/bn/comments.jsonghost/i18n/locales/bs/comments.jsonghost/i18n/locales/ca/comments.jsonghost/i18n/locales/context.jsonghost/i18n/locales/cs/comments.jsonghost/i18n/locales/da/comments.jsonghost/i18n/locales/de-CH/comments.jsonghost/i18n/locales/de/comments.jsonghost/i18n/locales/el/comments.jsonghost/i18n/locales/en/comments.jsonghost/i18n/locales/eo/comments.jsonghost/i18n/locales/es/comments.jsonghost/i18n/locales/et/comments.jsonghost/i18n/locales/eu/comments.jsonghost/i18n/locales/fa/comments.jsonghost/i18n/locales/fi/comments.jsonghost/i18n/locales/fr/comments.jsonghost/i18n/locales/gd/comments.jsonghost/i18n/locales/he/comments.jsonghost/i18n/locales/hi/comments.jsonghost/i18n/locales/hr/comments.jsonghost/i18n/locales/hu/comments.jsonghost/i18n/locales/id/comments.jsonghost/i18n/locales/is/comments.jsonghost/i18n/locales/it/comments.jsonghost/i18n/locales/ja/comments.jsonghost/i18n/locales/ko/comments.jsonghost/i18n/locales/kz/comments.jsonghost/i18n/locales/lt/comments.jsonghost/i18n/locales/lv/comments.jsonghost/i18n/locales/mk/comments.jsonghost/i18n/locales/mn/comments.jsonghost/i18n/locales/ms/comments.jsonghost/i18n/locales/nb/comments.jsonghost/i18n/locales/ne/comments.jsonghost/i18n/locales/nl/comments.jsonghost/i18n/locales/nn/comments.jsonghost/i18n/locales/pa/comments.jsonghost/i18n/locales/pl/comments.jsonghost/i18n/locales/pt-BR/comments.jsonghost/i18n/locales/pt/comments.jsonghost/i18n/locales/ro/comments.jsonghost/i18n/locales/ru/comments.jsonghost/i18n/locales/si/comments.jsonghost/i18n/locales/sk/comments.jsonghost/i18n/locales/sl/comments.jsonghost/i18n/locales/sq/comments.jsonghost/i18n/locales/sr-Cyrl/comments.jsonghost/i18n/locales/sr/comments.jsonghost/i18n/locales/sv/comments.jsonghost/i18n/locales/sw/comments.jsonghost/i18n/locales/ta/comments.jsonghost/i18n/locales/th/comments.jsonghost/i18n/locales/tr/comments.jsonghost/i18n/locales/uk/comments.jsonghost/i18n/locales/ur/comments.jsonghost/i18n/locales/uz/comments.jsonghost/i18n/locales/vi/comments.jsonghost/i18n/locales/zh-Hant/comments.jsonghost/i18n/locales/zh/comments.json
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #28021 +/- ##
=======================================
Coverage 73.85% 73.85%
=======================================
Files 1523 1525 +2
Lines 128982 129052 +70
Branches 15488 15493 +5
=======================================
+ Hits 95254 95312 +58
- Misses 32766 32802 +36
+ Partials 962 938 -24
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
8a43a90 to
598a1d0
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/comments-ui/src/components/content/forms/sorting-form.tsx`:
- Around line 9-14: selectedOption is only initialized from order once and can
become stale when order or bestOrder (which depends on capabilities) changes;
add a useEffect that watches order and bestOrder and calls setSelectedOption
with the new order (or computed bestOrder) so the UI label stays in sync with
capability-driven changes. Update the effect to reference selectedOption,
setSelectedOption, order, and bestOrder (and any i18n key if required) and
ensure options array continues to use bestOrder so the dropdown options and
selectedOption remain consistent.
In `@apps/comments-ui/test/unit/components/content/comment.test.jsx`:
- Around line 98-100: The current assertion for the icon-only dislike button
only excludes "1" and can miss other numeric text; update the assertion on
screen.getByTestId('dislike-button') to assert an empty text content (e.g.
expect(screen.getByTestId('dislike-button')).toHaveTextContent('')) so the
button truly contains no visible label or counts, keeping the accessible name
check intact; locate the test that queries 'dislike-button' and replace the
not.toHaveTextContent('1') line with a strict empty-text assertion.
In `@apps/posts/src/views/comments/components/comment-likes-modal.tsx`:
- Around line 167-205: The likes-only view currently shows a blank area when
dislikesEnabled is false and likes is empty; update the conditional rendering
inside the likes branch (the block using likesLoading, likes.map(...),
likesRemaining) to explicitly render an empty-state element when !likesLoading
and likes.length === 0 (e.g., a centered message/icon like "No likes yet" or
similar). Modify the component that contains Avatar, formatMemberName,
formatTimestamp and likesRemaining to check for the empty-case before mapping
likes so the LoadingIndicator, the list mapping, and the "and X more" footer
remain unchanged for non-empty states.
In `@apps/posts/src/views/comments/components/comment-metrics.tsx`:
- Around line 147-154: The click handler always sets
setLikesModalDefaultTab('likes') which opens an empty tab for dislike-only
comments; update the onClick in the button (the handler referencing
setLikesModalDefaultTab and setLikesModalOpen) to choose the initial tab based
on the comment's counts (e.g., if likes count is 0 and dislikes count > 0 then
setLikesModalDefaultTab('dislikes') else 'likes'), using the available
props/state for likes/dislikes (e.g., comment.scoreLikesCount or
scoreDislikesCount or equivalent) before calling setLikesModalOpen(true).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 19578c7a-2bf6-41b0-9eb8-c661059ead9d
⛔ Files ignored due to path filters (2)
apps/comments-ui/src/images/icons/thumbs-down.svgis excluded by!**/*.svgapps/comments-ui/src/images/icons/thumbs-up.svgis excluded by!**/*.svg
📒 Files selected for processing (84)
apps/admin-x-framework/src/api/comments.tsapps/admin-x-framework/src/utils/api/hooks.tsapps/comments-ui/package.jsonapps/comments-ui/src/actions.tsapps/comments-ui/src/app-context.tsapps/comments-ui/src/app.tsxapps/comments-ui/src/components/content/buttons/like-button.tsxapps/comments-ui/src/components/content/buttons/like-count.tsxapps/comments-ui/src/components/content/comment.tsxapps/comments-ui/src/components/content/forms/sorting-form.tsxapps/comments-ui/src/utils/api.tsapps/comments-ui/test/unit/actions.test.jsapps/comments-ui/test/unit/components/content/comment.test.jsxapps/comments-ui/test/utils/fixtures.tsapps/comments-ui/test/utils/mocked-api.tsapps/posts/src/views/comments/comments.tsxapps/posts/src/views/comments/components/comment-likes-modal.tsxapps/posts/src/views/comments/components/comment-metrics.tsxapps/posts/src/views/comments/components/comment-thread-list.tsxapps/posts/src/views/comments/components/comment-thread-sidebar.tsxapps/posts/src/views/comments/components/comments-list.tsxghost/i18n/locales/af/comments.jsonghost/i18n/locales/ar/comments.jsonghost/i18n/locales/bg/comments.jsonghost/i18n/locales/bn/comments.jsonghost/i18n/locales/bs/comments.jsonghost/i18n/locales/ca/comments.jsonghost/i18n/locales/context.jsonghost/i18n/locales/cs/comments.jsonghost/i18n/locales/da/comments.jsonghost/i18n/locales/de-CH/comments.jsonghost/i18n/locales/de/comments.jsonghost/i18n/locales/el/comments.jsonghost/i18n/locales/en/comments.jsonghost/i18n/locales/eo/comments.jsonghost/i18n/locales/es/comments.jsonghost/i18n/locales/et/comments.jsonghost/i18n/locales/eu/comments.jsonghost/i18n/locales/fa/comments.jsonghost/i18n/locales/fi/comments.jsonghost/i18n/locales/fr/comments.jsonghost/i18n/locales/gd/comments.jsonghost/i18n/locales/he/comments.jsonghost/i18n/locales/hi/comments.jsonghost/i18n/locales/hr/comments.jsonghost/i18n/locales/hu/comments.jsonghost/i18n/locales/id/comments.jsonghost/i18n/locales/is/comments.jsonghost/i18n/locales/it/comments.jsonghost/i18n/locales/ja/comments.jsonghost/i18n/locales/ko/comments.jsonghost/i18n/locales/kz/comments.jsonghost/i18n/locales/lt/comments.jsonghost/i18n/locales/lv/comments.jsonghost/i18n/locales/mk/comments.jsonghost/i18n/locales/mn/comments.jsonghost/i18n/locales/ms/comments.jsonghost/i18n/locales/nb/comments.jsonghost/i18n/locales/ne/comments.jsonghost/i18n/locales/nl/comments.jsonghost/i18n/locales/nn/comments.jsonghost/i18n/locales/pa/comments.jsonghost/i18n/locales/pl/comments.jsonghost/i18n/locales/pt-BR/comments.jsonghost/i18n/locales/pt/comments.jsonghost/i18n/locales/ro/comments.jsonghost/i18n/locales/ru/comments.jsonghost/i18n/locales/si/comments.jsonghost/i18n/locales/sk/comments.jsonghost/i18n/locales/sl/comments.jsonghost/i18n/locales/sq/comments.jsonghost/i18n/locales/sr-Cyrl/comments.jsonghost/i18n/locales/sr/comments.jsonghost/i18n/locales/sv/comments.jsonghost/i18n/locales/sw/comments.jsonghost/i18n/locales/ta/comments.jsonghost/i18n/locales/th/comments.jsonghost/i18n/locales/tr/comments.jsonghost/i18n/locales/uk/comments.jsonghost/i18n/locales/ur/comments.jsonghost/i18n/locales/uz/comments.jsonghost/i18n/locales/vi/comments.jsonghost/i18n/locales/zh-Hant/comments.jsonghost/i18n/locales/zh/comments.json
✅ Files skipped from review due to trivial changes (38)
- apps/comments-ui/package.json
- ghost/i18n/locales/si/comments.json
- ghost/i18n/locales/bg/comments.json
- ghost/i18n/locales/en/comments.json
- ghost/i18n/locales/uk/comments.json
- ghost/i18n/locales/hu/comments.json
- ghost/i18n/locales/zh/comments.json
- ghost/i18n/locales/ja/comments.json
- ghost/i18n/locales/de/comments.json
- ghost/i18n/locales/id/comments.json
- ghost/i18n/locales/mn/comments.json
- ghost/i18n/locales/eu/comments.json
- ghost/i18n/locales/sq/comments.json
- ghost/i18n/locales/sr-Cyrl/comments.json
- ghost/i18n/locales/uz/comments.json
- ghost/i18n/locales/bs/comments.json
- ghost/i18n/locales/es/comments.json
- ghost/i18n/locales/sr/comments.json
- ghost/i18n/locales/sl/comments.json
- ghost/i18n/locales/nl/comments.json
- ghost/i18n/locales/et/comments.json
- ghost/i18n/locales/cs/comments.json
- ghost/i18n/locales/pl/comments.json
- ghost/i18n/locales/lv/comments.json
- ghost/i18n/locales/he/comments.json
- ghost/i18n/locales/kz/comments.json
- ghost/i18n/locales/gd/comments.json
- ghost/i18n/locales/mk/comments.json
- ghost/i18n/locales/pt-BR/comments.json
- ghost/i18n/locales/pt/comments.json
- ghost/i18n/locales/fr/comments.json
- ghost/i18n/locales/ms/comments.json
- ghost/i18n/locales/bn/comments.json
- ghost/i18n/locales/ar/comments.json
- ghost/i18n/locales/nb/comments.json
- ghost/i18n/locales/sv/comments.json
- ghost/i18n/locales/vi/comments.json
- ghost/i18n/locales/is/comments.json
598a1d0 to
42493f3
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 42493f3921
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return {}; | ||
| } catch { | ||
| dispatchAction('updateCommentLikeState', {id: comment.id, liked: false}); | ||
| dispatchAction('updateCommentLikeState', {id: comment.id, liked: false, restoreDisliked: wasDisliked}); |
There was a problem hiding this comment.
Guard rollback against overlapping reaction toggles
This rollback uses wasDisliked captured before the request, so if a user clicks Like and then quickly clicks Dislike (dislikes-enabled UI shows two independent buttons), a later failure of the first request will force disliked back to that stale snapshot and can undo the newer successful action. The same stale-snapshot pattern exists in the inverse dislike rollback path, so concurrent/out-of-order toggles can leave client state inconsistent with the server until a full refetch.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
♻️ Duplicate comments (2)
apps/comments-ui/test/unit/components/content/comment.test.jsx (1)
100-100:⚠️ Potential issue | 🟡 MinorWeak assertion for icon-only button.
This assertion only excludes the string
'1'and will pass if other numeric counts (e.g.,'2','3') are rendered. A past review comment already suggested strengthening this to either assert empty text content or exclude all digits using a regex pattern.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/comments-ui/test/unit/components/content/comment.test.jsx` at line 100, The assertion on getByTestId('dislike-button') is too weak (only excludes the string '1'); update the test to assert that the icon-only button contains no digits by either asserting an empty text content or asserting no numeric characters (for example replace the current expect(screen.getByTestId('dislike-button')).not.toHaveTextContent('1') with a stricter assertion such as expecting an empty string or using a regex to ensure no digits), keeping the check on getByTestId('dislike-button') and the same test setup.apps/admin-x-framework/src/api/comments.ts (1)
105-114:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
memberThreadCommentIncludesshould usecommentDislikeMemberIncludesto include thedislikedflag.Thread/nested comments fetched via this include string will have
count.dislikesbut not the current member'sdislikedstatus, so the dislike button UI won't know if the user has already disliked a reply.Proposed fix
export const memberThreadCommentIncludes = (dislikesEnabled: boolean) => [ 'member', 'post', 'count.direct_replies', 'count.likes', - ...(dislikesEnabled ? [commentDislikeIncludes] : []), + ...(dislikesEnabled ? [commentDislikeMemberIncludes] : []), 'count.reports', 'parent', 'in_reply_to' ].join(',');🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/admin-x-framework/src/api/comments.ts` around lines 105 - 114, memberThreadCommentIncludes currently adds commentDislikeIncludes when dislikesEnabled, which only brings count.dislikes; change it to include commentDislikeMemberIncludes so the fetched thread comments also contain the current member's disliked flag. Update the spread in memberThreadCommentIncludes (the expression that currently uses commentDislikeIncludes) to use commentDislikeMemberIncludes while keeping the dislikesEnabled conditional and the rest of the include list unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@apps/admin-x-framework/src/api/comments.ts`:
- Around line 105-114: memberThreadCommentIncludes currently adds
commentDislikeIncludes when dislikesEnabled, which only brings count.dislikes;
change it to include commentDislikeMemberIncludes so the fetched thread comments
also contain the current member's disliked flag. Update the spread in
memberThreadCommentIncludes (the expression that currently uses
commentDislikeIncludes) to use commentDislikeMemberIncludes while keeping the
dislikesEnabled conditional and the rest of the include list unchanged.
In `@apps/comments-ui/test/unit/components/content/comment.test.jsx`:
- Line 100: The assertion on getByTestId('dislike-button') is too weak (only
excludes the string '1'); update the test to assert that the icon-only button
contains no digits by either asserting an empty text content or asserting no
numeric characters (for example replace the current
expect(screen.getByTestId('dislike-button')).not.toHaveTextContent('1') with a
stricter assertion such as expecting an empty string or using a regex to ensure
no digits), keeping the check on getByTestId('dislike-button') and the same test
setup.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 2446e70a-1fc1-4bb8-9174-99aab9222ed2
⛔ Files ignored due to path filters (2)
apps/comments-ui/src/images/icons/thumbs-down.svgis excluded by!**/*.svgapps/comments-ui/src/images/icons/thumbs-up.svgis excluded by!**/*.svg
📒 Files selected for processing (84)
apps/admin-x-framework/src/api/comments.tsapps/admin-x-framework/src/utils/api/hooks.tsapps/comments-ui/package.jsonapps/comments-ui/src/actions.tsapps/comments-ui/src/app-context.tsapps/comments-ui/src/app.tsxapps/comments-ui/src/components/content/buttons/like-button.tsxapps/comments-ui/src/components/content/buttons/like-count.tsxapps/comments-ui/src/components/content/comment.tsxapps/comments-ui/src/components/content/forms/sorting-form.tsxapps/comments-ui/src/utils/api.tsapps/comments-ui/test/unit/actions.test.jsapps/comments-ui/test/unit/components/content/comment.test.jsxapps/comments-ui/test/utils/fixtures.tsapps/comments-ui/test/utils/mocked-api.tsapps/posts/src/views/comments/comments.tsxapps/posts/src/views/comments/components/comment-likes-modal.tsxapps/posts/src/views/comments/components/comment-metrics.tsxapps/posts/src/views/comments/components/comment-thread-list.tsxapps/posts/src/views/comments/components/comment-thread-sidebar.tsxapps/posts/src/views/comments/components/comments-list.tsxghost/i18n/locales/af/comments.jsonghost/i18n/locales/ar/comments.jsonghost/i18n/locales/bg/comments.jsonghost/i18n/locales/bn/comments.jsonghost/i18n/locales/bs/comments.jsonghost/i18n/locales/ca/comments.jsonghost/i18n/locales/context.jsonghost/i18n/locales/cs/comments.jsonghost/i18n/locales/da/comments.jsonghost/i18n/locales/de-CH/comments.jsonghost/i18n/locales/de/comments.jsonghost/i18n/locales/el/comments.jsonghost/i18n/locales/en/comments.jsonghost/i18n/locales/eo/comments.jsonghost/i18n/locales/es/comments.jsonghost/i18n/locales/et/comments.jsonghost/i18n/locales/eu/comments.jsonghost/i18n/locales/fa/comments.jsonghost/i18n/locales/fi/comments.jsonghost/i18n/locales/fr/comments.jsonghost/i18n/locales/gd/comments.jsonghost/i18n/locales/he/comments.jsonghost/i18n/locales/hi/comments.jsonghost/i18n/locales/hr/comments.jsonghost/i18n/locales/hu/comments.jsonghost/i18n/locales/id/comments.jsonghost/i18n/locales/is/comments.jsonghost/i18n/locales/it/comments.jsonghost/i18n/locales/ja/comments.jsonghost/i18n/locales/ko/comments.jsonghost/i18n/locales/kz/comments.jsonghost/i18n/locales/lt/comments.jsonghost/i18n/locales/lv/comments.jsonghost/i18n/locales/mk/comments.jsonghost/i18n/locales/mn/comments.jsonghost/i18n/locales/ms/comments.jsonghost/i18n/locales/nb/comments.jsonghost/i18n/locales/ne/comments.jsonghost/i18n/locales/nl/comments.jsonghost/i18n/locales/nn/comments.jsonghost/i18n/locales/pa/comments.jsonghost/i18n/locales/pl/comments.jsonghost/i18n/locales/pt-BR/comments.jsonghost/i18n/locales/pt/comments.jsonghost/i18n/locales/ro/comments.jsonghost/i18n/locales/ru/comments.jsonghost/i18n/locales/si/comments.jsonghost/i18n/locales/sk/comments.jsonghost/i18n/locales/sl/comments.jsonghost/i18n/locales/sq/comments.jsonghost/i18n/locales/sr-Cyrl/comments.jsonghost/i18n/locales/sr/comments.jsonghost/i18n/locales/sv/comments.jsonghost/i18n/locales/sw/comments.jsonghost/i18n/locales/ta/comments.jsonghost/i18n/locales/th/comments.jsonghost/i18n/locales/tr/comments.jsonghost/i18n/locales/uk/comments.jsonghost/i18n/locales/ur/comments.jsonghost/i18n/locales/uz/comments.jsonghost/i18n/locales/vi/comments.jsonghost/i18n/locales/zh-Hant/comments.jsonghost/i18n/locales/zh/comments.json
✅ Files skipped from review due to trivial changes (39)
- ghost/i18n/locales/hi/comments.json
- ghost/i18n/locales/sq/comments.json
- ghost/i18n/locales/nn/comments.json
- ghost/i18n/locales/gd/comments.json
- ghost/i18n/locales/ms/comments.json
- ghost/i18n/locales/zh/comments.json
- ghost/i18n/locales/ko/comments.json
- ghost/i18n/locales/nl/comments.json
- ghost/i18n/locales/pa/comments.json
- apps/comments-ui/package.json
- ghost/i18n/locales/sr-Cyrl/comments.json
- ghost/i18n/locales/vi/comments.json
- ghost/i18n/locales/uk/comments.json
- ghost/i18n/locales/si/comments.json
- ghost/i18n/locales/it/comments.json
- ghost/i18n/locales/uz/comments.json
- ghost/i18n/locales/sv/comments.json
- ghost/i18n/locales/eu/comments.json
- ghost/i18n/locales/et/comments.json
- ghost/i18n/locales/lv/comments.json
- ghost/i18n/locales/el/comments.json
- ghost/i18n/locales/es/comments.json
- ghost/i18n/locales/sl/comments.json
- ghost/i18n/locales/fr/comments.json
- ghost/i18n/locales/ca/comments.json
- ghost/i18n/locales/lt/comments.json
- apps/admin-x-framework/src/utils/api/hooks.ts
- ghost/i18n/locales/ne/comments.json
- ghost/i18n/locales/en/comments.json
- ghost/i18n/locales/pt/comments.json
- ghost/i18n/locales/ar/comments.json
- ghost/i18n/locales/he/comments.json
- ghost/i18n/locales/fi/comments.json
- ghost/i18n/locales/de/comments.json
- ghost/i18n/locales/eo/comments.json
- ghost/i18n/locales/ro/comments.json
- ghost/i18n/locales/ja/comments.json
- ghost/i18n/locales/mk/comments.json
- apps/comments-ui/src/components/content/buttons/like-button.tsx
42493f3 to
c8f3cbd
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: c8f3cbdeef
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return {}; | ||
| } catch { | ||
| dispatchAction('updateCommentLikeState', {id: comment.id, liked: true}); | ||
| dispatchAction('updateCommentLikeState', {id: comment.id, liked: true, expectedLiked: false}); |
There was a problem hiding this comment.
Skip unlike rollback after a newer dislike toggle
When unlikeComment fails, this rollback always dispatches liked: true as long as the current liked state is false. If the user clicks Unlike and then quickly clicks Dislike, a later unlike failure will reapply liked: true and (via updateCommentLikeState) clear disliked, overwriting the newer successful dislike action and leaving the client out of sync until a refetch.
Useful? React with 👍 / 👎.
| await api.comments.undislike({comment}); | ||
| return {}; | ||
| } catch { | ||
| dispatchAction('updateCommentDislikeState', {id: comment.id, disliked: true, expectedDisliked: false}); |
There was a problem hiding this comment.
Skip undislike rollback after a newer like toggle
When undislikeComment fails, this rollback unconditionally dispatches disliked: true if the current disliked value is false. In the sequence Undislike → Like, a late undislike failure can overwrite a newer successful like by restoring disliked: true and forcing liked: false, producing incorrect reaction state/counts on the client until the next reload/refetch.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
♻️ Duplicate comments (2)
apps/comments-ui/test/unit/components/content/comment.test.jsx (1)
99-101:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winStrengthen the icon-only assertion for
dislike-button.On Line 101,
not.toHaveTextContent('1')can miss other numeric text; assert no numeric content (or empty visible text) instead.Suggested fix
- expect(screen.getByTestId('dislike-button')).not.toHaveTextContent('1'); + expect(screen.getByTestId('dislike-button')).not.toHaveTextContent(/\d/);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/comments-ui/test/unit/components/content/comment.test.jsx` around lines 99 - 101, The current assertion only checks that the dislike button does not contain the specific character '1'; update the assertion for screen.getByTestId('dislike-button') so it verifies the visible text is empty or contains no digits (e.g., assert empty visible text or use a regex to assert no numeric characters), ensuring the icon-only button has no numeric label.apps/admin-x-framework/src/api/comments.ts (1)
105-114:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
memberThreadCommentIncludesstill omits per-memberdislikedstate.Line 110 uses
commentDislikeIncludes(count.dislikes) instead of the member-aware include, so thread replies may missdislikedand render incorrect dislike state.Proposed fix
export const memberThreadCommentIncludes = (dislikesEnabled: boolean) => [ 'member', 'post', 'count.direct_replies', 'count.likes', - ...(dislikesEnabled ? [commentDislikeIncludes] : []), + ...(dislikesEnabled ? [commentDislikeMemberIncludes] : []), 'count.reports', 'parent', 'in_reply_to' ].join(',');🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/admin-x-framework/src/api/comments.ts` around lines 105 - 114, memberThreadCommentIncludes currently spreads commentDislikeIncludes which only adds count.dislikes and therefore omits the per-member disliked state; update memberThreadCommentIncludes to include the member-aware dislike include (replace commentDislikeIncludes with the include that adds the per-member "disliked" field, e.g. commentDislikedIncludes or the existing member-aware dislike include in the codebase) so thread replies receive both count.dislikes and the member-specific disliked flag; keep the conditional (dislikesEnabled) behavior and ensure you reference the member-aware include symbol instead of commentDislikeIncludes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@apps/admin-x-framework/src/api/comments.ts`:
- Around line 105-114: memberThreadCommentIncludes currently spreads
commentDislikeIncludes which only adds count.dislikes and therefore omits the
per-member disliked state; update memberThreadCommentIncludes to include the
member-aware dislike include (replace commentDislikeIncludes with the include
that adds the per-member "disliked" field, e.g. commentDislikedIncludes or the
existing member-aware dislike include in the codebase) so thread replies receive
both count.dislikes and the member-specific disliked flag; keep the conditional
(dislikesEnabled) behavior and ensure you reference the member-aware include
symbol instead of commentDislikeIncludes.
In `@apps/comments-ui/test/unit/components/content/comment.test.jsx`:
- Around line 99-101: The current assertion only checks that the dislike button
does not contain the specific character '1'; update the assertion for
screen.getByTestId('dislike-button') so it verifies the visible text is empty or
contains no digits (e.g., assert empty visible text or use a regex to assert no
numeric characters), ensuring the icon-only button has no numeric label.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 50159703-c3c5-44c9-bfc9-70cd86ffb0d6
⛔ Files ignored due to path filters (2)
apps/comments-ui/src/images/icons/thumbs-down.svgis excluded by!**/*.svgapps/comments-ui/src/images/icons/thumbs-up.svgis excluded by!**/*.svg
📒 Files selected for processing (84)
apps/admin-x-framework/src/api/comments.tsapps/admin-x-framework/src/utils/api/hooks.tsapps/comments-ui/package.jsonapps/comments-ui/src/actions.tsapps/comments-ui/src/app-context.tsapps/comments-ui/src/app.tsxapps/comments-ui/src/components/content/buttons/like-button.tsxapps/comments-ui/src/components/content/buttons/like-count.tsxapps/comments-ui/src/components/content/comment.tsxapps/comments-ui/src/components/content/forms/sorting-form.tsxapps/comments-ui/src/utils/api.tsapps/comments-ui/test/unit/actions.test.jsapps/comments-ui/test/unit/components/content/comment.test.jsxapps/comments-ui/test/utils/fixtures.tsapps/comments-ui/test/utils/mocked-api.tsapps/posts/src/views/comments/comments.tsxapps/posts/src/views/comments/components/comment-likes-modal.tsxapps/posts/src/views/comments/components/comment-metrics.tsxapps/posts/src/views/comments/components/comment-thread-list.tsxapps/posts/src/views/comments/components/comment-thread-sidebar.tsxapps/posts/src/views/comments/components/comments-list.tsxghost/i18n/locales/af/comments.jsonghost/i18n/locales/ar/comments.jsonghost/i18n/locales/bg/comments.jsonghost/i18n/locales/bn/comments.jsonghost/i18n/locales/bs/comments.jsonghost/i18n/locales/ca/comments.jsonghost/i18n/locales/context.jsonghost/i18n/locales/cs/comments.jsonghost/i18n/locales/da/comments.jsonghost/i18n/locales/de-CH/comments.jsonghost/i18n/locales/de/comments.jsonghost/i18n/locales/el/comments.jsonghost/i18n/locales/en/comments.jsonghost/i18n/locales/eo/comments.jsonghost/i18n/locales/es/comments.jsonghost/i18n/locales/et/comments.jsonghost/i18n/locales/eu/comments.jsonghost/i18n/locales/fa/comments.jsonghost/i18n/locales/fi/comments.jsonghost/i18n/locales/fr/comments.jsonghost/i18n/locales/gd/comments.jsonghost/i18n/locales/he/comments.jsonghost/i18n/locales/hi/comments.jsonghost/i18n/locales/hr/comments.jsonghost/i18n/locales/hu/comments.jsonghost/i18n/locales/id/comments.jsonghost/i18n/locales/is/comments.jsonghost/i18n/locales/it/comments.jsonghost/i18n/locales/ja/comments.jsonghost/i18n/locales/ko/comments.jsonghost/i18n/locales/kz/comments.jsonghost/i18n/locales/lt/comments.jsonghost/i18n/locales/lv/comments.jsonghost/i18n/locales/mk/comments.jsonghost/i18n/locales/mn/comments.jsonghost/i18n/locales/ms/comments.jsonghost/i18n/locales/nb/comments.jsonghost/i18n/locales/ne/comments.jsonghost/i18n/locales/nl/comments.jsonghost/i18n/locales/nn/comments.jsonghost/i18n/locales/pa/comments.jsonghost/i18n/locales/pl/comments.jsonghost/i18n/locales/pt-BR/comments.jsonghost/i18n/locales/pt/comments.jsonghost/i18n/locales/ro/comments.jsonghost/i18n/locales/ru/comments.jsonghost/i18n/locales/si/comments.jsonghost/i18n/locales/sk/comments.jsonghost/i18n/locales/sl/comments.jsonghost/i18n/locales/sq/comments.jsonghost/i18n/locales/sr-Cyrl/comments.jsonghost/i18n/locales/sr/comments.jsonghost/i18n/locales/sv/comments.jsonghost/i18n/locales/sw/comments.jsonghost/i18n/locales/ta/comments.jsonghost/i18n/locales/th/comments.jsonghost/i18n/locales/tr/comments.jsonghost/i18n/locales/uk/comments.jsonghost/i18n/locales/ur/comments.jsonghost/i18n/locales/uz/comments.jsonghost/i18n/locales/vi/comments.jsonghost/i18n/locales/zh-Hant/comments.jsonghost/i18n/locales/zh/comments.json
✅ Files skipped from review due to trivial changes (33)
- ghost/i18n/locales/zh/comments.json
- apps/comments-ui/package.json
- ghost/i18n/locales/fi/comments.json
- ghost/i18n/locales/ja/comments.json
- ghost/i18n/locales/ne/comments.json
- ghost/i18n/locales/de/comments.json
- ghost/i18n/locales/hr/comments.json
- ghost/i18n/locales/eo/comments.json
- ghost/i18n/locales/si/comments.json
- ghost/i18n/locales/vi/comments.json
- ghost/i18n/locales/sv/comments.json
- ghost/i18n/locales/ru/comments.json
- ghost/i18n/locales/et/comments.json
- ghost/i18n/locales/eu/comments.json
- ghost/i18n/locales/lv/comments.json
- ghost/i18n/locales/gd/comments.json
- ghost/i18n/locales/hi/comments.json
- ghost/i18n/locales/fr/comments.json
- ghost/i18n/locales/nl/comments.json
- ghost/i18n/locales/en/comments.json
- ghost/i18n/locales/ms/comments.json
- ghost/i18n/locales/ro/comments.json
- ghost/i18n/locales/kz/comments.json
- ghost/i18n/locales/th/comments.json
- ghost/i18n/locales/ur/comments.json
- ghost/i18n/locales/mn/comments.json
- ghost/i18n/locales/sr/comments.json
- ghost/i18n/locales/lt/comments.json
- ghost/i18n/locales/sr-Cyrl/comments.json
- ghost/i18n/locales/sw/comments.json
- ghost/i18n/locales/id/comments.json
- ghost/i18n/locales/ar/comments.json
- ghost/i18n/locales/context.json
ref https://linear.app/ghost/issue/BER-3550/adjust-ui-for-liking-and-disliking-comments-in-comments-ui Enables the public dislike controls only when comments responses advertise support, while keeping old servers like-only and avoiding public dislike counts. Also wires the Admin comments UI to the same capability cue for authenticated moderation views.
c8f3cbd to
f90b584
Compare
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f90b584cec
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| await api.comments.dislike({comment}); | ||
| return {}; | ||
| } catch { | ||
| dispatchAction('updateCommentDislikeState', {id: comment.id, disliked: false, restoreLiked: wasLiked, expectedDisliked: true}); |
There was a problem hiding this comment.
Prevent stale rollback after dual like/dislike failures
This rollback restores liked from wasLiked captured before the dislike request, but that snapshot may itself be an optimistic state from an earlier in-flight like/unlike request. If a user quickly toggles Like→Dislike (or Unlike→Dislike) and both requests fail out of order, the earlier rollback can be skipped by expected* guards and this later rollback can still reapply the stale snapshot, leaving client reactions/counts inconsistent with the server until a refetch.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
apps/comments-ui/test/utils/mocked-api.ts (1)
145-156: ⚡ Quick winAlign tie-break ordering with
created_at descin net-score sorting.The comparator currently sorts ties by oldest first, which conflicts with the order key (
count__net_score desc, created_at desc) and can make mock behavior diverge from real API ordering.Proposed fix
- const aDate = new Date(a.created_at).getTime(); - const bDate = new Date(b.created_at).getTime(); - return aDate - bDate; // For the rest, sort by date asc + const aDate = new Date(a.created_at).getTime(); + const bDate = new Date(b.created_at).getTime(); + return bDate - aDate; // Tie-break by created_at desc🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/comments-ui/test/utils/mocked-api.ts` around lines 145 - 156, Tie-breaker is currently ascending but should be descending for order key "count__net_score desc, created_at desc": update the comparator inside the if (setOrder === 'count__net_score desc, created_at desc') block (the this.comments.sort callback) to return bDate - aDate instead of aDate - bDate so ties on net score are ordered by created_at descending; ensure the comparator still computes likesDiff the same way and only flips the final date comparison.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/comments-ui/test/utils/mocked-api.ts`:
- Around line 497-500: The decrement of comment.count.likes when swapping from
liked to disliked can produce negatives if count.likes is 0/undefined; change
the logic around comment.liked to ensure a numeric baseline and clamp to zero,
e.g. compute likes = Math.max(0, (comment.count?.likes ?? 0) - 1) and assign
back to comment.count.likes, then set comment.liked = false; also ensure
comment.count exists before reading/writing to avoid undefined errors.
---
Nitpick comments:
In `@apps/comments-ui/test/utils/mocked-api.ts`:
- Around line 145-156: Tie-breaker is currently ascending but should be
descending for order key "count__net_score desc, created_at desc": update the
comparator inside the if (setOrder === 'count__net_score desc, created_at desc')
block (the this.comments.sort callback) to return bDate - aDate instead of aDate
- bDate so ties on net score are ordered by created_at descending; ensure the
comparator still computes likesDiff the same way and only flips the final date
comparison.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 144b24cd-2aec-4a80-abc3-6133e739fb9b
⛔ Files ignored due to path filters (2)
apps/comments-ui/src/images/icons/thumbs-down.svgis excluded by!**/*.svgapps/comments-ui/src/images/icons/thumbs-up.svgis excluded by!**/*.svg
📒 Files selected for processing (84)
apps/admin-x-framework/src/api/comments.tsapps/admin-x-framework/src/utils/api/hooks.tsapps/comments-ui/package.jsonapps/comments-ui/src/actions.tsapps/comments-ui/src/app-context.tsapps/comments-ui/src/app.tsxapps/comments-ui/src/components/content/buttons/like-button.tsxapps/comments-ui/src/components/content/buttons/like-count.tsxapps/comments-ui/src/components/content/comment.tsxapps/comments-ui/src/components/content/forms/sorting-form.tsxapps/comments-ui/src/utils/api.tsapps/comments-ui/test/unit/actions.test.jsapps/comments-ui/test/unit/components/content/comment.test.jsxapps/comments-ui/test/utils/fixtures.tsapps/comments-ui/test/utils/mocked-api.tsapps/posts/src/views/comments/comments.tsxapps/posts/src/views/comments/components/comment-likes-modal.tsxapps/posts/src/views/comments/components/comment-metrics.tsxapps/posts/src/views/comments/components/comment-thread-list.tsxapps/posts/src/views/comments/components/comment-thread-sidebar.tsxapps/posts/src/views/comments/components/comments-list.tsxghost/i18n/locales/af/comments.jsonghost/i18n/locales/ar/comments.jsonghost/i18n/locales/bg/comments.jsonghost/i18n/locales/bn/comments.jsonghost/i18n/locales/bs/comments.jsonghost/i18n/locales/ca/comments.jsonghost/i18n/locales/context.jsonghost/i18n/locales/cs/comments.jsonghost/i18n/locales/da/comments.jsonghost/i18n/locales/de-CH/comments.jsonghost/i18n/locales/de/comments.jsonghost/i18n/locales/el/comments.jsonghost/i18n/locales/en/comments.jsonghost/i18n/locales/eo/comments.jsonghost/i18n/locales/es/comments.jsonghost/i18n/locales/et/comments.jsonghost/i18n/locales/eu/comments.jsonghost/i18n/locales/fa/comments.jsonghost/i18n/locales/fi/comments.jsonghost/i18n/locales/fr/comments.jsonghost/i18n/locales/gd/comments.jsonghost/i18n/locales/he/comments.jsonghost/i18n/locales/hi/comments.jsonghost/i18n/locales/hr/comments.jsonghost/i18n/locales/hu/comments.jsonghost/i18n/locales/id/comments.jsonghost/i18n/locales/is/comments.jsonghost/i18n/locales/it/comments.jsonghost/i18n/locales/ja/comments.jsonghost/i18n/locales/ko/comments.jsonghost/i18n/locales/kz/comments.jsonghost/i18n/locales/lt/comments.jsonghost/i18n/locales/lv/comments.jsonghost/i18n/locales/mk/comments.jsonghost/i18n/locales/mn/comments.jsonghost/i18n/locales/ms/comments.jsonghost/i18n/locales/nb/comments.jsonghost/i18n/locales/ne/comments.jsonghost/i18n/locales/nl/comments.jsonghost/i18n/locales/nn/comments.jsonghost/i18n/locales/pa/comments.jsonghost/i18n/locales/pl/comments.jsonghost/i18n/locales/pt-BR/comments.jsonghost/i18n/locales/pt/comments.jsonghost/i18n/locales/ro/comments.jsonghost/i18n/locales/ru/comments.jsonghost/i18n/locales/si/comments.jsonghost/i18n/locales/sk/comments.jsonghost/i18n/locales/sl/comments.jsonghost/i18n/locales/sq/comments.jsonghost/i18n/locales/sr-Cyrl/comments.jsonghost/i18n/locales/sr/comments.jsonghost/i18n/locales/sv/comments.jsonghost/i18n/locales/sw/comments.jsonghost/i18n/locales/ta/comments.jsonghost/i18n/locales/th/comments.jsonghost/i18n/locales/tr/comments.jsonghost/i18n/locales/uk/comments.jsonghost/i18n/locales/ur/comments.jsonghost/i18n/locales/uz/comments.jsonghost/i18n/locales/vi/comments.jsonghost/i18n/locales/zh-Hant/comments.jsonghost/i18n/locales/zh/comments.json
✅ Files skipped from review due to trivial changes (40)
- apps/comments-ui/package.json
- ghost/i18n/locales/lt/comments.json
- apps/comments-ui/test/utils/fixtures.ts
- apps/admin-x-framework/src/utils/api/hooks.ts
- ghost/i18n/locales/tr/comments.json
- ghost/i18n/locales/sw/comments.json
- ghost/i18n/locales/nb/comments.json
- ghost/i18n/locales/vi/comments.json
- ghost/i18n/locales/sl/comments.json
- ghost/i18n/locales/id/comments.json
- ghost/i18n/locales/pt/comments.json
- ghost/i18n/locales/sv/comments.json
- ghost/i18n/locales/de/comments.json
- ghost/i18n/locales/fi/comments.json
- ghost/i18n/locales/mn/comments.json
- ghost/i18n/locales/ru/comments.json
- ghost/i18n/locales/en/comments.json
- ghost/i18n/locales/th/comments.json
- ghost/i18n/locales/zh/comments.json
- ghost/i18n/locales/nn/comments.json
- ghost/i18n/locales/bs/comments.json
- ghost/i18n/locales/cs/comments.json
- ghost/i18n/locales/ca/comments.json
- ghost/i18n/locales/nl/comments.json
- ghost/i18n/locales/de-CH/comments.json
- ghost/i18n/locales/sr-Cyrl/comments.json
- ghost/i18n/locales/gd/comments.json
- ghost/i18n/locales/bg/comments.json
- ghost/i18n/locales/sq/comments.json
- ghost/i18n/locales/ta/comments.json
- ghost/i18n/locales/uk/comments.json
- ghost/i18n/locales/lv/comments.json
- ghost/i18n/locales/ur/comments.json
- ghost/i18n/locales/ar/comments.json
- ghost/i18n/locales/da/comments.json
- ghost/i18n/locales/eu/comments.json
- ghost/i18n/locales/is/comments.json
- ghost/i18n/locales/context.json
- ghost/i18n/locales/ko/comments.json
- ghost/i18n/locales/pa/comments.json
| if (comment.liked) { | ||
| comment.count.likes -= 1; | ||
| comment.liked = false; | ||
| } |
There was a problem hiding this comment.
Clamp like decrement during dislike swap to avoid negative likes in mocks.
If fixture state is inconsistent (liked: true with count.likes at 0/undefined), this path can return negative likes and cause flaky assertions.
Proposed fix
if (comment.liked) {
- comment.count.likes -= 1;
+ comment.count.likes = Math.max(0, (comment.count.likes ?? 0) - 1);
comment.liked = false;
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (comment.liked) { | |
| comment.count.likes -= 1; | |
| comment.liked = false; | |
| } | |
| if (comment.liked) { | |
| comment.count.likes = Math.max(0, (comment.count.likes ?? 0) - 1); | |
| comment.liked = false; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/comments-ui/test/utils/mocked-api.ts` around lines 497 - 500, The
decrement of comment.count.likes when swapping from liked to disliked can
produce negatives if count.likes is 0/undefined; change the logic around
comment.liked to ensure a numeric baseline and clamp to zero, e.g. compute likes
= Math.max(0, (comment.count?.likes ?? 0) - 1) and assign back to
comment.count.likes, then set comment.liked = false; also ensure comment.count
exists before reading/writing to avoid undefined errors.
Stack
Summary
meta.capabilities.dislikes.Compatibility
Verification
pnpm --filter @tryghost/comments-ui test:unit -- actions.test.jspnpm --filter @tryghost/comments-ui test:unit -- comment.test.jsxpnpm --filter @tryghost/i18n translateKnown local verification blockers
pnpm --filter @tryghost/admin-x-framework test:typescurrently fails before these changes on missingbson-objectid/type-festfrom automations.pnpm --filter @tryghost/posts test:unit -- commentscurrently fails before the comments tests on missingdequal/bson-objectidfrom automations.pnpm --filter @tryghost/i18n lint:translationscurrently fails on stale unused ignores intest/i18n-ignores.jsonfor eu ghost translations.