Skip to content

Add socialweb account migration settings UI#27957

Merged
mike182uk merged 4 commits into
TryGhost:mainfrom
JohnONolan:codex/mastodon-migration-ui
May 20, 2026
Merged

Add socialweb account migration settings UI#27957
mike182uk merged 4 commits into
TryGhost:mainfrom
JohnONolan:codex/mastodon-migration-ui

Conversation

@JohnONolan
Copy link
Copy Markdown
Member

@JohnONolan JohnONolan commented May 18, 2026

Added support for inbound social web account migration, so that (eg) you can migrate a mastodon profile to Ghost, and the followers will move over:

Depends on: TryGhost/ActivityPub#1804

https://docs.joinmastodon.org/user/moving/#move

CleanShot 2026-05-18 at 12 57 08@2x

Summary

  • Add an ActivityPub preferences page for account migration aliases
  • Add client API/query hooks for listing, creating, and removing aliases
  • Show existing aliases newest-first and keep the aliases section hidden when there are none
  • Add acceptance coverage for creating aliases, existing aliases, and load failures

Why

Ghost Admin needs a UI for configuring the old Mastodon/social web account before the user starts the move from their old account. The UI calls the new ActivityPub alias API and keeps the workflow inside ActivityPub preferences.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 18, 2026

Review Change Stack

Note

Reviews paused

It 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 reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This PR adds account alias management to the ActivityPub module. It introduces API contracts and methods (getAccountAliases, addAccountAlias, removeAccountAlias) that communicate with a Ghost endpoint, wraps these in React Query hooks for caching and state management, and implements a new AccountMigration component that lets users manage account aliases via the preferences UI. The route is registered at /preferences/move, and the settings page now links to it. Unit tests validate API method behavior with defensive handling for empty responses, and acceptance tests cover alias creation, listing, unlink failures, and load failures.

Suggested reviewers

  • EvanHahn
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding a UI for social web account migration settings in ActivityPub preferences.
Description check ✅ Passed The description is directly related to the changeset, providing context about inbound social web account migration and listing the specific UI/API additions implemented.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
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: 2

