Skip to content

Updated profile tab to use dedicated account endpoints in admin-x-activitypub#22010

Merged
mike182uk merged 3 commits intomainfrom
mike-ap-648-refactor-profile-tab-to-use-account-and-follows
Jan 15, 2025
Merged

Updated profile tab to use dedicated account endpoints in admin-x-activitypub#22010
mike182uk merged 3 commits intomainfrom
mike-ap-648-refactor-profile-tab-to-use-account-and-follows

Conversation

@mike182uk
Copy link
Member

@mike182uk mike182uk commented Jan 15, 2025

refs AP-647

Updated the profile tab in admin-x-activitypub to use dedicated account endpoints. This is to remove coupling between the UI and the ActivityPub endpoints in preparation for the upcoming changes around storing accounts and follows in the database

Summary by CodeRabbit

  • New Features

    • Enhanced ActivityPub API with improved account management.
    • Added comprehensive account details retrieval.
    • Introduced new methods for fetching user follows and followers.
  • Improvements

    • Streamlined profile data handling.
    • Updated avatar and profile component logic.
    • Simplified account-related data fetching.
  • Changes

    • Removed legacy count-based methods.
    • Updated data structures for more robust account representation.
  • Version Update

    • Updated package version from 0.3.44 to 0.3.45.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 15, 2025

Warning

There were issues while running some tools. Please review the errors and either fix the tool’s configuration or disable the tool if it’s a critical failure.

🔧 eslint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

apps/admin-x-activitypub/src/components/Profile.tsx

