Skip to content

Hosting: Pro blog claim passes through the customize step - #1456

Merged
feruzm merged 6 commits into
developfrom
feature/hosting-pro-claim-customize
Aug 12, 2026
Merged

Hosting: Pro blog claim passes through the customize step#1456
feruzm merged 6 commits into
developfrom
feature/hosting-pro-claim-customize

Conversation

@feruzm

@feruzm feruzm commented Aug 12, 2026

Copy link
Copy Markdown
Member

Closes #1422

What

The Pro free-blog claim now carries the same customize step as the paid signup, so a claimed blog starts out looking like its owner instead of the default template.

How

  • Claim dialog (pro-blog-claim.tsx): template cards, accent quick picks + hex field and the font preset selector, reusing the signup's TemplatePicker and AccentPicker as they are. Title and description prefill once from the member's profile and stay editable. A catalog load failure never blocks the claim; the payload simply degrades to the pre-customize shape.
  • Web proxy (/api/hosting/claim-blog): forwards styleTemplate, accent and fontPreset; the hosting service stays authoritative for validation.
  • Hosting API (/v1/internal/claim-blog): validates the new fields against the same rosters as the public create path (template roster, accent hex pattern, font preset keys) and fails closed with 400 on junk, since silently dropping a chosen template would report a successful claim that looks nothing like what the claimant picked. Valid values flow into the existing buildConfig path.
  • FONT_PRESETS moves from a local constant in hosting-signup.tsx to hosting-api.ts, so both customize surfaces read one list.

Tests

  • 2 new web specs: the claim payload carries the chosen customization plus prefilled identity, and the no-customization fallback stays byte-compatible with the old payload
  • 2 new hosting API tests: overrides reach buildConfig, invalid values reject with 400 before any DB work
  • Full suites green: 2627 web, 421 hosting API; both typechecks

Summary by CodeRabbit

  • New Features

    • Added blog customization options during the Pro blog claim process.
    • Users can select a template, accent color, and font preset.
    • Blog title and description fields are prefilled from the user’s profile and remain editable.
    • Selected customization settings are applied when claiming a blog.
  • Bug Fixes

    • Invalid customization values are rejected with a clear request error.
    • Blog claiming remains available when customization templates cannot be loaded.

The Pro free-blog claim accepted only title and description overrides, so
every claimed instance started on the default look. The claim dialog now
carries the same customize step as the paid signup: template cards, accent,
font preset and an identity prefilled from the member's profile. The web
proxy forwards the new fields and the hosting endpoint validates them
against the same rosters the public create path enforces, failing closed
on junk rather than silently dropping a chosen look. FONT_PRESETS moves
into hosting-api.ts so both surfaces read one list.
@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 12, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (6) 📘 Rule violations (14) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. any in FormControl onChange 📘 Rule violation ⚙ Maintainability
Description
ProBlogClaim introduces explicit any types in onChange handlers, weakening type safety and
potentially masking runtime errors. This violates the requirement to avoid any in new TypeScript
code.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R191-192]

+        onChange={(e: any) => setTitle(e.target.value)}
+        placeholder={i18next.t("hosting.blog-title-placeholder")}
Relevance

●●● Strong

Repo has accepted removing newly introduced any in TS event handlers/mocks; likely to require
proper event typing.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in modified TypeScript. The new FormControl
handlers explicitly type the event parameter as any.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/pro/pro-blog-claim.tsx[187-200]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` uses explicit `any` for `FormControl` change events, violating the no-`any` TypeScript rule.
## Issue Context
The component has two `onChange={(e: any) => ...}` handlers for title and description inputs.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[191-199]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. any used in claim spec 📘 Rule violation ⚙ Maintainability
Description
The new pro-blog-claim.spec.tsx introduces multiple any casts (importActual, as any),
reducing test type safety and hiding incorrect mocks. This violates the requirement to avoid any
in new TypeScript code.
Code

apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[R21-22]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
+  return { ...actual, hostingApi: { ...actual.hostingApi, templates: mocks.templates } };
Relevance

●●● Strong

Recent accepted reviews push tightening test typings and removing any casts, even in specs.

PR-#1394
PR-#919

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids adding any usage in changed TypeScript. The new spec uses
vi.importActual and multiple as any casts when mocking modules and fetch.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Pro blog claim spec introduces explicit `any` via `vi.importActual<any>(...)` and several `as any` casts.
## Issue Context
These casts are unnecessary in most cases and can be replaced with proper typings (e.g., `typeof import(...)`, `unknown`, or a typed Response stub).
## Fix Focus Areas
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Stale accent submitted 🐞 Bug ≡ Correctness
Description
In ProBlogClaim, typing a non-empty invalid hex accent updates the input but leaves the last valid
accent state intact, so clicking Claim can submit a different accent than what the user currently
sees in the field.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R162-165]

+          const trimmed = raw.trim();
+          if (!trimmed) setAccent(null);
+          else if (ACCENT_HEX_PATTERN.test(trimmed)) setAccent(trimmed);
+        }}
Relevance

●●● Strong

User-visible stale-state submission mismatch is a correctness issue; similar stale UI/state
mismatches were fixed before.

PR-#823

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim request body is built from the accent state, but the onInput handler only updates
accent when the input is empty or matches the hex pattern; for non-empty invalid input, accent
remains whatever it was previously, creating a visible/submitted mismatch.

apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
apps/web/src/features/pro/pro-blog-claim.tsx[156-165]
apps/web/src/features/hosting-signup/accent-picker.tsx[23-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` maintains both `accentInput` (raw text) and `accent` (last valid hex). When the user edits the accent field into an invalid, non-empty value, `accent` is not cleared/invalidated. The claim payload uses `accent`, so the request can silently submit a previous valid accent while the UI shows an invalid value.
## Issue Context
`AccentPicker` explicitly supports a mid-edit invalid text state, so the parent component must ensure the submitted value is consistent with what is displayed.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
- apps/web/src/features/pro/pro-blog-claim.tsx[156-170]
## Suggested fix
Pick one of these (either is acceptable):
1) **Prevent submission when the accent input is invalid**: before `fetch()`, compute `const trimmed = accentInput.trim()` and if `trimmed.length > 0 && !ACCENT_HEX_PATTERN.test(trimmed)` then set an error and return (and optionally disable the Claim button while invalid).
2) **Invalidate the committed accent on invalid input**: in `onInput`, add an `else setAccent(null)` branch so any non-empty invalid string clears the submitted accent (and consider also surfacing the existing invalid message to prevent surprises).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View medium (15)
4. any used in claim spec 📘 Rule violation ⚙ Maintainability
Description
The new pro-blog-claim.spec.tsx introduces multiple any casts (importActual, as any),
reducing test type safety and hiding incorrect mocks. This violates the requirement to avoid any
in new TypeScript code.
Code

apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[R21-22]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
+  return { ...actual, hostingApi: { ...actual.hostingApi, templates: mocks.templates } };
Relevance

●●● Strong

Recent accepted reviews push tightening test typings and removing any casts, even in specs.

PR-#1394
PR-#919

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids adding any usage in changed TypeScript. The new spec uses
vi.importActual and multiple as any casts when mocking modules and fetch.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Pro blog claim spec introduces explicit `any` via `vi.importActual<any>(...)` and several `as any` casts.
## Issue Context
These casts are unnecessary in most cases and can be replaced with proper typings (e.g., `typeof import(...)`, `unknown`, or a typed Response stub).
## Fix Focus Areas
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. Stale accent submitted 🐞 Bug ≡ Correctness
Description
In ProBlogClaim, typing a non-empty invalid hex accent updates the input but leaves the last valid
accent state intact, so clicking Claim can submit a different accent than what the user currently
sees in the field.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R162-165]

+          const trimmed = raw.trim();
+          if (!trimmed) setAccent(null);
+          else if (ACCENT_HEX_PATTERN.test(trimmed)) setAccent(trimmed);
+        }}
Relevance

●●● Strong

User-visible stale-state submission mismatch is a correctness issue; similar stale UI/state
mismatches were fixed before.

PR-#823

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim request body is built from the accent state, but the onInput handler only updates
accent when the input is empty or matches the hex pattern; for non-empty invalid input, accent
remains whatever it was previously, creating a visible/submitted mismatch.

apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
apps/web/src/features/pro/pro-blog-claim.tsx[156-165]
apps/web/src/features/hosting-signup/accent-picker.tsx[23-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` maintains both `accentInput` (raw text) and `accent` (last valid hex). When the user edits the accent field into an invalid, non-empty value, `accent` is not cleared/invalidated. The claim payload uses `accent`, so the request can silently submit a previous valid accent while the UI shows an invalid value.
## Issue Context
`AccentPicker` explicitly supports a mid-edit invalid text state, so the parent component must ensure the submitted value is consistent with what is displayed.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
- apps/web/src/features/pro/pro-blog-claim.tsx[156-170]
## Suggested fix
Pick one of these (either is acceptable):
1) **Prevent submission when the accent input is invalid**: before `fetch()`, compute `const trimmed = accentInput.trim()` and if `trimmed.length > 0 && !ACCENT_HEX_PATTERN.test(trimmed)` then set an error and return (and optionally disable the Claim button while invalid).
2) **Invalidate the committed accent on invalid input**: in `onInput`, add an `else setAccent(null)` branch so any non-empty invalid string clears the submitted accent (and consider also surfacing the existing invalid message to prevent surprises).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. any in FormControl onChange 📘 Rule violation ⚙ Maintainability
Description
ProBlogClaim introduces explicit any types in onChange handlers, weakening type safety and
potentially masking runtime errors. This violates the requirement to avoid any in new TypeScript
code.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R191-192]

+        onChange={(e: any) => setTitle(e.target.value)}
+        placeholder={i18next.t("hosting.blog-title-placeholder")}
Relevance

●●● Strong

Repo has accepted removing newly introduced any in TS event handlers/mocks; likely to require
proper event typing.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in modified TypeScript. The new FormControl
handlers explicitly type the event parameter as any.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/pro/pro-blog-claim.tsx[187-200]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` uses explicit `any` for `FormControl` change events, violating the no-`any` TypeScript rule.
## Issue Context
The component has two `onChange={(e: any) => ...}` handlers for title and description inputs.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[191-199]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. any used in claim spec 📘 Rule violation ⚙ Maintainability
Description
The new pro-blog-claim.spec.tsx introduces multiple any casts (importActual, as any),
reducing test type safety and hiding incorrect mocks. This violates the requirement to avoid any
in new TypeScript code.
Code

apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[R21-22]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
+  return { ...actual, hostingApi: { ...actual.hostingApi, templates: mocks.templates } };
Relevance

●●● Strong

Recent accepted reviews push tightening test typings and removing any casts, even in specs.

PR-#1394
PR-#919

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids adding any usage in changed TypeScript. The new spec uses
vi.importActual and multiple as any casts when mocking modules and fetch.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Pro blog claim spec introduces explicit `any` via `vi.importActual<any>(...)` and several `as any` casts.
## Issue Context
These casts are unnecessary in most cases and can be replaced with proper typings (e.g., `typeof import(...)`, `unknown`, or a typed Response stub).
## Fix Focus Areas
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


8. Stale accent submitted 🐞 Bug ≡ Correctness
Description
In ProBlogClaim, typing a non-empty invalid hex accent updates the input but leaves the last valid
accent state intact, so clicking Claim can submit a different accent than what the user currently
sees in the field.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R162-165]

+          const trimmed = raw.trim();
+          if (!trimmed) setAccent(null);
+          else if (ACCENT_HEX_PATTERN.test(trimmed)) setAccent(trimmed);
+        }}
Relevance

●●● Strong

User-visible stale-state submission mismatch is a correctness issue; similar stale UI/state
mismatches were fixed before.

PR-#823

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim request body is built from the accent state, but the onInput handler only updates
accent when the input is empty or matches the hex pattern; for non-empty invalid input, accent
remains whatever it was previously, creating a visible/submitted mismatch.

apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
apps/web/src/features/pro/pro-blog-claim.tsx[156-165]
apps/web/src/features/hosting-signup/accent-picker.tsx[23-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` maintains both `accentInput` (raw text) and `accent` (last valid hex). When the user edits the accent field into an invalid, non-empty value, `accent` is not cleared/invalidated. The claim payload uses `accent`, so the request can silently submit a previous valid accent while the UI shows an invalid value.
## Issue Context
`AccentPicker` explicitly supports a mid-edit invalid text state, so the parent component must ensure the submitted value is consistent with what is displayed.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
- apps/web/src/features/pro/pro-blog-claim.tsx[156-170]
## Suggested fix
Pick one of these (either is acceptable):
1) **Prevent submission when the accent input is invalid**: before `fetch()`, compute `const trimmed = accentInput.trim()` and if `trimmed.length > 0 && !ACCENT_HEX_PATTERN.test(trimmed)` then set an error and return (and optionally disable the Claim button while invalid).
2) **Invalidate the committed accent on invalid input**: in `onInput`, add an `else setAccent(null)` branch so any non-empty invalid string clears the submitted accent (and consider also surfacing the existing invalid message to prevent surprises).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


9. any in FormControl onChange 📘 Rule violation ⚙ Maintainability
Description
ProBlogClaim introduces explicit any types in onChange handlers, weakening type safety and
potentially masking runtime errors. This violates the requirement to avoid any in new TypeScript
code.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R191-192]

+        onChange={(e: any) => setTitle(e.target.value)}
+        placeholder={i18next.t("hosting.blog-title-placeholder")}
Relevance

●●● Strong

Repo has accepted removing newly introduced any in TS event handlers/mocks; likely to require
proper event typing.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in modified TypeScript. The new FormControl
handlers explicitly type the event parameter as any.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/pro/pro-blog-claim.tsx[187-200]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` uses explicit `any` for `FormControl` change events, violating the no-`any` TypeScript rule.
## Issue Context
The component has two `onChange={(e: any) => ...}` handlers for title and description inputs.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[191-199]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


10. any used in claim spec 📘 Rule violation ⚙ Maintainability
Description
The new pro-blog-claim.spec.tsx introduces multiple any casts (importActual, as any),
reducing test type safety and hiding incorrect mocks. This violates the requirement to avoid any
in new TypeScript code.
Code

apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[R21-22]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
+  return { ...actual, hostingApi: { ...actual.hostingApi, templates: mocks.templates } };
Relevance

●●● Strong

Recent accepted reviews push tightening test typings and removing any casts, even in specs.

PR-#1394
PR-#919

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids adding any usage in changed TypeScript. The new spec uses
vi.importActual and multiple as any casts when mocking modules and fetch.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Pro blog claim spec introduces explicit `any` via `vi.importActual<any>(...)` and several `as any` casts.
## Issue Context
These casts are unnecessary in most cases and can be replaced with proper typings (e.g., `typeof import(...)`, `unknown`, or a typed Response stub).
## Fix Focus Areas
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


11. Stale accent submitted 🐞 Bug ≡ Correctness
Description
In ProBlogClaim, typing a non-empty invalid hex accent updates the input but leaves the last valid
accent state intact, so clicking Claim can submit a different accent than what the user currently
sees in the field.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R162-165]

+          const trimmed = raw.trim();
+          if (!trimmed) setAccent(null);
+          else if (ACCENT_HEX_PATTERN.test(trimmed)) setAccent(trimmed);
+        }}
Relevance

●●● Strong

User-visible stale-state submission mismatch is a correctness issue; similar stale UI/state
mismatches were fixed before.

PR-#823

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim request body is built from the accent state, but the onInput handler only updates
accent when the input is empty or matches the hex pattern; for non-empty invalid input, accent
remains whatever it was previously, creating a visible/submitted mismatch.

apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
apps/web/src/features/pro/pro-blog-claim.tsx[156-165]
apps/web/src/features/hosting-signup/accent-picker.tsx[23-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` maintains both `accentInput` (raw text) and `accent` (last valid hex). When the user edits the accent field into an invalid, non-empty value, `accent` is not cleared/invalidated. The claim payload uses `accent`, so the request can silently submit a previous valid accent while the UI shows an invalid value.
## Issue Context
`AccentPicker` explicitly supports a mid-edit invalid text state, so the parent component must ensure the submitted value is consistent with what is displayed.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
- apps/web/src/features/pro/pro-blog-claim.tsx[156-170]
## Suggested fix
Pick one of these (either is acceptable):
1) **Prevent submission when the accent input is invalid**: before `fetch()`, compute `const trimmed = accentInput.trim()` and if `trimmed.length > 0 && !ACCENT_HEX_PATTERN.test(trimmed)` then set an error and return (and optionally disable the Claim button while invalid).
2) **Invalidate the committed accent on invalid input**: in `onInput`, add an `else setAccent(null)` branch so any non-empty invalid string clears the submitted accent (and consider also surfacing the existing invalid message to prevent surprises).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


12. any in FormControl onChange 📘 Rule violation ⚙ Maintainability
Description
ProBlogClaim introduces explicit any types in onChange handlers, weakening type safety and
potentially masking runtime errors. This violates the requirement to avoid any in new TypeScript
code.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R191-192]

+        onChange={(e: any) => setTitle(e.target.value)}
+        placeholder={i18next.t("hosting.blog-title-placeholder")}
Relevance

●●● Strong

Repo has accepted removing newly introduced any in TS event handlers/mocks; likely to require
proper event typing.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in modified TypeScript. The new FormControl
handlers explicitly type the event parameter as any.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/pro/pro-blog-claim.tsx[187-200]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` uses explicit `any` for `FormControl` change events, violating the no-`any` TypeScript rule.
## Issue Context
The component has two `onChange={(e: any) => ...}` handlers for title and description inputs.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[191-199]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


13. any used in claim spec 📘 Rule violation ⚙ Maintainability
Description
The new pro-blog-claim.spec.tsx introduces multiple any casts (importActual, as any),
reducing test type safety and hiding incorrect mocks. This violates the requirement to avoid any
in new TypeScript code.
Code

apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[R21-22]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
+  return { ...actual, hostingApi: { ...actual.hostingApi, templates: mocks.templates } };
Relevance

●●● Strong

Recent accepted reviews push tightening test typings and removing any casts, even in specs.

PR-#1394
PR-#919

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids adding any usage in changed TypeScript. The new spec uses
vi.importActual and multiple as any casts when mocking modules and fetch.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Pro blog claim spec introduces explicit `any` via `vi.importActual<any>(...)` and several `as any` casts.
## Issue Context
These casts are unnecessary in most cases and can be replaced with proper typings (e.g., `typeof import(...)`, `unknown`, or a typed Response stub).
## Fix Focus Areas
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


14. Stale accent submitted 🐞 Bug ≡ Correctness
Description
In ProBlogClaim, typing a non-empty invalid hex accent updates the input but leaves the last valid
accent state intact, so clicking Claim can submit a different accent than what the user currently
sees in the field.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R162-165]

+          const trimmed = raw.trim();
+          if (!trimmed) setAccent(null);
+          else if (ACCENT_HEX_PATTERN.test(trimmed)) setAccent(trimmed);
+        }}
Relevance

●●● Strong

User-visible stale-state submission mismatch is a correctness issue; similar stale UI/state
mismatches were fixed before.

PR-#823

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim request body is built from the accent state, but the onInput handler only updates
accent when the input is empty or matches the hex pattern; for non-empty invalid input, accent
remains whatever it was previously, creating a visible/submitted mismatch.

apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
apps/web/src/features/pro/pro-blog-claim.tsx[156-165]
apps/web/src/features/hosting-signup/accent-picker.tsx[23-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` maintains both `accentInput` (raw text) and `accent` (last valid hex). When the user edits the accent field into an invalid, non-empty value, `accent` is not cleared/invalidated. The claim payload uses `accent`, so the request can silently submit a previous valid accent while the UI shows an invalid value.
## Issue Context
`AccentPicker` explicitly supports a mid-edit invalid text state, so the parent component must ensure the submitted value is consistent with what is displayed.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
- apps/web/src/features/pro/pro-blog-claim.tsx[156-170]
## Suggested fix
Pick one of these (either is acceptable):
1) **Prevent submission when the accent input is invalid**: before `fetch()`, compute `const trimmed = accentInput.trim()` and if `trimmed.length > 0 && !ACCENT_HEX_PATTERN.test(trimmed)` then set an error and return (and optionally disable the Claim button while invalid).
2) **Invalidate the committed accent on invalid input**: in `onInput`, add an `else setAccent(null)` branch so any non-empty invalid string clears the submitted accent (and consider also surfacing the existing invalid message to prevent surprises).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


15. any in FormControl onChange 📘 Rule violation ⚙ Maintainability
Description
ProBlogClaim introduces explicit any types in onChange handlers, weakening type safety and
potentially masking runtime errors. This violates the requirement to avoid any in new TypeScript
code.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R191-192]

+        onChange={(e: any) => setTitle(e.target.value)}
+        placeholder={i18next.t("hosting.blog-title-placeholder")}
Relevance

●●● Strong

Repo has accepted removing newly introduced any in TS event handlers/mocks; likely to require
proper event typing.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in modified TypeScript. The new FormControl
handlers explicitly type the event parameter as any.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/pro/pro-blog-claim.tsx[187-200]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` uses explicit `any` for `FormControl` change events, violating the no-`any` TypeScript rule.
## Issue Context
The component has two `onChange={(e: any) => ...}` handlers for title and description inputs.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[191-199]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


16. any used in claim spec 📘 Rule violation ⚙ Maintainability
Description
The new pro-blog-claim.spec.tsx introduces multiple any casts (importActual, as any),
reducing test type safety and hiding incorrect mocks. This violates the requirement to avoid any
in new TypeScript code.
Code

apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[R21-22]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
+  return { ...actual, hostingApi: { ...actual.hostingApi, templates: mocks.templates } };
Relevance

●●● Strong

Recent accepted reviews push tightening test typings and removing any casts, even in specs.

PR-#1394
PR-#919

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids adding any usage in changed TypeScript. The new spec uses
vi.importActual and multiple as any casts when mocking modules and fetch.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Pro blog claim spec introduces explicit `any` via `vi.importActual<any>(...)` and several `as any` casts.
## Issue Context
These casts are unnecessary in most cases and can be replaced with proper typings (e.g., `typeof import(...)`, `unknown`, or a typed Response stub).
## Fix Focus Areas
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


17. Stale accent submitted 🐞 Bug ≡ Correctness
Description
In ProBlogClaim, typing a non-empty invalid hex accent updates the input but leaves the last valid
accent state intact, so clicking Claim can submit a different accent than what the user currently
sees in the field.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R162-165]

+          const trimmed = raw.trim();
+          if (!trimmed) setAccent(null);
+          else if (ACCENT_HEX_PATTERN.test(trimmed)) setAccent(trimmed);
+        }}
Relevance

●●● Strong

User-visible stale-state submission mismatch is a correctness issue; similar stale UI/state
mismatches were fixed before.

PR-#823

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim request body is built from the accent state, but the onInput handler only updates
accent when the input is empty or matches the hex pattern; for non-empty invalid input, accent
remains whatever it was previously, creating a visible/submitted mismatch.

apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
apps/web/src/features/pro/pro-blog-claim.tsx[156-165]
apps/web/src/features/hosting-signup/accent-picker.tsx[23-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` maintains both `accentInput` (raw text) and `accent` (last valid hex). When the user edits the accent field into an invalid, non-empty value, `accent` is not cleared/invalidated. The claim payload uses `accent`, so the request can silently submit a previous valid accent while the UI shows an invalid value.
## Issue Context
`AccentPicker` explicitly supports a mid-edit invalid text state, so the parent component must ensure the submitted value is consistent with what is displayed.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
- apps/web/src/features/pro/pro-blog-claim.tsx[156-170]
## Suggested fix
Pick one of these (either is acceptable):
1) **Prevent submission when the accent input is invalid**: before `fetch()`, compute `const trimmed = accentInput.trim()` and if `trimmed.length > 0 && !ACCENT_HEX_PATTERN.test(trimmed)` then set an error and return (and optionally disable the Claim button while invalid).
2) **Invalidate the committed accent on invalid input**: in `onInput`, add an `else setAccent(null)` branch so any non-empty invalid string clears the submitted accent (and consider also surfacing the existing invalid message to prevent surprises).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


18. any in FormControl onChange 📘 Rule violation ⚙ Maintainability
Description
ProBlogClaim introduces explicit any types in onChange handlers, weakening type safety and
potentially masking runtime errors. This violates the requirement to avoid any in new TypeScript
code.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R191-192]

+        onChange={(e: any) => setTitle(e.target.value)}
+        placeholder={i18next.t("hosting.blog-title-placeholder")}
Relevance

●●● Strong

Repo has accepted removing newly introduced any in TS event handlers/mocks; likely to require
proper event typing.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in modified TypeScript. The new FormControl
handlers explicitly type the event parameter as any.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/pro/pro-blog-claim.tsx[187-200]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` uses explicit `any` for `FormControl` change events, violating the no-`any` TypeScript rule.
## Issue Context
The component has two `onChange={(e: any) => ...}` handlers for title and description inputs.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[191-199]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

19. Empty template catalog blank ✓ Resolved 🐞 Bug ☼ Reliability
Description
If the templates API returns an empty array, ProBlogClaim treats it as a successful load and
TemplatePicker renders an empty radiogroup without any fallback message, leaving the template
section blank.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R58-62]

+    hostingApi
+      .templates()
+      .then((r) => {
+        if (!cancelled) setTemplates(r.templates);
+      })
Relevance

●●● Strong

Team previously accepted adding empty-state/failed handling when templates API returns [] to avoid
blank pickers.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim UI sets templates directly from the response without checking for an empty roster.
TemplatePicker only distinguishes failed, null/unset, and otherwise maps the array; with [],
it renders no options and no message.

