Hosting: Pro blog claim passes through the customize step - #1456
Conversation
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.
Code Review by Qodo
1. any in FormControl onChange
|
PR Summary by QodoHosting: Pro blog claim now supports the customize step
AI Description
Diagram
High-Level Assessment
Files changed (7)
|
|
Warning Review limit reached
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 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 configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughThe 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. ChangesPro blog claim customization
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
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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 winUse
QueryKeysfor the mocked query key.Replace the literal
["account", "alice"]withQueryKeys.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 winReplace
anywith 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
📒 Files selected for processing (7)
apps/self-hosted/hosting/api/src/routes/internal.test.tsapps/self-hosted/hosting/api/src/routes/internal.tsapps/web/src/app/api/hosting/claim-blog/route.tsapps/web/src/features/hosting-signup/hosting-api.tsapps/web/src/features/hosting-signup/hosting-signup.tsxapps/web/src/features/pro/pro-blog-claim.tsxapps/web/src/specs/features/pro/pro-blog-claim.spec.tsx
Code Review by Qodo
1. any used in claim spec
|
| onChange={(e: any) => setTitle(e.target.value)} | ||
| placeholder={i18next.t("hosting.blog-title-placeholder")} |
There was a problem hiding this comment.
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
| const actual = await vi.importActual<any>("@/features/hosting-signup/hosting-api"); | ||
| return { ...actual, hostingApi: { ...actual.hostingApi, templates: mocks.templates } }; |
There was a problem hiding this comment.
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
| const trimmed = raw.trim(); | ||
| if (!trimmed) setAccent(null); | ||
| else if (ACCENT_HEX_PATTERN.test(trimmed)) setAccent(trimmed); | ||
| }} |
There was a problem hiding this comment.
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
… 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.
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
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./api/hosting/claim-blog): forwardsstyleTemplate,accentandfontPreset; the hosting service stays authoritative for validation./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_PRESETSmoves from a local constant in hosting-signup.tsx to hosting-api.ts, so both customize surfaces read one list.Tests
Summary by CodeRabbit
New Features
Bug Fixes