Hosting: manage panel becomes a remote settings surface - #1457
Conversation
The manage panel edits a hosted instance's title, description, theme and accent without a visit to the instance. Authorization is a hosting token obtained in place: every ecency.com login method holds a Hivesigner-compatible session token that /v1/auth/hivesigner exchanges, with a Keychain posting-key challenge as the fallback rail, cached per account for its lifetime. The editor prefills from the served config when the tenant is active, sends only the fields that actually changed and a blank field always keeps the current value. Works for a tenant that is still activating too: the PATCH persists and publishes on activation.
Code Review by Qodo
1.
|
📝 WalkthroughWalkthroughThe hosting manage panel now edits tenant title, description, theme, and accent settings. It retrieves stored configuration, obtains cached authenticated hosting tokens, submits changed values, and reports publication status. Tests cover authentication, prefilling, editing, persistence, loading races, and failures. ChangesRemote tenant settings
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Owner
participant TenantSettings
participant obtainHostingToken
participant hostingApi
Owner->>TenantSettings: Edit tenant settings
TenantSettings->>hostingApi: Retrieve stored configuration
hostingApi-->>TenantSettings: Return configuration
TenantSettings->>obtainHostingToken: Request owner token
obtainHostingToken-->>TenantSettings: Return hosting token
TenantSettings->>hostingApi: PATCH changed settings
hostingApi-->>TenantSettings: Return publication status
TenantSettings-->>Owner: Display save status
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. 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 |
PR Summary by QodoHosting: edit tenant settings from /hosting manage panel
AI Description
Diagram
High-Level Assessment
Files changed (7)
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 865ced502f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| initialRef.current = next; | ||
| setTitle(next.title); |
There was a problem hiding this comment.
Preserve edits made before prefill completes
For an active tenant on a slow config request, the form is editable immediately, so a user can begin typing before tenantConfig() resolves; these unconditional state updates then replace every in-progress edit with the fetched values. Disable editing until prefill finishes or apply each fetched value only while its field remains untouched.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Confirmed and fixed in 2101219: fetched values now seed only fields the owner has not started editing (functional setState, prev wins) and a prefill landing after a save began is dropped entirely, so neither race can discard edits or overwrite the post-save baseline. The change diff still compares against the fetched snapshot. A spec pins the typing-during-prefill case.
| "theme-light": "Light", | ||
| "theme-dark": "Dark", | ||
| "settings-save": "Save settings", | ||
| "settings-saved": "Saved. Changes reach your site within a minute.", |
There was a problem hiding this comment.
Report inactive saves as unpublished
When settings are saved for an inactive, expired, or suspended tenant, the PATCH only persists the configuration and does not publish it until the tenant becomes active, but this unconditional success message promises that the changes reach the site within a minute. Use the tenant status or the PATCH response's published field to show an activation-dependent message for these saves.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Confirmed and fixed in 2101219: saves for a tenant that is not active show a status-dependent message saying the changes publish when the site activates, instead of promising a live site. Spec asserts the pending message on the inactive path.
Code Review by Qodo
1.
|
Fetched values now seed only fields the owner has not started editing and a prefill landing after a save is dropped entirely, so neither race can discard edits or re-flag saved fields. Saves for a tenant that is not yet active say the changes publish on activation instead of promising a live site, and the new input handlers carry real event types.
… status The PATCH answers with an authoritative published flag; the manage list's subscription status can go stale between fetching the panel and saving, so the success copy now keys on the response, falling back to the status only for an older API that omits the flag.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/src/features/hosting-signup/hosting-token.ts`:
- Around line 59-65: Update the authentication helper around the signature and
session-token failure paths to throw stable, non-user-facing error codes instead
of the literal messages “Signature refused” and “No session token available”. In
TenantSettings, detect those codes and resolve the displayed messages through
i18next using entries added to en-US.json, while preserving existing
exchange-error handling.
In `@apps/web/src/features/hosting-signup/tenant-settings.tsx`:
- Around line 145-161: Associate the title and description labels with their
corresponding FormControl inputs by adding stable, unique id values and matching
htmlFor attributes. Update the relevant specs to locate both fields by role and
accessible name, using the label text rather than implementation-specific
selectors.
🪄 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: 2fc9a2a2-13cd-42a6-ba4c-9cff8a934c01
📒 Files selected for processing (7)
apps/web/src/features/hosting-signup/hosting-api.tsapps/web/src/features/hosting-signup/hosting-manage.tsxapps/web/src/features/hosting-signup/hosting-token.tsapps/web/src/features/hosting-signup/tenant-settings.tsxapps/web/src/features/i18n/locales/en-US.jsonapps/web/src/specs/features/hosting-signup/hosting-token.spec.tsapps/web/src/specs/features/hosting-signup/tenant-settings.spec.tsx
| if (!signed.success || !signed.result) { | ||
| throw new Error(signed.message || "Signature refused"); | ||
| } | ||
| return remember(await hostingApi.authVerify(username, signed.result, challenge)); | ||
| } | ||
|
|
||
| throw exchangeError ?? new Error("No session token available"); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Localize fallback authentication errors.
TenantSettings renders these error messages to the owner. "Signature refused" and "No session token available" bypass en-US.json and i18next.
Return stable error codes from this helper. Map those codes to localized messages in the UI.
As per coding guidelines, “All new user-facing strings must be added to en-US.json and accessed through i18next.”
🤖 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/hosting-signup/hosting-token.ts` around lines 59 - 65,
Update the authentication helper around the signature and session-token failure
paths to throw stable, non-user-facing error codes instead of the literal
messages “Signature refused” and “No session token available”. In
TenantSettings, detect those codes and resolve the displayed messages through
i18next using entries added to en-US.json, while preserving existing
exchange-error handling.
Source: Coding guidelines
| <label className="text-sm font-semibold">{i18next.t("hosting.blog-title-label")}</label> | ||
| <FormControl | ||
| type="text" | ||
| value={title} | ||
| maxLength={100} | ||
| onChange={(e: React.ChangeEvent<HTMLInputElement>) => setTitle(e.target.value)} | ||
| placeholder={i18next.t("hosting.settings-keep")} | ||
| /> | ||
|
|
||
| <label className="text-sm font-semibold">{i18next.t("hosting.blog-desc-label")}</label> | ||
| <FormControl | ||
| type="text" | ||
| value={description} | ||
| maxLength={500} | ||
| onChange={(e: React.ChangeEvent<HTMLInputElement>) => setDescription(e.target.value)} | ||
| placeholder={i18next.t("hosting.settings-keep")} | ||
| /> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Associate each text input with its label.
Line 145 and Line 154 render standalone <label> elements. The FormControl elements have no matching id. Screen readers cannot determine whether each input edits the title or description.
Add stable id values to both inputs and matching htmlFor values to both labels. Update the specs to select these fields by role and accessible name.
🤖 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/hosting-signup/tenant-settings.tsx` around lines 145 -
161, Associate the title and description labels with their corresponding
FormControl inputs by adding stable, unique id values and matching htmlFor
attributes. Update the relevant specs to locate both fields by role and
accessible name, using the label text rather than implementation-specific
selectors.
Closes #1423
What
Owners edit a hosted instance's title, description, theme and accent right from the manage panel on /hosting, no visit to the instance needed. Works while a tenant is still activating, since the PATCH persists for inactive tenants and publishes on activation.
How
hosting-token.ts): every ecency.com login method holds a Hivesigner-compatible session token, so/v1/auth/hivesignerexchanges it for a hosting token as the universal rail; a Keychain posting-key challenge (/v1/auth/challenge+/v1/auth/verify) is the fallback. Tokens cache per account for their lifetime, so one authorization serves many edits.tenant-settings.tsx): prefills fromGET /v1/tenants/:username/configwhen the tenant is active (the endpoint answers 402 before activation, where fields start blank). Only fields that actually changed are sent through the flat-key PATCH and a blank field always means keep the current value. Mid-edit invalid accents block saving, same derivation as the signup.PATCH /v1/tenants/:usernameand its owner check already exist, and CORS already admits ecency.com.Tests
Summary by CodeRabbit