apps/web/src/features/pro/pro-blog-claim.tsx[56-65]
apps/web/src/features/hosting-signup/template-picker.tsx[26-42]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` marks the template catalog as loaded whenever the request resolves, even if `templates` is an empty array. `TemplatePicker` only has explicit branches for `failed` and `!templates`; an empty array is truthy and results in a rendered radiogroup with zero options and no explanatory text.
## Issue Context
The PR intent is “catalog load failure never blocks the claim”; an empty roster is effectively a failure from the UI’s perspective and should degrade to the same fallback messaging/default behavior.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[56-65]
- apps/web/src/features/hosting-signup/template-picker.tsx[26-42]
## Suggested fix
Either:
- In `ProBlogClaim`’s `.then`, treat empty arrays as failure:
- if `!r || !Array.isArray(r.templates) || r.templates.length === 0` -> `setTemplatesFailed(true)` (and optionally keep `templates` as `null`)
- Or add an explicit empty-state branch inside `TemplatePicker` for `templates.length === 0` (show a message similar to `hosting.template-load-failed`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


20. Empty template catalog blank ✓ Resolved 🐞 Bug ☼ Reliability
Description
If the templates API returns an empty array, ProBlogClaim treats it as a successful load and
TemplatePicker renders an empty radiogroup without any fallback message, leaving the template
section blank.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R58-62]

+    hostingApi
+      .templates()
+      .then((r) => {
+        if (!cancelled) setTemplates(r.templates);
+      })
Relevance

●●● Strong

Team previously accepted adding empty-state/failed handling when templates API returns [] to avoid
blank pickers.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim UI sets templates directly from the response without checking for an empty roster.
TemplatePicker only distinguishes failed, null/unset, and otherwise maps the array; with [],
it renders no options and no message.

apps/web/src/features/pro/pro-blog-claim.tsx[56-65]
apps/web/src/features/hosting-signup/template-picker.tsx[26-42]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` marks the template catalog as loaded whenever the request resolves, even if `templates` is an empty array. `TemplatePicker` only has explicit branches for `failed` and `!templates`; an empty array is truthy and results in a rendered radiogroup with zero options and no explanatory text.
## Issue Context
The PR intent is “catalog load failure never blocks the claim”; an empty roster is effectively a failure from the UI’s perspective and should degrade to the same fallback messaging/default behavior.
## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[56-65]
- apps/web/src/features/hosting-signup/template-picker.tsx[26-42]
## Suggested fix
Either:
- In `ProBlogClaim`’s `.then`, treat empty arrays as failure:
- if `!r || !Array.isArray(r.templates) || r.templates.length === 0` -> `setTemplatesFailed(true)` (and optionally keep `templates` as `null`)
- Or add an explicit empty-state branch inside `TemplatePicker` for `templates.length === 0` (show a message similar to `hosting.template-load-failed`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


21. Empty template catalog blank ✓ Resolved 🐞 Bug ☼ Reliability
Description
If the templates API returns an empty array, ProBlogClaim treats it as a successful load and
TemplatePicker renders an empty radiogroup without any fallback message, leaving the template
section blank.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R58-62]

+    hostingApi
+      .templates()
+      .then((r) => {
+        if (!cancelled) setTemplates(r.templates);
+      })
Relevance

●●● Strong

Team previously accepted adding empty-state/failed handling when templates API returns [] to avoid
blank pickers.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim UI sets templates directly from the response without checking for an empty roster.
TemplatePicker only distinguishes failed, null/unset, and otherwise maps the array; with [],
it renders no options and no message.

apps/web/src/features/pro/pro-blog-claim.tsx[56-65]
apps/web/src/features/hosting-signup/template-picker.tsx[26-42]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` marks the template catalog as loaded whenever the request resolves, even if `templates` is an empty array. `TemplatePicker` only has explicit branches for `failed` and `!templates`; an empty array is truthy and results in a rendered radiogroup with zero options and no explanatory text.
##...

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Aug 12, 2026

Copy link
Copy Markdown

PR Summary by Qodo

Hosting: Pro blog claim now supports the customize step

✨ Enhancement 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Add template/accent/font customization to the Pro blog claim dialog
• Forward customization fields through the web proxy into the hosting internal claim endpoint
• Validate customization against hosting rosters and cover pass-through/fallback with tests
Diagram

graph TD
UI["ProBlogClaim UI"] --> Proxy["/api/hosting/claim-blog"] --> Internal["/v1/internal/claim-blog"] --> Build["TenantService.buildConfig"] --> Tenant["Claimed tenant config"]
UI --> Catalog["Template catalog"]
Internal --> Rosters["Template/accent/font rosters"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Serve rosters from hosting and render options dynamically
  • ➕ Eliminates drift risk between web UI and hosting validation (fonts/templates)
  • ➕ Allows adding/removing options without web deploy
  • ➖ Adds another network dependency for rendering the customize step
  • ➖ Requires designing/versioning a roster endpoint and caching strategy
2. Shared schema package for claim/create payload validation
  • ➕ Single source of truth for allowed fields, types, and constraints
  • ➕ Can generate both server validation and client typing
  • ➖ Introduces cross-app coupling and release coordination
  • ➖ May be heavier than needed for a small roster set
3. Accept-but-drop invalid customization (fail-open)
  • ➕ More permissive; avoids user-visible 400s for stale clients
  • ➖ Violates user expectations (preview vs result mismatch)
  • ➖ Harder to debug; silent degradation hides client issues

Recommendation: Keep the PR’s fail-closed server validation: a successful claim must match the selected appearance. Consider a follow-up to source rosters from hosting (or a shared schema) to prevent long-term drift, but the current change is appropriately scoped and maintains hosting as the authority.

Files changed (7) +350 / -7

Enhancement (3) +168 / -6
internal.tsValidate and apply appearance overrides in /claim-blog +35/-1

Validate and apply appearance overrides in /claim-blog

• Extends the internal claim endpoint to accept styleTemplate, accent, and fontPreset. Validates each against the same rosters/patterns as public tenant creation and fails closed with 400 on invalid input, then forwards overrides into TenantService.buildConfig.

apps/self-hosted/hosting/api/src/routes/internal.ts

route.tsForward claim customization fields to hosting internal API +9/-1

Forward claim customization fields to hosting internal API

• Updates the Next.js proxy route to include styleTemplate, accent, and fontPreset in the upstream request. Leaves validation authoritative to the hosting service.

apps/web/src/app/api/hosting/claim-blog/route.ts

pro-blog-claim.tsxAdd customize step + profile prefill to Pro blog claim +124/-4

Add customize step + profile prefill to Pro blog claim

• Extends the claim dialog with template selection, accent picker (quick picks + hex input), and font preset selection, reusing existing signup pickers. Prefills title/description once from the member profile via react-query and submits optional appearance/identity overrides in the claim payload; template catalog load failures degrade to the pre-customize payload shape.

apps/web/src/features/pro/pro-blog-claim.tsx

Refactor (2) +8 / -1
hosting-api.tsCentralize FONT_PRESETS roster for customize surfaces +7/-0

Centralize FONT_PRESETS roster for customize surfaces

• Introduces a shared FONT_PRESETS constant in hosting-api.ts as a client-side mirror of the hosting API roster. This allows both signup and claim customize steps to use the same list and reduce drift.

apps/web/src/features/hosting-signup/hosting-api.ts

hosting-signup.tsxUse shared FONT_PRESETS instead of local constant +1/-1

Use shared FONT_PRESETS instead of local constant

• Removes the local FONT_PRESETS definition and imports it from hosting-api.ts. Keeps the signup UI behavior unchanged while sharing the roster with other flows.

apps/web/src/features/hosting-signup/hosting-signup.tsx

Tests (2) +174 / -0
internal.test.tsAdd claim customization pass-through and validation tests +54/-0

Add claim customization pass-through and validation tests

• Adds coverage ensuring styleTemplate/accent/fontPreset are passed into buildConfig on claim. Adds table-driven tests asserting invalid customization values return 400 and do not call buildConfig.

apps/self-hosted/hosting/api/src/routes/internal.test.ts

pro-blog-claim.spec.tsxAdd web specs for claim payload customization and fallback +120/-0

Add web specs for claim payload customization and fallback

• Adds tests asserting the claim payload includes prefilled identity plus selected template/accent/font. Adds a fallback test ensuring that when the template catalog fails and nothing is chosen, the request body remains byte-compatible with the prior behavior (code-only).

apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@feruzm, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 15 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c286e5f5-dfa8-40cc-bd13-afa29626f58f

📥 Commits

Reviewing files that changed from the base of the PR and between de0b7db and db60bd8.

📒 Files selected for processing (6)
  • apps/self-hosted/hosting/api/src/routes/internal.test.ts
  • apps/self-hosted/hosting/api/src/routes/internal.ts
  • apps/web/src/features/i18n/locales/en-US.json
  • apps/web/src/features/pro/pro-blog-claim.tsx
  • apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx
  • apps/web/src/specs/setup-any-spec.ts
📝 Walkthrough

Walkthrough

The Pro blog claim flow now supports template, accent, font, title, and description customization. The web and internal hosting routes forward and validate these fields. Tests cover successful customization, invalid values, profile prefilling, and catalog-load fallback.

Changes

Pro blog claim customization

Layer / File(s) Summary
Customization form and shared font presets
apps/web/src/features/pro/pro-blog-claim.tsx, apps/web/src/features/hosting-signup/hosting-api.ts, apps/web/src/features/hosting-signup/hosting-signup.tsx, apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx
The claim form loads templates, prefills title and description from the profile, collects template, accent, font, title, and description values, and submits them. Font presets are shared with the hosting signup flow. Tests cover successful submission and catalog-load fallback.
Claim request forwarding
apps/web/src/app/api/hosting/claim-blog/route.ts
The web route forwards optional template, accent, and font values with the existing title and description fields.
Claim validation and tenant configuration
apps/self-hosted/hosting/api/src/routes/internal.ts, apps/self-hosted/hosting/api/src/routes/internal.test.ts
The internal route validates customization values, returns 400 invalid_request for unsupported values, and passes valid settings to TenantService.buildConfig. Tests cover both paths.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ProBlogClaim
  participant ClaimRoute
  participant InternalClaimRoute
  participant TenantService
  ProBlogClaim->>ClaimRoute: Submit claim and customization fields
  ClaimRoute->>InternalClaimRoute: Forward request
  InternalClaimRoute->>TenantService: Build configuration with validated settings
  TenantService-->>InternalClaimRoute: Return configuration
  InternalClaimRoute-->>ClaimRoute: Return claim result
  ClaimRoute-->>ProBlogClaim: Display success or error
Loading

Possibly related PRs

Poem

A rabbit picked a font with care,
A template brightened every lair.
The accent passed, the title grew,
The claim route checked each value too.
“Hop forth,” said Bun, “your blog is new!”

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the Pro blog claim customization change.
Linked Issues check ✅ Passed The PR adds template, accent, and profile-prefilled identity customization to the Pro claim flow as required by issue #1422.
Out of Scope Changes check ✅ Passed All changes support customization propagation, validation, shared presets, or coverage for the Pro blog claim flow.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/hosting-pro-claim-customize

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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 3

🧹 Nitpick comments (2)
apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx (1)

54-55: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use QueryKeys for the mocked query key.

Replace the literal ["account", "alice"] with QueryKeys.accounts.full("alice"). This keeps the test aligned with the SDK cache-key contract.

🤖 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/web/src/specs/features/pro/pro-blog-claim.spec.tsx` around lines 54 -
55, Update the mocked query key in the getAccountFullQueryOptions mock to use
QueryKeys.accounts.full("alice") instead of the literal array, preserving
alignment with the SDK cache-key contract.