Oops! Something went wrong! :(

ESLint: 8.44.0

ESLint couldn't find the plugin "eslint-plugin-react-hooks".

(The package "eslint-plugin-react-hooks" was not found when loaded as a Node module from the directory "/apps/admin-x-activitypub".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-react-hooks@latest --save-dev

The plugin "eslint-plugin-react-hooks" was referenced from the config file in "apps/admin-x-activitypub/.eslintrc.cjs".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

Walkthrough

The pull request introduces enhancements to the ActivityPub API and related components, focusing on user account management and profile functionality. It adds new types and interfaces for accounts, modifies data fetching mechanisms, and removes unused methods to streamline the codebase. The changes aim to provide a more structured and efficient approach to handling user account information, including followers, following, and profile details.

Changes

File Change Summary
apps/admin-x-activitypub/src/api/activitypub.ts - Added new types: AccountFollowsType, GetAccountResponse, MinimalAccount
- Created Account interface with detailed user properties
- Added getAccount and getAccountFollows methods
- Removed count-related methods
apps/admin-x-activitypub/src/components/Profile.tsx - Updated data handling for user profiles
- Modified hooks to use new account-related types
- Simplified profile data fetching
- Adjusted rendering logic for user information
apps/admin-x-activitypub/src/components/global/APAvatar.tsx - Updated APAvatarProps interface
- Modified author prop structure
- Adjusted avatar rendering logic
apps/admin-x-activitypub/src/hooks/useActivityPubQueries.ts - Added useAccountForUser and useAccountFollowsForUser hooks
- Removed count-specific hooks for followers, following, and likes
apps/admin-x-activitypub/package.json - Updated package version from 0.3.44 to 0.3.45

Sequence Diagram

sequenceDiagram
    participant User
    participant ProfileComponent
    participant ActivityPubAPI
    participant AccountHooks

    User->>ProfileComponent: View Profile
    ProfileComponent->>AccountHooks: useAccountForUser(handle)
    AccountHooks->>ActivityPubAPI: getAccount()
    ActivityPubAPI-->>AccountHooks: Return Account Details
    AccountHooks-->>ProfileComponent: Provide Account Data
    ProfileComponent->>AccountHooks: useAccountFollowsForUser(handle, type)
    AccountHooks->>ActivityPubAPI: getAccountFollows(type)
    ActivityPubAPI-->>AccountHooks: Return Follows List
    AccountHooks-->>ProfileComponent: Provide Follows Data
    ProfileComponent->>User: Display Profile Information
Loading

Possibly related PRs

  • Added table of contents to articles #22008: The changes in the main PR introduce new types and interfaces for account management, while the retrieved PR focuses on enhancing article navigation with a table of contents. Both PRs involve structural changes to data handling and user interaction, indicating a potential relationship in terms of improving user experience within the application.

Poem

🐰 A Rabbit's Ode to ActivityPub's New Groove 🌐

With types so crisp and methods so neat,
Our API now dances to a different beat
Accounts unfurl, followers take flight
Simplicity shines, everything's just right!

Hop, hop, hooray for code so clean! 🚀


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@mike182uk mike182uk changed the title Updated profile tab to use dedicated account endpoints in admin-x-activitypub Updated profile tab to use dedicated account endpoints in admin-x-activitypub Jan 15, 2025
…ivitypub

refs [AP-647](https://linear.app/ghost/issue/AP-648/refactor-profile-tab-to-use-account-and-follows)

Updated the profile tab in admin-x-activitypub to use dedicated account endpoints.
This is to remove coupling between the UI and activitypub endpoints in preparation
for the upcoming changes around storing accounts and follows in the database
@mike182uk mike182uk force-pushed the mike-ap-648-refactor-profile-tab-to-use-account-and-follows branch from 374610c to 797e003 Compare January 15, 2025 15:58
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🔭 Outside diff range comments (1)
apps/admin-x-activitypub/src/components/global/APAvatar.tsx (1)

Line range hint 71-77: Remove unsafe type casting and update utility function.

The component uses unsafe type casting to ActorProperties in both the onClick handler and title calculation. This could lead to runtime errors if the expected properties from ActorProperties are missing.

Consider updating the getUsername utility to work with the new author type structure:

  1. Update the utility function:
// Before
function getUsername(author: ActorProperties): string

// After
function getUsername(author: { name: string; /* add required properties */ }): string
  1. Remove the type casting:
-getUsername(author as ActorProperties)
+getUsername(author)
🧹 Nitpick comments (4)
apps/admin-x-activitypub/src/components/global/APAvatar.tsx (1)

Line range hint 1-116: Consider completing the type migration.

The changes are part of a larger effort to update account-related types, as mentioned in the PR objectives. To maintain consistency and type safety:

  1. Complete the migration away from ActorProperties
  2. Update all related utility functions to work with the new types
  3. Document the new type structure for other developers

This will help prepare for the future modifications related to accounts storage mentioned in the PR objectives.

apps/admin-x-activitypub/src/components/Profile.tsx (3)

384-384: Add a unique key prop to elements in lists

The element inside the customFields.map function lacks a unique key prop, which is necessary for React to properly track elements in a list.

Apply this diff to add the key prop:

- {customFields.map(customField => (
+ {customFields.map(customField => (
+     <span key={customField.name} className='mt-3 line-clamp-1 flex flex-col text-[1.5rem]'>
      <span className={`text-xs font-semibold`}>{customField.name}</span>
      <span dangerouslySetInnerHTML={{__html: customField.value}} className='ap-profile-content truncate'/>
     </span>
))}
🧰 Tools
🪛 Biome (1.9.4)

[error] 384-384: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


318-323: Avoid using non-null assertions to prevent potential runtime errors

Using the non-null assertion operator ! on account can lead to runtime errors if account is null or undefined. Consider checking that account is defined before accessing its properties.

Apply this diff to safely access account.customFields:

- const customFields = Object.keys(account?.customFields || {}).map((key) => {
-     return {
-         name: key,
-         value: account!.customFields[key]
-     };
- }) || [];
+ const customFields = account?.customFields
+     ? Object.keys(account.customFields).map((key) => ({
+         name: key,
+         value: account.customFields[key]
+     }))
+     : [];

200-201: Remove redundant key prop from child element

Having a key prop on both the React.Fragment and its child ActivityItem is unnecessary. The key prop should be applied to the outermost element in the list. You can remove the redundant key prop from ActivityItem.

Apply this diff:

<React.Fragment key={account.id}>
    <ActivityItem
-       key={account.id}
        onClick={() => handleAccountClick(account.handle)}
    >
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 73f8bcf and 374610ce8874b47cdbf292ba39b9e3efed75d654.

📒 Files selected for processing (4)
  • apps/admin-x-activitypub/src/api/activitypub.ts (2 hunks)
  • apps/admin-x-activitypub/src/components/Profile.tsx (12 hunks)
  • apps/admin-x-activitypub/src/components/global/APAvatar.tsx (1 hunks)
  • apps/admin-x-activitypub/src/hooks/useActivityPubQueries.ts (2 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
apps/admin-x-activitypub/src/components/Profile.tsx

[error] 380-380: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


[error] 384-384: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 386-386: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🔇 Additional comments (6)
apps/admin-x-activitypub/src/components/global/APAvatar.tsx (2)

Line range hint 25-28: Well-implemented state management and null safety!

The component correctly handles the author prop with proper optional chaining and state synchronization.


12-17: Inconsistent type usage detected.

While the author prop type has been updated to a more specific structure, the component still casts it back to ActorProperties in the onClick handler. This suggests an incomplete migration from the ActorProperties type.

Let's verify the usage of ActorProperties in the codebase:

apps/admin-x-activitypub/src/components/Profile.tsx (2)

380-380: ⚠️ Potential issue

Avoid using dangerouslySetInnerHTML to prevent XSS vulnerabilities

Using dangerouslySetInnerHTML can expose users to XSS attacks. Please ensure that account.bio is properly sanitized before rendering. Alternatively, consider rendering the bio as plain text or using a safe HTML rendering library.

🧰 Tools
🪛 Biome (1.9.4)

[error] 380-380: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


386-386: ⚠️ Potential issue

Avoid using dangerouslySetInnerHTML to prevent XSS vulnerabilities

Using dangerouslySetInnerHTML can expose users to XSS attacks. Please ensure that customField.value is properly sanitized before rendering. Consider rendering the content as plain text or using a safe HTML rendering library.

🧰 Tools
🪛 Biome (1.9.4)

[error] 386-386: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

apps/admin-x-activitypub/src/api/activitypub.ts (1)

409-449: LGTM!

The new methods and types introduced align with the enhancements made to the account management features. Error handling is properly implemented.

apps/admin-x-activitypub/src/hooks/useActivityPubQueries.ts (1)

532-556: LGTM!

The new hooks useAccountForUser and useAccountFollowsForUser are well implemented and integrate properly with the existing codebase.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (3)
apps/admin-x-activitypub/src/components/Profile.tsx (2)

44-52: Add explicit error handling for unknown data structures.

The data flattening logic should handle unknown data structures explicitly.

 const items = (data?.pages.flatMap((page) => {
     if ('data' in page) {
         return page.data;
     } else if ('accounts' in page) {
         return page.accounts as TData[];
     }
-    return [];
+    console.warn('Unknown data structure in page:', page);
+    return [];
 }) ?? []);

Line range hint 294-314: Consider using default values for counters.

Using || 0 could lead to issues with falsy values. Consider using nullish coalescing.

-counter: account?.likedCount || 0
+counter: account?.likedCount ?? 0

-counter: account?.followingCount || 0
+counter: account?.followingCount ?? 0

-counter: account?.followerCount || 0
+counter: account?.followerCount ?? 0
apps/admin-x-activitypub/src/hooks/useActivityPubQueries.ts (1)

533-542: Add error handling to account query.

Consider adding error handling to provide better user feedback.

 export function useAccountForUser(handle: string) {
     return useQuery({
         queryKey: [`account:${handle}`],
         async queryFn() {
             const siteUrl = await getSiteUrl();
             const api = createActivityPubAPI(handle, siteUrl);
-            return api.getAccount();
+            try {
+                return await api.getAccount();
+            } catch (error) {
+                console.error('Failed to fetch account:', error);
+                throw error;
+            }
         }
     });
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 374610ce8874b47cdbf292ba39b9e3efed75d654 and 797e003.

📒 Files selected for processing (4)
  • apps/admin-x-activitypub/src/api/activitypub.ts (2 hunks)
  • apps/admin-x-activitypub/src/components/Profile.tsx (12 hunks)
  • apps/admin-x-activitypub/src/components/global/APAvatar.tsx (1 hunks)
  • apps/admin-x-activitypub/src/hooks/useActivityPubQueries.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/admin-x-activitypub/src/components/global/APAvatar.tsx
🧰 Additional context used
🪛 Biome (1.9.4)
apps/admin-x-activitypub/src/components/Profile.tsx

[error] 380-380: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


[error] 384-384: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 386-386: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🔇 Additional comments (4)
apps/admin-x-activitypub/src/api/activitypub.ts (3)

46-72: Well-structured account types and interfaces!

The new account-related types are well-designed:

  • Account interface provides a comprehensive structure for user profiles
  • MinimalAccount type efficiently uses Pick to optimize data transfer
  • Clear separation between full and minimal account information

410-412: LGTM! Consistent URL getter implementation.

The accountApiUrl getter follows the established pattern for API endpoint construction.


420-449: LGTM! Robust implementation of account follows retrieval.

The method includes:

  • Proper pagination support
  • Thorough null checks
  • Array type validation
  • Consistent error handling
apps/admin-x-activitypub/src/hooks/useActivityPubQueries.ts (1)

544-556: LGTM! Well-implemented infinite query hook.

The implementation follows React Query best practices:

  • Proper compound query key
  • Correct pagination handling
  • Type-safe implementation

Comment on lines +414 to +418
async getAccount(): Promise<GetAccountResponse> {
const json = await this.fetchJSON(this.accountApiUrl);

return json as GetAccountResponse;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add null response handling.

The method should handle null responses consistently with other methods in the class.

 async getAccount(): Promise<GetAccountResponse> {
     const json = await this.fetchJSON(this.accountApiUrl);
+    if (json === null) {
+        throw new Error('Failed to fetch account');
+    }
     return json as GetAccountResponse;
 }
📝 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.

Suggested change
async getAccount(): Promise<GetAccountResponse> {
const json = await this.fetchJSON(this.accountApiUrl);
return json as GetAccountResponse;
}
async getAccount(): Promise<GetAccountResponse> {
const json = await this.fetchJSON(this.accountApiUrl);
if (json === null) {
throw new Error('Failed to fetch account');
}
return json as GetAccountResponse;
}

Comment on lines +380 to +386
dangerouslySetInnerHTML={{__html: account?.bio ?? ''}}
className='ap-profile-content mt-3 text-[1.5rem] [&>p]:mb-3'
/>
{attachments.map(attachment => (
{customFields.map(customField => (
<span className='mt-3 line-clamp-1 flex flex-col text-[1.5rem]'>
<span className={`text-xs font-semibold`}>{attachment.name}</span>
<span dangerouslySetInnerHTML={{__html: attachment.value}} className='ap-profile-content truncate'/>
<span className={`text-xs font-semibold`}>{customField.name}</span>
<span dangerouslySetInnerHTML={{__html: customField.value}} className='ap-profile-content truncate'/>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Sanitize HTML content before rendering.

The use of dangerouslySetInnerHTML without sanitization poses a security risk for XSS attacks.

Consider using a sanitization library like DOMPurify:

+import DOMPurify from 'dompurify';

-dangerouslySetInnerHTML={{__html: account?.bio ?? ''}}
+dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(account?.bio ?? '')}}

-dangerouslySetInnerHTML={{__html: customField.value}}
+dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(customField.value)}}
📝 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.

Suggested change
dangerouslySetInnerHTML={{__html: account?.bio ?? ''}}
className='ap-profile-content mt-3 text-[1.5rem] [&>p]:mb-3'
/>
{attachments.map(attachment => (
{customFields.map(customField => (
<span className='mt-3 line-clamp-1 flex flex-col text-[1.5rem]'>
<span className={`text-xs font-semibold`}>{attachment.name}</span>
<span dangerouslySetInnerHTML={{__html: attachment.value}} className='ap-profile-content truncate'/>
<span className={`text-xs font-semibold`}>{customField.name}</span>
<span dangerouslySetInnerHTML={{__html: customField.value}} className='ap-profile-content truncate'/>
dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(account?.bio ?? '')}}
className='ap-profile-content mt-3 text-[1.5rem] [&>p]:mb-3'
/>
{customFields.map(customField => (
<span className='mt-3 line-clamp-1 flex flex-col text-[1.5rem]'>
<span className={`text-xs font-semibold`}>{customField.name}</span>
<span dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(customField.value)}} className='ap-profile-content truncate'/>
🧰 Tools
🪛 Biome (1.9.4)

[error] 380-380: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


[error] 384-384: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 386-386: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

Comment on lines +383 to 387
{customFields.map(customField => (
<span className='mt-3 line-clamp-1 flex flex-col text-[1.5rem]'>
<span className={`text-xs font-semibold`}>{attachment.name}</span>
<span dangerouslySetInnerHTML={{__html: attachment.value}} className='ap-profile-content truncate'/>
<span className={`text-xs font-semibold`}>{customField.name}</span>
<span dangerouslySetInnerHTML={{__html: customField.value}} className='ap-profile-content truncate'/>
</span>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add key prop to custom field spans.

React requires a unique key for elements in an iterable.

-<span className='mt-3 line-clamp-1 flex flex-col text-[1.5rem]'>
+<span key={customField.name} className='mt-3 line-clamp-1 flex flex-col text-[1.5rem]'>
📝 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.

Suggested change
{customFields.map(customField => (
<span className='mt-3 line-clamp-1 flex flex-col text-[1.5rem]'>
<span className={`text-xs font-semibold`}>{attachment.name}</span>
<span dangerouslySetInnerHTML={{__html: attachment.value}} className='ap-profile-content truncate'/>
<span className={`text-xs font-semibold`}>{customField.name}</span>
<span dangerouslySetInnerHTML={{__html: customField.value}} className='ap-profile-content truncate'/>
</span>
{customFields.map(customField => (
<span key={customField.name} className='mt-3 line-clamp-1 flex flex-col text-[1.5rem]'>
<span className={`text-xs font-semibold`}>{customField.name}</span>
<span dangerouslySetInnerHTML={{__html: customField.value}} className='ap-profile-content truncate'/>
</span>
🧰 Tools
🪛 Biome (1.9.4)

[error] 384-384: Missing key property for this element in iterable.

The order of the items may change, and having a key can help React identify which item was moved.
Check the React documentation.

(lint/correctness/useJsxKeyInIterable)


[error] 386-386: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

♻️ Duplicate comments (1)
apps/admin-x-activitypub/src/components/Profile.tsx (1)

380-386: ⚠️ Potential issue

Sanitize HTML content before rendering.

The use of dangerouslySetInnerHTML without sanitization poses a security risk for XSS attacks.

As mentioned in the previous review, consider using DOMPurify:

+import DOMPurify from 'dompurify';

-dangerouslySetInnerHTML={{__html: account?.bio ?? ''}}
+dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(account?.bio ?? '')}}

-dangerouslySetInnerHTML={{__html: customField.value}}
+dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(customField.value)}}
🧰 Tools
🪛 Biome (1.9.4)

[error] 380-380: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


[error] 386-386: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🧹 Nitpick comments (3)
apps/admin-x-activitypub/src/components/Profile.tsx (3)

27-27: Consider enhancing error handling in data flattening.

While the type union and data structure handling is good, the empty array fallback might hide potential errors.

Consider this improvement:

-        return [];
+        console.warn('Unexpected data structure in page:', page);
+        return [];

Also applies to: 44-52


179-183: Consider memoizing the click handler.

The handler function could be memoized using useCallback to prevent unnecessary re-renders in child components.

-const handleAccountClick = (handle: string) => {
+const handleAccountClick = useCallback((handle: string) => {
    NiceModal.show(ViewProfileModal, {
        profile: handle
    });
-};
+}, []);

Line range hint 186-216: Consider extracting shared code into a reusable component.

The FollowingTab and FollowersTab components share significant code structure. Consider creating a shared component to reduce duplication.

Example refactor:

interface AccountListProps {
    accounts: MinimalAccount[];
    onAccountClick: (handle: string) => void;
}

const AccountList: React.FC<AccountListProps> = ({accounts, onAccountClick}) => (
    <List>
        {accounts.map((account, index) => (
            <React.Fragment key={account.id}>
                <ActivityItem
                    key={account.id}
                    onClick={() => onAccountClick(account.handle)}
                >
                    <APAvatar author={{
                        icon: { url: account.avatarUrl },
                        name: account.name
                    }} />
                    <div>
                        <div className='text-grey-600'>
                            <span className='mr-1 font-bold text-black'>{account.name}</span>
                            <div className='text-sm'>{account.handle}</div>
                        </div>
                    </div>
                </ActivityItem>
                {index < accounts.length - 1 && <Separator />}
            </React.Fragment>
        ))}
    </List>
);

Also applies to: 227-257

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 797e003 and b721147.

📒 Files selected for processing (2)
  • apps/admin-x-activitypub/package.json (1 hunks)
  • apps/admin-x-activitypub/src/components/Profile.tsx (12 hunks)
✅ Files skipped from review due to trivial changes (1)
  • apps/admin-x-activitypub/package.json
🧰 Additional context used
🪛 Biome (1.9.4)
apps/admin-x-activitypub/src/components/Profile.tsx

[error] 380-380: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


[error] 386-386: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)

🔇 Additional comments (1)
apps/admin-x-activitypub/src/components/Profile.tsx (1)

8-15: LGTM! Import and type changes align with PR objectives.

The new imports and type definitions properly support the transition to dedicated account endpoints, improving the separation of concerns.

@mike182uk mike182uk merged commit 6bc164c into main Jan 15, 2025
18 checks passed
@mike182uk mike182uk deleted the mike-ap-648-refactor-profile-tab-to-use-account-and-follows branch January 15, 2025 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant