Skip to content

Redirect /ghost/#/my-profile to current staff profile#26588

Merged
kevinansfield merged 6 commits intoTryGhost:mainfrom
kevinansfield:codex/admin-profile-redirect
Feb 26, 2026
Merged

Redirect /ghost/#/my-profile to current staff profile#26588
kevinansfield merged 6 commits intoTryGhost:mainfrom
kevinansfield:codex/admin-profile-redirect

Conversation

@kevinansfield
Copy link
Copy Markdown
Member

@kevinansfield kevinansfield commented Feb 25, 2026

no issue

  • redirects /ghost/#/my-profile to the signed-in users actual staff slug route in the settings app

ref n/a

Added settings app route normalization and tests, including an e2e deep-link check.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 25, 2026

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

Adds a MyProfileRedirect React component that reads the current user and redirects /my-profile to /settings/staff/{currentUser.slug}. Registers a "my-profile" route using that component. Introduces an AdminStaffDetailsPage page object with locators and gotoMyProfile, re-exports it from admin settings helpers, and adds a Playwright e2e test that navigates to /ghost/#/my-profile, inspects the user-detail-modal slug, and asserts the URL ends with /ghost/#/settings/staff/{slug}.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Redirect /ghost/#/my-profile to current staff profile' clearly and specifically describes the main change: adding a redirect mechanism for the /my-profile route to the user's actual staff profile.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description check ✅ Passed The PR description accurately describes the changeset, explaining the redirect from /ghost/#/my-profile to the signed-in user's actual staff slug route.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

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

@kevinansfield kevinansfield changed the title 🐛 Redirect staff/me to current staff profile Redirect /ghost/#/staff/me to current staff profile Feb 25, 2026
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 the current code and only fix it if needed.

Inline comments:
In `@e2e/tests/admin/settings/staff.test.ts`:
- Around line 15-17: Replace the dynamic RegExp URL assertion to avoid RegExp
construction: instead of using new RegExp(`/ghost/#/settings/staff/${slug}$`),
assert against the resolved page URL (e.g., use page.url() and
expect(...).toContain(...) or a pre-escaped string) referencing the existing
slug variable and page object so the line becomes a simple substring check
(expect(page.url()).toContain(`/ghost/#/settings/staff/${slug}`)) rather than
constructing a RegExp for toHaveURL.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 475004c and ca4c2a3.

📒 Files selected for processing (4)
  • apps/admin-x-settings/src/components/providers/settings-router.tsx
  • apps/admin-x-settings/src/components/settings/general/user-detail-modal.tsx
  • apps/admin-x-settings/test/acceptance/permissions.test.ts
  • e2e/tests/admin/settings/staff.test.ts

Comment thread e2e/tests/admin/settings/staff.test.ts Outdated
ref n/a

Sorted imports and updated the e2e assertion style to satisfy package lint rules.
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)
e2e/tests/admin/settings/staff.test.ts (1)

12-13: LGTM — dynamic RegExp construction correctly replaced with static literals.

Both URL and input-value assertions now use static regex literals, eliminating the prior ReDoS risk flagged in the previous review.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/tests/admin/settings/staff.test.ts` around lines 12 - 13, Replace any
dynamically constructed RegExp usage with static regex literals in the staff
settings assertions: update the slugInput assertion (used with toHaveValue) and
the page URL assertion (used with toHaveURL) to use static regex literals like
/^(?!me$).+/ and /\/ghost\/#\/settings\/staff\/(?!me$)[^/]+$/ respectively to
avoid ReDoS risks; ensure the assertions reference the existing slugInput
variable and page object and keep the negative lookahead patterns intact.
🧹 Nitpick comments (1)
e2e/tests/admin/settings/staff.test.ts (1)

1-14: Consider introducing a Page Object per ADR-0002.

All locator and navigation logic is currently inlined. Per the ADR-0002 requirement to use the Page Object pattern, the UserDetailModal interactions and the staff page navigation could be encapsulated in a dedicated Page Object (e.g., StaffPage / UserDetailModalPage), making them reusable across future staff-settings tests.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/tests/admin/settings/staff.test.ts` around lines 1 - 14, Extract the
inline navigation and locator logic from the test "redirects staff/me to the
current user profile" into Page Object(s) per ADR-0002: create a StaffPage with
a method to navigateToStaffMe (wraps page.goto('/ghost/#/settings/staff/me'))
and a getter for the UserDetailModal, and create a UserDetailModalPage exposing
slugInput and assertions (e.g., isVisible, getSlugValue) so the test uses
StaffPage.navigateToStaffMe(), StaffPage.userDetailModal.getSlugValue() /
isVisible() and StaffPage.assertUrlIsUserProfile() instead of directly calling
page.goto, page.getByTestId('user-detail-modal'), or
userDetailModal.getByRole('textbox', {name: 'Slug'}); update the test to import
and use these Page Objects.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@e2e/tests/admin/settings/staff.test.ts`:
- Around line 12-13: Replace any dynamically constructed RegExp usage with
static regex literals in the staff settings assertions: update the slugInput
assertion (used with toHaveValue) and the page URL assertion (used with
toHaveURL) to use static regex literals like /^(?!me$).+/ and
/\/ghost\/#\/settings\/staff\/(?!me$)[^/]+$/ respectively to avoid ReDoS risks;
ensure the assertions reference the existing slugInput variable and page object
and keep the negative lookahead patterns intact.

---

Nitpick comments:
In `@e2e/tests/admin/settings/staff.test.ts`:
- Around line 1-14: Extract the inline navigation and locator logic from the
test "redirects staff/me to the current user profile" into Page Object(s) per
ADR-0002: create a StaffPage with a method to navigateToStaffMe (wraps
page.goto('/ghost/#/settings/staff/me')) and a getter for the UserDetailModal,
and create a UserDetailModalPage exposing slugInput and assertions (e.g.,
isVisible, getSlugValue) so the test uses StaffPage.navigateToStaffMe(),
StaffPage.userDetailModal.getSlugValue() / isVisible() and
StaffPage.assertUrlIsUserProfile() instead of directly calling page.goto,
page.getByTestId('user-detail-modal'), or userDetailModal.getByRole('textbox',
{name: 'Slug'}); update the test to import and use these Page Objects.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca4c2a3 and a941cd9.

📒 Files selected for processing (2)
  • apps/admin-x-settings/src/components/providers/settings-router.tsx
  • e2e/tests/admin/settings/staff.test.ts

return;
}

const normalizedRoute = route.replace(/^staff\/me(?=\/|$)/, `staff/${currentUser.slug}`);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What if there's a staff member with the slug "me"?

Comment thread e2e/tests/admin/settings/staff.test.ts Outdated

test.describe('Ghost Admin - Staff settings', () => {
test('redirects staff/me to the current user profile', async ({page}) => {
await page.goto('/ghost/#/settings/staff/me');
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.

We should create a page object in /helpers/pages/admin/settings/.

Comment thread e2e/tests/admin/settings/staff.test.ts Outdated
test('redirects staff/me to the current user profile', async ({page}) => {
await page.goto('/ghost/#/settings/staff/me');

const userDetailModal = page.getByTestId('user-detail-modal');
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.

Locators should be part of the page object.

Comment thread e2e/tests/admin/settings/staff.test.ts Outdated
const userDetailModal = page.getByTestId('user-detail-modal');
await expect(userDetailModal).toBeVisible();

const slugInput = userDetailModal.getByRole('textbox', {name: 'Slug'});
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.

We can simplify this then to something like:

const StaffDetailsPage = new AdminStaffDetailsPage(page);
await StaffDetailsPage.goto('/me');
const slug = getSlug(page);
await expect(slug.value).toEqual('me');

ref n/a

Adds a top-level my-profile route in the React admin shell and removes the temporary staff/me alias from admin-x-settings to avoid slug clashes.
@kevinansfield kevinansfield changed the title Redirect /ghost/#/staff/me to current staff profile Redirect /ghost/#/my-profile to current staff profile Feb 25, 2026
ref n/a

Adds a settings staff details page object and updates the my-profile redirect e2e test to use it per review feedback.
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 the current code and only fix it if needed.

Inline comments:
In `@apps/admin/src/my-profile-redirect.tsx`:
- Around line 5-9: The component MyProfileRedirect currently renders null when
useCurrentUser returns undefined even if the hook errored; update the call to
useCurrentUser to also destructure isError (e.g., const { data: currentUser,
isError } = useCurrentUser()) and change the render guard so you only return
null while loading (i.e., when !currentUser && !isError); if isError is true
render a graceful fallback (redirect to a safe route or show an error UI) so the
route does not stay blank.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a941cd9 and c277794.

📒 Files selected for processing (3)
  • apps/admin/src/my-profile-redirect.tsx
  • apps/admin/src/routes.tsx
  • e2e/tests/admin/settings/staff.test.ts

Comment thread apps/admin/src/my-profile-redirect.tsx Outdated
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.

🧹 Nitpick comments (2)
e2e/helpers/pages/admin/settings/staff-details-page.ts (1)

5-6: Add explicit public modifier to locators.

Both userDetailModal and slugInput lack the explicit public keyword. While TypeScript's default visibility is public, the coding guidelines require locators to be explicitly declared as public readonly when used in assertions.

♻️ Proposed fix
-    readonly userDetailModal: Locator;
-    readonly slugInput: Locator;
+    public readonly userDetailModal: Locator;
+    public readonly slugInput: Locator;

As per coding guidelines: "Page Objects should expose locators as public readonly when used with assertions."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/helpers/pages/admin/settings/staff-details-page.ts` around lines 5 - 6,
The properties userDetailModal and slugInput are missing the explicit public
modifier; update their declarations to be public readonly userDetailModal and
public readonly slugInput so they follow the Page Object guideline that locators
used in assertions must be exposed as public readonly (locate these symbols in
the admin settings Staff Details page class and adjust their declarations
accordingly).
e2e/tests/admin/settings/staff.test.ts (1)

5-14: Consider adding explicit AAA section comments for clarity.

The test is logically correct and follows the AAA structure, but the sections aren't visually separated. The coding guidelines require "clear sections" for the AAA pattern.

♻️ Proposed refactor
     test('redirects my-profile to the current user profile', async ({page}) => {
+        // Arrange
         const staffDetailsPage = new AdminStaffDetailsPage(page);
 
+        // Act
         await staffDetailsPage.gotoMyProfile();
 
+        // Assert
         await expect(staffDetailsPage.userDetailModal).toBeVisible();
         await expect(staffDetailsPage.slugInput).toBeVisible();
         await expect(staffDetailsPage.slugInput).toHaveValue(/^(?!me$).+/);
         await expect(page).toHaveURL(/\/ghost\/#\/settings\/staff\/(?!me$)[^/]+$/);
     });

As per coding guidelines: "Use the AAA Pattern (Arrange, Act, Assert) in E2E tests with clear sections."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@e2e/tests/admin/settings/staff.test.ts` around lines 5 - 14, Add explicit AAA
(Arrange, Act, Assert) section comments to the test 'redirects my-profile to the
current user profile' to follow coding guidelines: mark the setup with "//
Arrange" before constructing AdminStaffDetailsPage and any preconditions, mark
the action with "// Act" immediately before calling
staffDetailsPage.gotoMyProfile(), and mark assertions with "// Assert" before
the expect(...) checks (references: test name, AdminStaffDetailsPage,
gotoMyProfile, staffDetailsPage.userDetailModal, staffDetailsPage.slugInput,
page URL assertion). Ensure comments are placed so each logical block is
visually separated and in the same test function.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@e2e/helpers/pages/admin/settings/staff-details-page.ts`:
- Around line 5-6: The properties userDetailModal and slugInput are missing the
explicit public modifier; update their declarations to be public readonly
userDetailModal and public readonly slugInput so they follow the Page Object
guideline that locators used in assertions must be exposed as public readonly
(locate these symbols in the admin settings Staff Details page class and adjust
their declarations accordingly).

In `@e2e/tests/admin/settings/staff.test.ts`:
- Around line 5-14: Add explicit AAA (Arrange, Act, Assert) section comments to
the test 'redirects my-profile to the current user profile' to follow coding
guidelines: mark the setup with "// Arrange" before constructing
AdminStaffDetailsPage and any preconditions, mark the action with "// Act"
immediately before calling staffDetailsPage.gotoMyProfile(), and mark assertions
with "// Assert" before the expect(...) checks (references: test name,
AdminStaffDetailsPage, gotoMyProfile, staffDetailsPage.userDetailModal,
staffDetailsPage.slugInput, page URL assertion). Ensure comments are placed so
each logical block is visually separated and in the same test function.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c277794 and 1c1bc79.

📒 Files selected for processing (3)
  • e2e/helpers/pages/admin/settings/index.ts
  • e2e/helpers/pages/admin/settings/staff-details-page.ts
  • e2e/tests/admin/settings/staff.test.ts

ref n/a

Redirects to a safe route when the current-user query errors or resolves without a user instead of rendering an empty state indefinitely.
@kevinansfield
Copy link
Copy Markdown
Member Author

kevinansfield commented Feb 26, 2026

@9larsons I addressed your comments and we reviewed in mob session and gave a 👍 so I've set to auto-merge pending your approval

@kevinansfield kevinansfield enabled auto-merge (squash) February 26, 2026 10:21
Comment thread e2e/tests/admin/settings/staff.test.ts Outdated
await expect(staffDetailsPage.emailInput).toHaveValue(ghostAccountOwner.email);
await expect(staffDetailsPage.slugInput).toBeVisible();

const currentUserSlug = await staffDetailsPage.slugInput.inputValue();
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

ghostAccountOwner does not expose a slug so we go via the form details

@kevinansfield kevinansfield enabled auto-merge (squash) February 26, 2026 17:47
Copy link
Copy Markdown
Contributor

@9larsons 9larsons left a comment

Choose a reason for hiding this comment

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

Thanks!

@kevinansfield kevinansfield merged commit 83a13a8 into TryGhost:main Feb 26, 2026
30 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.

3 participants