Source: Coding guidelines

apps/web/src/features/pro/pro-blog-claim.tsx (1)

187-200: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replace any with a typed input event.

The new handlers bypass strict TypeScript checks. Type the event as React.ChangeEvent<HTMLInputElement> or use a minimal { target: { value: string } } type.

🤖 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/web/src/features/pro/pro-blog-claim.tsx` around lines 187 - 200, Replace
the any event annotations in the title and description FormControl onChange
handlers with a typed input event, using React.ChangeEvent<HTMLInputElement> or
an equivalent minimal value-bearing target type, while preserving the existing
setTitle and setDescription behavior.

Source: Coding guidelines

🤖 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/self-hosted/hosting/api/src/routes/internal.ts`:
- Around line 515-523: Update the post-commit publication call in the route to
use ConfigService.publishConfigFile(username) instead of publishing the stale
transaction-returned tenant; update the route test to assert username-based
publication.

In `@apps/web/src/features/pro/pro-blog-claim.tsx`:
- Around line 156-170: Update the claim form around AccentPicker and the claim
button to derive an accentPending state from the trimmed accent input, marking
it pending when non-empty and not matching ACCENT_HEX_PATTERN. Disable the claim
button while accentPending is true, while preserving the existing behavior for
valid or empty input and matching HostingSignup.

In `@apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx`:
- Around line 54-59: Update the mock returned by getAccountFullQueryOptions to
use QueryKeys.accounts.full("alice") for queryKey instead of the hardcoded
array, matching the production account query key used by both test setups.

---

Nitpick comments:
In `@apps/web/src/features/pro/pro-blog-claim.tsx`:
- Around line 187-200: Replace the any event annotations in the title and
description FormControl onChange handlers with a typed input event, using
React.ChangeEvent<HTMLInputElement> or an equivalent minimal value-bearing
target type, while preserving the existing setTitle and setDescription behavior.

In `@apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx`:
- Around line 54-55: Update the mocked query key in the
getAccountFullQueryOptions mock to use QueryKeys.accounts.full("alice") instead
of the literal array, preserving alignment with the SDK cache-key contract.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 24931baf-dd51-4e7e-b9fe-c34b043e1d83

📥 Commits

Reviewing files that changed from the base of the PR and between 5dde702 and de0b7db.

📒 Files selected for processing (7)
  • apps/self-hosted/hosting/api/src/routes/internal.test.ts
  • apps/self-hosted/hosting/api/src/routes/internal.ts
  • apps/web/src/app/api/hosting/claim-blog/route.ts
  • apps/web/src/features/hosting-signup/hosting-api.ts
  • apps/web/src/features/hosting-signup/hosting-signup.tsx
  • apps/web/src/features/pro/pro-blog-claim.tsx
  • apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx

Comment thread apps/self-hosted/hosting/api/src/routes/internal.ts
Comment thread apps/web/src/features/pro/pro-blog-claim.tsx
Comment thread apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx
@qodo-code-review

qodo-code-review Bot commented Aug 12, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (4) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. any used in claim spec 📘 Rule violation ⚙ Maintainability
Description
The new pro-blog-claim.spec.tsx introduces multiple any casts (importActual<any>, as any),
reducing test type safety and hiding incorrect mocks. This violates the requirement to avoid any
in new TypeScript code.
Code

apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[R21-22]

+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
+  return { ...actual, hostingApi: { ...actual.hostingApi, templates: mocks.templates } };
Relevance

●●● Strong

Recent accepted reviews push tightening test typings and removing any casts, even in specs.