🤖 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/activitypub/package.json`:
- Line 3: The package.json version was incorrectly bumped only to a patch
release ("version": "3.1.24") despite introducing new features; update the
"version" field in apps/activitypub/package.json from 3.1.24 to 3.2.0 so the
package reflects a minor release for the added API methods, React Query hooks,
UI components and routes.

In `@apps/activitypub/src/api/activitypub.ts`:
- Around line 519-531: The methods addAccountAlias and removeAccountAlias
currently cast fetchJSON() results directly to AccountAliasesResponse even
though fetchJSON can return null for 202/204; update both functions
(addAccountAlias and removeAccountAlias) to check if json is null and if so
return a safe default AccountAliasesResponse (e.g. an object with aliases: []
and destination: null/empty) before casting/returning, otherwise return the
parsed json; reference fetchJSON to locate the call and AccountAliasesResponse
as the return type to ensure callers always receive a non-null structure.
🪄 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: f727546a-f143-473d-a3c7-180ee33603ff

📥 Commits

Reviewing files that changed from the base of the PR and between 82375b6 and 67c4a32.

📒 Files selected for processing (8)
  • apps/activitypub/package.json
  • apps/activitypub/src/api/activitypub.test.ts
  • apps/activitypub/src/api/activitypub.ts
  • apps/activitypub/src/hooks/use-activity-pub-queries.ts
  • apps/activitypub/src/routes.tsx
  • apps/activitypub/src/views/preferences/components/mastodon-migration.tsx
  • apps/activitypub/src/views/preferences/components/settings.tsx
  • apps/activitypub/test/acceptance/preferences.test.ts

Comment thread apps/activitypub/package.json Outdated
Comment thread apps/activitypub/src/api/activitypub.ts
@JohnONolan JohnONolan force-pushed the codex/mastodon-migration-ui branch from 67c4a32 to 46f1345 Compare May 18, 2026 19:51
Copy link
Copy Markdown
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.

♻️ Duplicate comments (1)
apps/activitypub/package.json (1)

3-3: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Bump version to 3.2.0 for this feature release.

The version was bumped to 3.1.25 (PATCH increment), but this PR introduces new features: API methods for account aliases, React Query hooks, a preferences UI route and component, settings integration, and acceptance tests. Per the project's versioning policy, patch increments are reserved for bug fixes, while minor increments should be used for new feature releases. Bump to 3.2.0 instead.

📦 Proposed fix
-  "version": "3.1.25",
+  "version": "3.2.0",
🤖 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/activitypub/package.json` at line 3, Update the package.json version
from "3.1.25" to "3.2.0" to reflect the new feature release; locate the
"version" field in apps/activitypub's package.json and change its value to 3.2.0
so the release semantics match the added API methods, React Query hooks,
preferences UI/route, settings integration, and acceptance tests.
🤖 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/activitypub/package.json`:
- Line 3: Update the package.json version from "3.1.25" to "3.2.0" to reflect
the new feature release; locate the "version" field in apps/activitypub's
package.json and change its value to 3.2.0 so the release semantics match the
added API methods, React Query hooks, preferences UI/route, settings
integration, and acceptance tests.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: bfe66a19-3662-41d3-8eff-29b71705d869

📥 Commits

Reviewing files that changed from the base of the PR and between 67c4a32 and 46f1345.

📒 Files selected for processing (8)
  • apps/activitypub/package.json
  • apps/activitypub/src/api/activitypub.test.ts
  • apps/activitypub/src/api/activitypub.ts
  • apps/activitypub/src/hooks/use-activity-pub-queries.ts
  • apps/activitypub/src/routes.tsx
  • apps/activitypub/src/views/preferences/components/mastodon-migration.tsx
  • apps/activitypub/src/views/preferences/components/settings.tsx
  • apps/activitypub/test/acceptance/preferences.test.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • apps/activitypub/src/views/preferences/components/settings.tsx
  • apps/activitypub/src/api/activitypub.ts
  • apps/activitypub/src/routes.tsx
  • apps/activitypub/test/acceptance/preferences.test.ts
  • apps/activitypub/src/api/activitypub.test.ts
  • apps/activitypub/src/hooks/use-activity-pub-queries.ts
  • apps/activitypub/src/views/preferences/components/mastodon-migration.tsx

@JohnONolan JohnONolan force-pushed the codex/mastodon-migration-ui branch from 46f1345 to c5ad5c1 Compare May 18, 2026 19:56
Copy link
Copy Markdown
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: 1

🤖 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/activitypub/src/views/preferences/components/mastodon-migration.tsx`:
- Around line 60-61: The unlink failure is being stored in handleError (useState
handleError / setHandleError), which incorrectly marks the input invalid and
shows a field-level message; introduce a dedicated state (e.g., aliasActionError
and setAliasActionError) and use that for alias/unlink action errors instead of
handleError; update the unlink/remove flow (where setHandleError is currently
called around the removingAlias logic) to call setAliasActionError on failure
and clear it on success, and ensure the input validation and rendering logic
(the code that checks handleError to set input invalid and to render the
field-level message) continue to only reference handleError so only validation
errors affect the input UI.
🪄 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: d91537da-f19e-40ce-83d2-604cfd6338fb

📥 Commits

Reviewing files that changed from the base of the PR and between 46f1345 and c5ad5c1.

📒 Files selected for processing (8)
  • apps/activitypub/package.json
  • apps/activitypub/src/api/activitypub.test.ts
  • apps/activitypub/src/api/activitypub.ts
  • apps/activitypub/src/hooks/use-activity-pub-queries.ts
  • apps/activitypub/src/routes.tsx
  • apps/activitypub/src/views/preferences/components/mastodon-migration.tsx
  • apps/activitypub/src/views/preferences/components/settings.tsx
  • apps/activitypub/test/acceptance/preferences.test.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/activitypub/package.json
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/activitypub/src/api/activitypub.test.ts
  • apps/activitypub/src/api/activitypub.ts
  • apps/activitypub/test/acceptance/preferences.test.ts
  • apps/activitypub/src/hooks/use-activity-pub-queries.ts
  • apps/activitypub/src/views/preferences/components/settings.tsx

@JohnONolan JohnONolan force-pushed the codex/mastodon-migration-ui branch from c5ad5c1 to 0461364 Compare May 18, 2026 20:05
@JohnONolan JohnONolan changed the title Add account migration settings UI Add socialweb account migration settings UI May 18, 2026
@JohnONolan JohnONolan force-pushed the codex/mastodon-migration-ui branch from 0461364 to 2705e8b Compare May 18, 2026 20:07
Adds the ActivityPub preferences page for creating and removing account aliases used by Mastodon-to-Ghost follower migration.\n\nIncludes the client API/query hooks, settings route, empty/error/loading behavior, and acceptance coverage for creating aliases, existing alias ordering, and load failures.
@JohnONolan JohnONolan force-pushed the codex/mastodon-migration-ui branch from 2705e8b to fd4bf56 Compare May 18, 2026 20:15
Copy link
Copy Markdown
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: 1

