-
-
Notifications
You must be signed in to change notification settings - Fork 10.6k
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
Added post delete mutation for posts in the admin-x-activitypub
app
#22330
base: main
Are you sure you want to change the base?
Added post delete mutation for posts in the admin-x-activitypub
app
#22330
Conversation
Warning Rate limit exceeded@mike182uk has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 13 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (9)
WalkthroughThe changes introduce a new exported interface Possibly related PRs
Suggested labels
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
a4716b4
to
11cd1a5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts (1)
819-882
: Comprehensive implementation with room for improvement in cache managementThe implementation is solid, handling optimistic updates and error recovery for feed and inbox. However, despite defining query keys for
outboxQueryKey
,likedQueryKey
, andprofilePostsQueryKey
, the code doesn't update these caches optimistically, which could lead to stale data.Consider updating all defined caches to maintain consistent state across the application. Here's a suggestion for extending the optimistic updates:
onMutate: (id) => { // Find the post in the feed query cache const previousFeed = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(feedQueryKey); queryClient.setQueryData(feedQueryKey, (current?: {pages: {posts: Activity[]}[]}) => { if (!current) { return current; } return { ...current, pages: current.pages.map((page: {posts: Activity[]}) => { return { ...page, posts: page.posts.filter((item: Activity) => item.id !== id) }; }) }; }); // Find the post in the inbox query cache const previousInbox = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(inboxQueryKey); queryClient.setQueryData(inboxQueryKey, (current?: {pages: {posts: Activity[]}[]}) => { if (!current) { return current; } return { ...current, pages: current.pages.map((page: {posts: Activity[]}) => { return { ...page, posts: page.posts.filter((item: Activity) => item.id !== id) }; }) }; }); + // Also update outbox, liked, and profile posts caches + const previousOutbox = queryClient.getQueryData<{pages: {data: Activity[]}[]}[]>(outboxQueryKey); + queryClient.setQueryData(outboxQueryKey, (current?: {pages: {data: Activity[]}[]}) => { + if (!current) { + return current; + } + + return { + ...current, + pages: current.pages.map((page: {data: Activity[]}) => { + return { + ...page, + data: page.data.filter((item: Activity) => item.id !== id) + }; + }) + }; + }); + + // Similar updates for likedQueryKey and profilePostsQueryKey + return { previousFeed, previousInbox, + previousOutbox, + // Add other previous states }; }, onError: (_err, _variables, context) => { queryClient.setQueryData(feedQueryKey, context?.previousFeed); queryClient.setQueryData(inboxQueryKey, context?.previousInbox); + queryClient.setQueryData(outboxQueryKey, context?.previousOutbox); + // Restore other caches }apps/admin-x-activitypub/src/components/feed/FeedItem.tsx (2)
218-224
: Improve user confirmation UX for delete operationThe current confirmation dialog is minimal and only shows the post ID, which isn't user-friendly. Consider showing a more descriptive message that includes some content from the post.
const handleDelete = (postId: string) => { - const confirm = window.confirm(`Delete post\n\n${postId}\n\n?`); + // Get a readable post identifier (title or first few characters of content) + const postIdentifier = object.name || + (object.content ? stripHtml(object.content).substring(0, 50) + '...' : 'this post'); + const confirm = window.confirm(`Are you sure you want to delete "${postIdentifier}"?\n\nThis action cannot be undone.`); if (confirm) { deletePostMutation.mutate(postId); } };
259-265
: Remove TODO commentThe TODO comment about deleting posts can now be removed since you've implemented the functionality.
- // TODO: If this is your own Note/Article, you should be able to delete it - // menuItems.push({ - // id: 'delete', - // label: 'Delete', - // destructive: true, - // onClick: handleDelete - // });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/admin-x-activitypub/src/api/activitypub.ts
(4 hunks)apps/admin-x-activitypub/src/components/feed/FeedItem.tsx
(4 hunks)apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts
(1 hunks)apps/admin-x-activitypub/src/utils/posts.ts
(1 hunks)
🔇 Additional comments (7)
apps/admin-x-activitypub/src/utils/posts.ts (1)
107-107
: LGTM! Appropriate handling of author status.The explicit comparison
=== true
ensures that the property is boolean, avoiding potential issues with falsy values. This change properly supports the post deletion feature being implemented.apps/admin-x-activitypub/src/components/feed/FeedItem.tsx (2)
195-195
: LGTM! Good initialization of the delete mutation hook.The hook is properly initialized with 'index' as the handle parameter.
251-257
: LGTM! Appropriate conditional rendering of delete optionThe delete menu item is correctly displayed only when the post is authored by the current user, ensuring proper access control.
apps/admin-x-activitypub/src/api/activitypub.ts (4)
104-104
: LGTM! Clear interface extension.Adding the
authoredByMe
boolean property to thePost
interface is a clean way to track post ownership.
137-137
: Type update correctly expands HTTP method supportThe update to include 'DELETE' as a valid method type is appropriate and follows TypeScript best practices.
151-155
: Proper handling of HTTP 204 No Content responsesThe implementation correctly handles 204 status code responses by returning null, which is appropriate for successful deletion operations that don't return content.
307-310
: Well-implemented delete methodThe delete method follows the established pattern in the class, using the appropriate URL structure and HTTP method. The implementation is clean and consistent with the codebase's style.
const previousFeed = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(feedQueryKey); | ||
queryClient.setQueryData(feedQueryKey, (current?: {pages: {posts: Activity[]}[]}) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix type assertion in getQueryData
The type assertion <{pages: {posts: Activity[]}[]}[]>
doesn't match the structure returned by the query. This could lead to runtime type errors.
- const previousFeed = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(feedQueryKey);
+ const previousFeed = queryClient.getQueryData<{pages: {posts: Activity[]}[]}>(feedQueryKey);
📝 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.
const previousFeed = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(feedQueryKey); | |
queryClient.setQueryData(feedQueryKey, (current?: {pages: {posts: Activity[]}[]}) => { | |
const previousFeed = queryClient.getQueryData<{pages: {posts: Activity[]}[]}>(feedQueryKey); | |
queryClient.setQueryData(feedQueryKey, (current?: {pages: {posts: Activity[]}[]}) => { |
const previousInbox = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(inboxQueryKey); | ||
queryClient.setQueryData(inboxQueryKey, (current?: {pages: {posts: Activity[]}[]}) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix type assertion in getQueryData
Same issue as previous comment - the type assertion doesn't match the structure returned by the query.
- const previousInbox = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(inboxQueryKey);
+ const previousInbox = queryClient.getQueryData<{pages: {posts: Activity[]}[]}>(inboxQueryKey);
📝 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.
const previousInbox = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(inboxQueryKey); | |
queryClient.setQueryData(inboxQueryKey, (current?: {pages: {posts: Activity[]}[]}) => { | |
const previousInbox = queryClient.getQueryData<{pages: {posts: Activity[]}[]}>(inboxQueryKey); | |
queryClient.setQueryData(inboxQueryKey, (current?: {pages: {posts: Activity[]}[]}) => { |
7f85b92
to
b36ce55
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
♻️ Duplicate comments (2)
apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts (2)
837-837
:⚠️ Potential issueFix type assertion in getQueryData
The type assertion
<{pages: {posts: Activity[]}[]}[]>
doesn't match the expected structure returned by the query.- const previousFeed = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(QUERY_KEYS.feed); + const previousFeed = queryClient.getQueryData<{pages: {posts: Activity[]}[]}>(QUERY_KEYS.feed);
856-856
:⚠️ Potential issueFix type assertion in getQueryData for inbox
The type assertion has the same issue as the previous one.
- const previousInbox = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(QUERY_KEYS.inbox); + const previousInbox = queryClient.getQueryData<{pages: {posts: Activity[]}[]}>(QUERY_KEYS.inbox);
🧹 Nitpick comments (2)
apps/admin-x-activitypub/src/components/feed/FeedItem.tsx (2)
218-225
: Replace window.confirm with a proper modal for better UX.The confirmation currently uses a basic
window.confirm()
dialog, which doesn't align with the design system used throughout the application. This is correctly identified by your TODO comment.Consider implementing a modal dialog using the design system's components for a more consistent user experience.
const handleDelete = (postId: string) => { - // @TODO: Show confirmation modal - const confirm = window.confirm(`Delete post\n\n${postId}\n\n?`); - - if (confirm) { + // Use a design-system modal component instead of window.confirm + showModal({ + title: 'Delete post', + description: `Are you sure you want to delete this post?`, + confirmLabel: 'Delete', + cancelLabel: 'Cancel', + destructive: true, + onConfirm: () => { deleteMutation.mutate(postId); - } + } + }); };
260-266
: Remove commented-out code that's now implemented.The commented-out code is now obsolete since you've implemented the delete functionality. It should be removed to maintain code cleanliness.
-// TODO: If this is your own Note/Article, you should be able to delete it -// menuItems.push({ -// id: 'delete', -// label: 'Delete', -// destructive: true, -// onClick: handleDelete -// });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/admin-x-activitypub/src/api/activitypub.ts
(4 hunks)apps/admin-x-activitypub/src/components/feed/FeedItem.tsx
(4 hunks)apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts
(2 hunks)apps/admin-x-activitypub/src/utils/posts.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- apps/admin-x-activitypub/src/utils/posts.ts
- apps/admin-x-activitypub/src/api/activitypub.ts
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Setup
🔇 Additional comments (5)
apps/admin-x-activitypub/src/components/feed/FeedItem.tsx (3)
15-15
: Appropriate import for the new delete functionality.Good job adding the import for the delete mutation hook which will be used to implement post deletion.
195-195
: The deletion capability is properly initialized.Creating the mutation with the 'index' handle parameter is appropriate. This allows the component to perform deletion operations against the ActivityPub API.
252-258
: Conditional menu item correctly checks post ownership.The delete menu item is appropriately shown only for posts authored by the current user, which ensures users can only delete their own content.
apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts (2)
67-73
: Thread query key properly handles null ID case.Good modification to handle the case when a thread ID is null. This allows for more flexible thread querying operations, which will be useful when managing thread-related operations.
825-913
: Well-implemented deletion mutation with optimistic updatesThe implementation follows best practices for React Query mutations:
- It provides optimistic updates to immediately reflect the deletion in the UI
- It handles all relevant caches (feed, inbox, thread)
- It implements proper error handling with cache restoration
This creates a smooth user experience while maintaining data consistency.
However, consider adding a success callback parameter to allow components to show success notifications:
export function useDeleteMutationForUser(handle: string) { const queryClient = useQueryClient(); return useMutation({ async mutationFn(id: string) { const siteUrl = await getSiteUrl(); const api = createActivityPubAPI(handle, siteUrl); return api.delete(id); }, + onSuccess: () => { + // Show success toast or trigger callback if provided + showToast({ + title: 'Post deleted successfully', + type: 'success' + }); + }, onMutate: (id) => { // ... existing optimistic update code }, onError: (_err, _variables, context) => { if (!context) { return; } queryClient.setQueryData(context.previousFeed.key, context.previousFeed.data); queryClient.setQueryData(context.previousInbox.key, context.previousInbox.data); queryClient.setQueryData(context.previousThreads.key, context.previousThreads.data); + + // Show error toast + showToast({ + title: 'Failed to delete post', + type: 'error' + }); } }); }
const threadQueryKey = QUERY_KEYS.thread(null); | ||
const previousThreads = queryClient.getQueryData<{posts: Activity[]}>(threadQueryKey); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Thread cache update should be more specific
Using a null ID for the thread query key is too broad - it might affect all thread queries rather than just the specific thread containing the deleted post. Consider using specific thread IDs when possible.
🏁 Script executed:
#!/bin/bash
# Check how the thread query key is used in the codebase
rg -A 5 "QUERY_KEYS.thread"
Length of output: 1278
Thread cache update should target a specific thread
The current implementation uses QUERY_KEYS.thread(null)
, which creates an overly broad cache key and may inadvertently update all thread queries rather than just the thread associated with the deleted post. For consistency and to prevent unexpected cache invalidation, please update this usage to use the appropriate thread ID (as seen elsewhere with QUERY_KEYS.thread(id)
).
- Update the cache key to use the specific thread ID instead of
null
in this file (apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts, lines 875-876).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Post can appear in multiple threads which is why we can't target a single thread here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mike182uk Thank you for clarifying that approach. I understand now - since posts can appear in multiple threads, using QUERY_KEYS.thread(null)
is actually the correct strategy here as it allows you to update all thread caches that might contain the deleted post rather than targeting just a single thread.
This is a good implementation choice given the requirements. I'll note this information for future reviews.
✏️ Learnings added
Learnt from: mike182uk
PR: TryGhost/Ghost#22330
File: apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts:911-912
Timestamp: 2025-03-04T17:19:50.786Z
Learning: In the ActivityPub app, posts can appear in multiple threads, so when updating thread caches (e.g., when deleting a post), using QUERY_KEYS.thread(null) is the appropriate approach to update all thread caches rather than targeting a specific thread.
Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.
b36ce55
to
2c34fad
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (3)
apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts (1)
933-934
: Profile posts cache update is too broadSimilar to the thread query issue, using
QUERY_KEYS.profilePosts(null)
creates a broad cache key that may affect all profile posts queries rather than just those for the specific user. Consider using the handle of the user performing the deletion to target only their profile posts.- const profilePostsQueryKey = QUERY_KEYS.profilePosts(null); + const profilePostsQueryKey = QUERY_KEYS.profilePosts(handle);apps/admin-x-activitypub/src/components/feed/FeedItem.tsx (2)
232-239
: Replace window.confirm with a proper modal dialogThe TODO comment indicates the intention to use a confirmation modal, but the current implementation uses
window.confirm
, which doesn't match the design system of the application.Consider implementing a proper confirmation dialog using the application's design system components for a consistent user experience. For example, using a modal component from
@tryghost/admin-x-design-system
would be more consistent with the rest of the application.
274-280
: Remove commented-out codeThe commented-out code for the delete menu item is now redundant since you've implemented the functionality above. It should be removed to keep the codebase clean.
- // TODO: If this is your own Note/Article, you should be able to delete it - // menuItems.push({ - // id: 'delete', - // label: 'Delete', - // destructive: true, - // onClick: handleDelete - // });
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
apps/admin-x-activitypub/src/api/activitypub.ts
(4 hunks)apps/admin-x-activitypub/src/components/feed/ArticleModal.tsx
(3 hunks)apps/admin-x-activitypub/src/components/feed/FeedItem.tsx
(6 hunks)apps/admin-x-activitypub/src/components/modals/ViewProfileModal.tsx
(1 hunks)apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts
(3 hunks)apps/admin-x-activitypub/src/utils/posts.ts
(1 hunks)apps/admin-x-activitypub/src/views/Inbox/Inbox.tsx
(1 hunks)apps/admin-x-activitypub/src/views/Profile/Profile.tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/admin-x-activitypub/src/utils/posts.ts
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: Unit tests (Node 22.13.1)
- GitHub Check: Unit tests (Node 20.11.1)
- GitHub Check: Unit tests (Node 18.12.1)
- GitHub Check: Lint
🔇 Additional comments (20)
apps/admin-x-activitypub/src/components/modals/ViewProfileModal.tsx (1)
172-172
: Added post deletion capability based on authorship.The new
allowDelete
prop appropriately controls whether deletion functionality is available based on the post's authorship status. This ensures users can only delete posts they've authored.apps/admin-x-activitypub/src/views/Inbox/Inbox.tsx (1)
93-93
: Deletion permissions properly restricted to post authors.The
allowDelete
prop implementation correctly restricts deletion functionality to posts authored by the current user, maintaining proper authorization boundaries.apps/admin-x-activitypub/src/components/feed/ArticleModal.tsx (3)
861-862
: Appropriate disabling of delete capability for thread parents.Setting
allowDelete
tofalse
for thread parents is correct since users shouldn't be able to delete parent posts in a thread that they didn't author. This maintains thread integrity.
882-883
: Comprehensive permission check for post deletion.The implementation correctly considers both authorship (
object.authored
) and thread context (threadParents.length === 0
). This ensures users can only delete their own posts and only when they aren't replies in a thread, which prevents orphaned replies.
950-951
: Thread reply deletion permissions properly implemented.Setting
allowDelete
based onitem.object.authored
ensures users can only delete their own replies in a thread, maintaining proper authorization boundaries while allowing for normal thread management.apps/admin-x-activitypub/src/api/activitypub.ts (4)
104-104
: Implementation ofauthoredByMe
property is correctAdding the
authoredByMe
boolean to thePost
interface will help determine whether the current user has permission to delete a post.
137-137
: Method signature correctly updated to include DELETE methodThe
fetchJSON
method signature has been properly updated to includeDELETE
alongside the existingGET
andPOST
HTTP methods.
152-154
: Good handling of 204 No Content responsesReturning
null
for 204 (No Content) responses is appropriate, as these responses don't contain a response body to parse as JSON.
307-310
: Implementation of delete method follows established patternsThe
delete
method implementation is concise and follows the same pattern as other API methods in this class, ensuring consistency in the codebase.apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts (6)
50-55
: Query key structure for handling null parameters is appropriateThe modification to
profilePosts
query key function to handlenull
parameters is well implemented, supporting the cache update needs in the delete mutation.
72-77
: Query key structure for handling null parameters is appropriateSimilar to the
profilePosts
modification, thethread
query key function has been updated to handlenull
parameters correctly.
841-841
: Fix type assertion in getQueryDataThe type assertion
<{pages: {posts: Activity[]}[]}[]>
doesn't match the structure returned by the query. This could lead to runtime type errors.- const previousFeed = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(QUERY_KEYS.feed); + const previousFeed = queryClient.getQueryData<{pages: {posts: Activity[]}[]}>(QUERY_KEYS.feed);
860-860
: Fix type assertion in getQueryDataSame issue as previous comment - the type assertion doesn't match the structure returned by the query.
- const previousInbox = queryClient.getQueryData<{pages: {posts: Activity[]}[]}[]>(QUERY_KEYS.inbox); + const previousInbox = queryClient.getQueryData<{pages: {posts: Activity[]}[]}>(QUERY_KEYS.inbox);
879-880
: Thread cache update should target a specific threadThe current implementation uses
QUERY_KEYS.thread(null)
, which creates an overly broad cache key and may inadvertently update all thread queries rather than just the thread associated with the deleted post. For consistency and to prevent unexpected cache invalidation, please update this usage to use the appropriate thread ID (as seen elsewhere withQUERY_KEYS.thread(id)
).
829-992
: Well implemented delete mutation function with optimistic updatesThe
useDeleteMutationForUser
function is well structured, following the established pattern in the codebase for mutation functions. It properly:
- Initializes the mutation function with the appropriate API call
- Implements optimistic updates for all relevant caches
- Provides context for error handling and rollback
- Returns proper types
Despite the minor issues noted in other comments, this implementation is solid and will handle deletion workflow effectively.
apps/admin-x-activitypub/src/components/feed/FeedItem.tsx (5)
15-15
: Import for delete mutation hook is appropriately addedThe import for
useDeleteMutationForUser
is correctly added to support the new deletion functionality.
172-172
: New prop for deletion permissions is well designedThe optional
allowDelete
property in theFeedItemProps
interface is a good approach for conditionally enabling delete functionality based on post ownership.
187-200
: Component parameter list with default value is correctly implementedThe component signature is properly updated to include the new
allowDelete
prop with a sensible default value offalse
.
209-209
: Delete mutation hook is properly initializedThe
deleteMutation
is correctly initialized using theuseDeleteMutationForUser
hook with the 'index' handle.
266-272
: Delete menu item implementation is well integratedThe conditional rendering of the delete menu item based on the
allowDelete
prop is well implemented and integrates smoothly with the existing menu structure.
allowDelete={true} // TODO: Only true if the user is the author | ||
layout='feed' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
TODO comment identifies a permission inconsistency.
The TODO comment correctly identifies that the current implementation doesn't properly restrict deletion permissions for liked content. Users should only be able to delete content they authored, not all content they've liked.
Implement the condition as suggested in the TODO:
-allowDelete={true} // TODO: Only true if the user is the author
+allowDelete={activity.object?.authoredByMe === true}
📝 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.
allowDelete={true} // TODO: Only true if the user is the author | |
layout='feed' | |
allowDelete={activity.object?.authoredByMe === true} | |
layout='feed' |
@@ -146,6 +146,7 @@ | |||
> | |||
<FeedItem | |||
actor={activity.actor} | |||
allowDelete={true} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Unconditional deletion permission requires validation.
Setting allowDelete
to true
unconditionally for posts in the user's profile might be appropriate since users should be able to delete their own posts. However, this differs from the pattern in other components where deletion is conditionally based on the authored
property, which could lead to inconsistent behavior.
To ensure this approach is intentional, let's check if other components follow this pattern:
🏁 Script executed:
#!/bin/bash
# Find all places where allowDelete is set and check if there are inconsistencies in its usage
rg -A 5 -B 5 "allowDelete" --type tsx
Length of output: 65
Let's re-run the search with a query that correctly targets TSX files. The previous command failed because --type tsx
isn’t recognized by rg
. We can instead use the built-in type for TypeScript React files. Please verify by running the following shell script:
This should help confirm if other components conditionally set allowDelete
(perhaps based on the authored
property) or if the behavior in apps/admin-x-activitypub/src/views/Profile/Profile.tsx
is consistent with the rest of the codebase.
🏁 Script executed:
#!/bin/bash
rg -A 5 -B 5 "allowDelete" -t typescriptreact
Length of output: 85
Let's run an updated search script that targets TSX files using a filename glob pattern. This script will search for both allowDelete
and authored
patterns to check if other components use conditional deletion permission.
🏁 Script executed:
#!/bin/bash
echo "Searching for 'allowDelete' in TSX files:"
rg -A 5 -B 5 "allowDelete" -g "*.tsx"
echo -e "\nSearching for 'authored' in TSX files:"
rg -A 5 -B 5 "authored" -g "*.tsx"
Length of output: 17911
Subject: Inconsistent Deletion Permission in Profile.tsx
We found that the Profile view sets allowDelete
unconditionally to true
(line 149), whereas other components (like in Inbox, ArticleModal, and ViewProfileModal) conditionally enable deletion based on the post’s authored
property. There's even a TODO comment in Profile.tsx suggesting this needs review. Please verify if this design is intentional. If not, consider updating Profile.tsx to align with the conditional check—e.g., using activity.object.authored
—to ensure users can delete only their own posts.
751c53a
to
da2d8ae
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
apps/admin-x-activitypub/src/api/activitypub.ts
(5 hunks)apps/admin-x-activitypub/src/components/feed/ArticleModal.tsx
(8 hunks)apps/admin-x-activitypub/src/components/feed/FeedItem.tsx
(6 hunks)apps/admin-x-activitypub/src/components/modals/ViewProfileModal.tsx
(1 hunks)apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts
(5 hunks)apps/admin-x-activitypub/src/utils/posts.ts
(1 hunks)apps/admin-x-activitypub/src/views/Inbox/Inbox.tsx
(1 hunks)apps/admin-x-activitypub/src/views/Profile/Profile.tsx
(2 hunks)apps/admin-x-activitypub/test/unit/utils/posts.test.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (7)
- apps/admin-x-activitypub/src/components/modals/ViewProfileModal.tsx
- apps/admin-x-activitypub/src/utils/posts.ts
- apps/admin-x-activitypub/src/views/Inbox/Inbox.tsx
- apps/admin-x-activitypub/src/api/activitypub.ts
- apps/admin-x-activitypub/src/components/feed/ArticleModal.tsx
- apps/admin-x-activitypub/src/components/feed/FeedItem.tsx
- apps/admin-x-activitypub/src/views/Profile/Profile.tsx
🔇 Additional comments (16)
apps/admin-x-activitypub/test/unit/utils/posts.test.ts (1)
42-42
: Good addition of authoredByMe propertyThe addition of the
authoredByMe
property to the post test fixture is appropriate and aligns with the implementation of deletion functionality. This ensures the test properly validates the mapping of this property.apps/admin-x-activitypub/src/hooks/use-activity-pub-queries.ts (15)
2-2
: Good addition of Account type importThe Account type import is correctly added to support the new deletion functionality, as it's referenced in the implementation of the
useDeleteMutationForUser
function.
51-56
: Well-structured and type-safe query key handlingThe updated
profilePosts
function now properly handles null values, following a consistent pattern that returns an appropriate key array. This allows for targeting either specific profile posts or all profile posts collectively.
73-78
: Consistent query key pattern implementationThe thread query key handling follows the same pattern as the profilePosts function, correctly handling both null and string ID cases. This is good for code consistency and facilitates global cache invalidation.
650-652
: Good inclusion of authorship informationSetting the
authored
property ensures that newly created notes are correctly marked as being authored by the current user, which is essential for determining deletion permissions in the UI.
833-842
: Well-implemented mutation hook for post deletionThe
useDeleteMutationForUser
function is well-structured, accepting the user handle and creating a mutation that calls the appropriate API method. The mutation function correctly handles both post ID and optional parent ID parameters.
843-876
: Comprehensive feed cache updates for post deletionThe feed cache update logic thoroughly:
- Removes the deleted post from the feed
- Updates the parent post's reply count when appropriate
- Uses proper type narrowing with
!current
checksThis approach ensures consistent user experience after deletion.
877-910
: Inbox cache update follows consistent patternThe inbox cache update logic follows the same pattern as the feed update, maintaining code consistency while providing proper optimistic updates for the inbox.
911-938
: Thread cache invalidation is properly implementedThe thread cache update correctly:
- Uses the global thread query key (
null
)- Properly removes the deleted post from all relevant threads
- Updates parent posts' reply counts
This follows the established pattern to ensure all instances of a post are removed from cached thread data.
915-916
: Thread cache update targets all thread data appropriatelyUsing
QUERY_KEYS.thread(null)
is the correct approach since a post can appear in multiple threads. This allows the operation to update all thread caches rather than targeting a specific thread.
939-959
: Well-handled outbox cache updateThe outbox cache update properly:
- Uses the correct query key based on the user handle
- Filters out the deleted post from each page of data
- Maintains the overall structure of the outbox data
This ensures that the user's outbox is immediately updated after post deletion.
960-983
: Smart approach for liked posts cache updateThe liked posts cache update includes tracking whether the post was removed from the liked collection, which is then used to determine if the account's liked count needs to be updated. This attention to detail ensures data consistency.
984-1004
: Comprehensive profile posts cache updateThe profile posts cache update uses the global query key to update all profile posts caches, ensuring that the deleted post is removed from all relevant profile views regardless of which profile they appear in.
1005-1025
: Conditional account cache update based on like statusThe account cache update is only performed if the post was removed from the liked collection, which is an efficient approach that avoids unnecessary updates. The like count is also properly bounded to avoid negative values.
1026-1057
: Well-structured context object for error handlingThe return object for the mutation context is well-organized, containing all previous cache states needed for restoration in case of error. The conditional inclusion of previous account data based on whether it was updated is a nice optimization.
1058-1073
: Robust error handling with complete cache restorationThe
onError
handler thoroughly restores all cache states to their previous values if the mutation fails, providing a seamless rollback. The null check for context and conditional restoration of account data show careful attention to edge cases.
refs [AP-806](https://linear.app/ghost/issue/AP-806/wire-up-the-delete-buttons-to-the-deleteid-api) Added post delete mutation for posts in the `admin-x-activitypub` app
da2d8ae
to
f59aa81
Compare
refs AP-806
Added post delete mutation for posts in the
admin-x-activitypub
app