PR-#1394
PR-#919

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 forbids adding any usage in changed TypeScript. The new spec uses
vi.importActual<any> and multiple as any casts when mocking modules and fetch.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new Pro blog claim spec introduces explicit `any` via `vi.importActual<any>(...)` and several `as any` casts.

## Issue Context
These casts are unnecessary in most cases and can be replaced with proper typings (e.g., `typeof import(...)`, `unknown`, or a typed Response stub).

## Fix Focus Areas
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Stale accent submitted 🐞 Bug ≡ Correctness
Description
In ProBlogClaim, typing a non-empty invalid hex accent updates the input but leaves the last valid
accent state intact, so clicking Claim can submit a different accent than what the user currently
sees in the field.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R162-165]

+          const trimmed = raw.trim();
+          if (!trimmed) setAccent(null);
+          else if (ACCENT_HEX_PATTERN.test(trimmed)) setAccent(trimmed);
+        }}
Relevance

●●● Strong

User-visible stale-state submission mismatch is a correctness issue; similar stale UI/state
mismatches were fixed before.

PR-#823

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim request body is built from the accent state, but the onInput handler only updates
accent when the input is empty or matches the hex pattern; for non-empty invalid input, accent
remains whatever it was previously, creating a visible/submitted mismatch.

apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
apps/web/src/features/pro/pro-blog-claim.tsx[156-165]
apps/web/src/features/hosting-signup/accent-picker.tsx[23-26]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` maintains both `accentInput` (raw text) and `accent` (last valid hex). When the user edits the accent field into an invalid, non-empty value, `accent` is not cleared/invalidated. The claim payload uses `accent`, so the request can silently submit a previous valid accent while the UI shows an invalid value.

## Issue Context
`AccentPicker` explicitly supports a mid-edit invalid text state, so the parent component must ensure the submitted value is consistent with what is displayed.

## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
- apps/web/src/features/pro/pro-blog-claim.tsx[156-170]

## Suggested fix
Pick one of these (either is acceptable):
1) **Prevent submission when the accent input is invalid**: before `fetch()`, compute `const trimmed = accentInput.trim()` and if `trimmed.length > 0 && !ACCENT_HEX_PATTERN.test(trimmed)` then set an error and return (and optionally disable the Claim button while invalid).
2) **Invalidate the committed accent on invalid input**: in `onInput`, add an `else setAccent(null)` branch so any non-empty invalid string clears the submitted accent (and consider also surfacing the existing invalid message to prevent surprises).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. any in FormControl onChange 📘 Rule violation ⚙ Maintainability
Description
ProBlogClaim introduces explicit any types in onChange handlers, weakening type safety and
potentially masking runtime errors. This violates the requirement to avoid any in new TypeScript
code.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R191-192]

+        onChange={(e: any) => setTitle(e.target.value)}
+        placeholder={i18next.t("hosting.blog-title-placeholder")}
Relevance

●●● Strong

Repo has accepted removing newly introduced any in TS event handlers/mocks; likely to require
proper event typing.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668119 disallows introducing any in modified TypeScript. The new FormControl
handlers explicitly type the event parameter as any.

Rule 2668119: Disallow implicit and any types in new TypeScript code
apps/web/src/features/pro/pro-blog-claim.tsx[187-200]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` uses explicit `any` for `FormControl` change events, violating the no-`any` TypeScript rule.

## Issue Context
The component has two `onChange={(e: any) => ...}` handlers for title and description inputs.

## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[191-199]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Informational

4. Empty template catalog blank ✓ Resolved 🐞 Bug ☼ Reliability
Description
If the templates API returns an empty array, ProBlogClaim treats it as a successful load and
TemplatePicker renders an empty radiogroup without any fallback message, leaving the template
section blank.
Code

apps/web/src/features/pro/pro-blog-claim.tsx[R58-62]

+    hostingApi
+      .templates()
+      .then((r) => {
+        if (!cancelled) setTemplates(r.templates);
+      })
Relevance

●●● Strong

Team previously accepted adding empty-state/failed handling when templates API returns [] to avoid
blank pickers.

PR-#1438

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The claim UI sets templates directly from the response without checking for an empty roster.
TemplatePicker only distinguishes failed, null/unset, and otherwise maps the array; with [],
it renders no options and no message.

apps/web/src/features/pro/pro-blog-claim.tsx[56-65]
apps/web/src/features/hosting-signup/template-picker.tsx[26-42]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`ProBlogClaim` marks the template catalog as loaded whenever the request resolves, even if `templates` is an empty array. `TemplatePicker` only has explicit branches for `failed` and `!templates`; an empty array is truthy and results in a rendered radiogroup with zero options and no explanatory text.

## Issue Context
The PR intent is “catalog load failure never blocks the claim”; an empty roster is effectively a failure from the UI’s perspective and should degrade to the same fallback messaging/default behavior.

## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[56-65]
- apps/web/src/features/hosting-signup/template-picker.tsx[26-42]

## Suggested fix
Either:
- In `ProBlogClaim`’s `.then`, treat empty arrays as failure:
 - if `!r || !Array.isArray(r.templates) || r.templates.length === 0` -> `setTemplatesFailed(true)` (and optionally keep `templates` as `null`)