🤖 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/activitypub/src/views/preferences/components/account-migration.tsx`:
- Around line 182-189: The button currently replaces its content with just
<LoadingIndicator> when removingAlias === alias.apId, which removes the readable
name for assistive tech; instead keep an accessible label by preserving the
"Unlink" text (or adding an explicit aria-label) when rendering the loading
state and mark the spinner aria-hidden so screen readers don't announce it.
Update the Button in account-migration.tsx (the button using removingAlias,
alias.apId, handleRemoveAlias, <LoadingIndicator> and <LucideIcon.Trash2>) to
render the spinner alongside a visually-hidden or visible "Unlink" text (or set
aria-label="Unlink" on the Button) while disabled, ensuring the spinner has
aria-hidden="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: c92f9181-b4fe-46c9-9300-6a111873614b

📥 Commits

Reviewing files that changed from the base of the PR and between 0461364 and 859f3e6.

📒 Files selected for processing (8)
  • apps/activitypub/package.json
  • apps/activitypub/src/api/activitypub.test.ts
  • apps/activitypub/src/api/activitypub.ts
  • apps/activitypub/src/hooks/use-activity-pub-queries.ts
  • apps/activitypub/src/routes.tsx
  • apps/activitypub/src/views/preferences/components/account-migration.tsx
  • apps/activitypub/src/views/preferences/components/settings.tsx
  • apps/activitypub/test/acceptance/preferences.test.ts
✅ Files skipped from review due to trivial changes (1)
  • apps/activitypub/package.json
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/activitypub/src/routes.tsx
  • apps/activitypub/src/api/activitypub.ts
  • apps/activitypub/src/api/activitypub.test.ts
  • apps/activitypub/src/views/preferences/components/settings.tsx
  • apps/activitypub/test/acceptance/preferences.test.ts
  • apps/activitypub/src/hooks/use-activity-pub-queries.ts

Comment on lines +182 to +189
<Button
className='shrink-0 px-0 font-medium text-gray-700 hover:text-red dark:text-gray-600 dark:hover:text-red'
disabled={removingAlias === alias.apId}
variant='link'
onClick={() => handleRemoveAlias(alias.apId)}
>
{removingAlias === alias.apId ? <LoadingIndicator size='sm' /> : <><LucideIcon.Trash2 size={15} /> Unlink</>}
</Button>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep an accessible label while unlink is loading.

At Line 188, replacing the entire button content with a spinner can leave the control without a readable name for assistive tech. Keep/restore an accessible text label in the loading state.

Suggested fix
-                                            {removingAlias === alias.apId ? <LoadingIndicator size='sm' /> : <><LucideIcon.Trash2 size={15} /> Unlink</>}
+                                            {removingAlias === alias.apId ? (
+                                                <>
+                                                    <LoadingIndicator size='sm' />
+                                                    <span className='sr-only'>Unlinking alias...</span>
+                                                </>
+                                            ) : (
+                                                <>
+                                                    <LucideIcon.Trash2 size={15} /> Unlink
+                                                </>
+                                            )}
📝 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
<Button
className='shrink-0 px-0 font-medium text-gray-700 hover:text-red dark:text-gray-600 dark:hover:text-red'
disabled={removingAlias === alias.apId}
variant='link'
onClick={() => handleRemoveAlias(alias.apId)}
>
{removingAlias === alias.apId ? <LoadingIndicator size='sm' /> : <><LucideIcon.Trash2 size={15} /> Unlink</>}
</Button>
<Button
className='shrink-0 px-0 font-medium text-gray-700 hover:text-red dark:text-gray-600 dark:hover:text-red'
disabled={removingAlias === alias.apId}
variant='link'
onClick={() => handleRemoveAlias(alias.apId)}
>
{removingAlias === alias.apId ? (
<>
<LoadingIndicator size='sm' />
<span className='sr-only'>Unlinking alias...</span>
</>
) : (
<>
<LucideIcon.Trash2 size={15} /> Unlink
</>
)}
</Button>
🤖 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/activitypub/src/views/preferences/components/account-migration.tsx`
around lines 182 - 189, The button currently replaces its content with just
<LoadingIndicator> when removingAlias === alias.apId, which removes the readable
name for assistive tech; instead keep an accessible label by preserving the
"Unlink" text (or adding an explicit aria-label) when rendering the loading
state and mark the spinner aria-hidden so screen readers don't announce it.
Update the Button in account-migration.tsx (the button using removingAlias,
alias.apId, handleRemoveAlias, <LoadingIndicator> and <LucideIcon.Trash2>) to
render the spinner alongside a visually-hidden or visible "Unlink" text (or set
aria-label="Unlink" on the Button) while disabled, ensuring the spinner has
aria-hidden="true".

@mike182uk mike182uk merged commit 1dc0370 into TryGhost:main May 20, 2026
41 checks passed
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.

2 participants