- Or add an explicit empty-state branch inside `TemplatePicker` for `templates.length === 0` (show a message similar to `hosting.template-load-failed`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


5. fetch spy not restored 📘 Rule violation ▣ Testability
Description
The new spec spies on globalThis.fetch but does not restore it after each test, risking cross-test
interference. This violates the requirement to clean up global mocks/spies.
Code

apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[R50-65]

+  beforeEach(() => {
+    vi.clearAllMocks();
+    mocks.accessToken = "tok-alice";
+    mocks.templates.mockResolvedValue({ templates: TEMPLATES });
+    vi.mocked(getAccountFullQueryOptions as any).mockImplementation(() => ({
+      queryKey: ["account", "alice"],
+      queryFn: async () => ({
+        profile: { name: "Alice in Chains", about: "Notes from the chain" }
+      })
+    }));
+    fetchSpy = vi.spyOn(globalThis, "fetch" as any).mockResolvedValue({
+      ok: true,
+      status: 200,
+      json: async () => ({ tenant: { blogUrl: "https://alice.blogs.ecency.com" } })
+    } as any);
+  });
Relevance

● Weak

They previously rejected restoring global spies after tests (e.g., window.open), so likely won’t
require fetchSpy restore.

PR-#1448

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668097 requires cleanup of global mocks/spies. The spec creates a
vi.spyOn(globalThis, "fetch" ...) in beforeEach but includes no afterEach restoration, leaving
global state mutated across tests.

Rule 2668097: Tests must restore global state (DOM, timers, mocks) after each test
apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[47-65]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
A global `fetch` spy is created in `beforeEach` but never restored, which can leak mocked global state into other tests.

## Issue Context
This file currently calls `vi.clearAllMocks()` only; it should restore spies (e.g., `vi.restoreAllMocks()` or `fetchSpy.mockRestore()`) in an `afterEach`.

## Fix Focus Areas
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[47-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. Mocks internal modules in spec 📘 Rule violation ▣ Testability
Description
The new spec mocks internal application modules (@/utils, @/features/hosting-signup/hosting-api)
rather than mocking only external package dependencies. This can lead to brittle tests that don't
exercise real internal behavior.
Code

apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[R15-23]

+vi.mock("@/utils", () => ({
+  getAccessToken: () => mocks.accessToken,
+  random: vi.fn()
+}));
+
+vi.mock("@/features/hosting-signup/hosting-api", async () => {
+  const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
+  return { ...actual, hostingApi: { ...actual.hostingApi, templates: mocks.templates } };
+});
Relevance

● Weak

They previously rejected guidance to avoid mocking internal @/utils via vi.mock in specs; expect
same here.

PR-#865

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
PR Compliance ID 2668008 restricts Vitest mocking to external packages. The new spec directly mocks
internal aliased modules under @/ using vi.mock().

Rule 2668008: Mock only external package dependencies with vi.fn in unit tests
apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[15-23]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The new spec uses `vi.mock()` to replace internal modules (`@/utils`, `@/features/hosting-signup/hosting-api`). The compliance rule requires mocking only external package dependencies with Vitest mocks.

## Issue Context
If the goal is to control tokens or template catalog responses, prefer setting up the environment (e.g., storage state) and mocking network boundaries (e.g., `fetch`) instead of mocking internal modules.

## Fix Focus Areas
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[15-23]
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[50-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
✅ Compliance rules (platform): 75 rules
✅ Skills: 6 invoked
  add-feature
  add-query
  add-sdk-mutation
  add-test
  code-review
  debug
Review mode: ⚖️ Balanced: This behavior change spans the claim UI, web proxy, hosting API validation, and build configuration, with multiple independently testable paths and meaningful user-facing impact; it warrants a careful single-pass review, but not redundant extended passes.

Grey Divider

Tip of the day
💡 Did you know, you can enable the Remediation agent and Qodo fixes findings in a dedicated fix PR

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +191 to +192
onChange={(e: any) => setTitle(e.target.value)}
placeholder={i18next.t("hosting.blog-title-placeholder")}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

1. any in formcontrol onchange 📘 Rule violation ⚙ Maintainability

ProBlogClaim introduces explicit any types in onChange handlers, weakening type safety and
potentially masking runtime errors. This violates the requirement to avoid any in new TypeScript
code.
Agent Prompt
## Issue description
`ProBlogClaim` uses explicit `any` for `FormControl` change events, violating the no-`any` TypeScript rule.

## Issue Context
The component has two `onChange={(e: any) => ...}` handlers for title and description inputs.

## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[191-199]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +21 to +22
const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api");
return { ...actual, hostingApi: { ...actual.hostingApi, templates: mocks.templates } };

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

2. any used in claim spec 📘 Rule violation ⚙ Maintainability

The new pro-blog-claim.spec.tsx introduces multiple any casts (importActual<any>, as any),
reducing test type safety and hiding incorrect mocks. This violates the requirement to avoid any
in new TypeScript code.
Agent Prompt
## Issue description
The new Pro blog claim spec introduces explicit `any` via `vi.importActual<any>(...)` and several `as any` casts.

## Issue Context
These casts are unnecessary in most cases and can be replaced with proper typings (e.g., `typeof import(...)`, `unknown`, or a typed Response stub).

## Fix Focus Areas
- apps/web/src/specs/features/pro/pro-blog-claim.spec.tsx[20-65]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +162 to +165
const trimmed = raw.trim();
if (!trimmed) setAccent(null);
else if (ACCENT_HEX_PATTERN.test(trimmed)) setAccent(trimmed);
}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Remediation recommended

5. Stale accent submitted 🐞 Bug ≡ Correctness

In ProBlogClaim, typing a non-empty invalid hex accent updates the input but leaves the last valid
accent state intact, so clicking Claim can submit a different accent than what the user currently
sees in the field.
Agent Prompt
## Issue description
`ProBlogClaim` maintains both `accentInput` (raw text) and `accent` (last valid hex). When the user edits the accent field into an invalid, non-empty value, `accent` is not cleared/invalidated. The claim payload uses `accent`, so the request can silently submit a previous valid accent while the UI shows an invalid value.

## Issue Context
`AccentPicker` explicitly supports a mid-edit invalid text state, so the parent component must ensure the submitted value is consistent with what is displayed.

## Fix Focus Areas
- apps/web/src/features/pro/pro-blog-claim.tsx[95-105]
- apps/web/src/features/pro/pro-blog-claim.tsx[156-170]

## Suggested fix
Pick one of these (either is acceptable):
1) **Prevent submission when the accent input is invalid**: before `fetch()`, compute `const trimmed = accentInput.trim()` and if `trimmed.length > 0 && !ACCENT_HEX_PATTERN.test(trimmed)` then set an error and return (and optionally disable the Claim button while invalid).
2) **Invalidate the committed accent on invalid input**: in `onInput`, add an `else setAccent(null)` branch so any non-empty invalid string clears the submitted accent (and consider also surfacing the existing invalid message to prevent surprises).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment thread apps/web/src/features/pro/pro-blog-claim.tsx
feruzm added 5 commits August 12, 2026 16:04
… a valid accent

The claim's config publish goes through publishConfigFile(username), a
locked re-read, instead of the transaction-returned row whose snapshot
could overwrite a config another writer committed in between. The claim
button disables while the accent field holds a mid-edit invalid value,
matching the paid signup, so the payload can never differ from what the
field shows. The spec's account query mock uses the shared QueryKeys
builder instead of a hardcoded key.
The claim is one-shot on the hosting side (an existing live tenant is
returned unchanged), so a click before the template catalog and the
profile prefill settle would lock in a default-looking config the
claimant never saw coming. The button now waits for both to settle and
failures still settle, so a dead catalog or profile degrades to claiming
without them rather than blocking forever.
…bounded

The claim dialog probes for the member's blog on mount: an existing one
swaps the form for a pointer to the blog and Your hosted sites, since the
claim endpoint returns a live tenant unchanged and a form whose fields
would be silently discarded reports a success that never happened. The
endpoint now surfaces created in its response, so a claim raced from
another tab shows the same already-exists state instead of pretending the
customization applied. An abandoned reservation stays claimable and probe
errors fail open to the form. The catalog fetch is bounded: a request
that neither resolves nor rejects times out into the ordinary failure
state instead of disabling the claim forever.
The probe gates the claim button the same way the catalog does, so it
gets the same settle bound and fails open to claimable on a stall. The
race that lets through is safe by construction: a blog that does exist
comes back unchanged with created: false and the claim shows the
already-exists state instead of a success.
An empty successful catalog response rendered a blank picker; the failure
message with the claim still allowed is the honest state for it.
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.

Hosting: Pro blog claim passes through the customize step

1 participant