mirror of
https://github.com/stablyai/orca.git
synced 2026-10-25 00:03:59 +00:00
* Restructure mobile pairing setup into a clear stepped layout * Rework mobile pairing UI: radio-style path selector with sign-in gate fo * fix(mobile): resolve mobile-pairing review findings Applies the code-review findings for the reworked pairing UI: - Clear a displayed Relay QR on sign-out in both MobilePage and MobilePane (the rework dropped the wasSignedInRef watcher, leaving a stale Relay QR next to a "sign in required" prompt). Anywhere stays selected; the QR re-mints as local-only. [#1, #3] - Extract useMobilePairingConnectionMode so both panes resolve the saved preference identically instead of duplicating the state + resync effect. [#6] - Delete ~24 i18n keys the rework left unreferenced; sync locale catalogs to parity. [#4] - Give the connection-path radiogroup roving tabindex + arrow-key nav and document why it diverges from SettingsSegmentedControl. [#7] - Add MobilePane.test.tsx (previously untested safety logic) and a MobilePage saved-local-only restore test. [#2, #5] Verified: 22 targeted tests pass, typecheck + oxlint clean, localization catalog/coverage and max-lines ratchet green. * fix(mobile): resolve adversarial-review findings for pairing UI Address accepted findings from the mobile pairing UI rework: - MobilePane: add a request-generation epoch so a late getPairingQR response can't paint a stale Relay QR after sign-out, a mode switch, or an address change; arm rotation when discarding a pending mint. - MobilePage: on sign-in, upgrade a signed-out local-only fallback QR to Relay (invalidate + rotate-regenerate); handle null->connected too. - Extract useMobilePairingQrInvalidation so both sign-in/out edges and cross-window preference syncs invalidate/re-mint the QR consistently. - MobilePane: clear + rotate the QR when the selected address changes (manual pick or refresh-driven) so it can't encode the old endpoint. - MobilePairingConnectionOptions: guard the Sign in CTA on configured; show an Unavailable panel on unconfigured builds instead of dead CTA. - Drop the duplicate sign-in helper from MobilePairingSetupSection. - Remove dead i18n keys (title, recommended, signInToGenerate) and add relayUnavailable across all locale catalogs. - Add tests: deferred sign-out/mode-switch races, sign-in upgrade, cross-window sync, unconfigured build, arrow-key radiogroup. TODO left for the relay-label-honesty finding: getPairingQR does not expose the actually-encoded mode when an automatic offer degrades to local-only, so the mismatch can't be surfaced without a new return field. * fix(mobile): resolve relay-pairing deep-review regressions - MobilePane: invalidatePairing now clears loading so a superseded mid-flight generate can't wedge Generate disabled forever - MobilePage: stop auto-minting a local-only QR under the Relay label when signed out with Anywhere; gate Step 2 auto-generate and the Generate button on a shared canMintMobilePairingOffer helper, align with Settings, clear QR + loading on sign-out, mint Relay on sign-in - qr-invalidation: clear pairQrDataUrl (and loading) on every invalidation path so a stale QR can't stay scannable during rotation - Strengthen MobilePane/MobilePage tests for the aligned behavior and stuck-loading coverage - Translate relayUnavailable in es/ja/ko/zh Co-authored-by: Orca <help@stably.ai> * fix(mobile): refuse to mint QR when signed-out with Anywhere selected Replace silent degradation of Anywhere mode to local-only QR with explicit refusal. Add canMintMobilePairingOffer guard across all mint paths (address change, network invalidation, connection mode switch). This ensures the UI honestly encodes the selected pairing path. Improve keyboard focus visibility on the path selector by adding a persistent focus ring. * fix(mobile): detect and flag Relay provisioning degradation When Relay provisioning fails during automatic (Anywhere) pairing offer creation, the offer silently degrades to local-only. This confuses users who selected Anywhere expecting cellular capability. Add connectionMode field to the pairing offer result to expose what the offer actually encodes. The UI now flags degradation when the offered mode mismatches the user's selection. Also move credential rotation logic to the main process: rotate when requested mode differs from the pending token's encoded mode. This ensures QR codes displayed under an old policy can't pair under a new one, and windows reminting after preference sync converge on one token. Rename MobileRelayBetaAvailability → MobileRelayBetaNotice. * test(mobile): verify pairing codes don't flash during Relay mint Assert that the pairing QR and URL remain hidden while the Relay mint is pending, preventing confusing intermediate states when signing in unlocks Relay. --------- Co-authored-by: Orca <help@stably.ai>
42 lines
1.4 KiB
TypeScript
42 lines
1.4 KiB
TypeScript
export type MobilePairingConnectionMode = 'automatic' | 'local-only'
|
|
|
|
/**
|
|
* Resolve the pairing path to show / remember.
|
|
*
|
|
* - Explicit saved preference wins (user already chose).
|
|
* - Otherwise default to Anywhere (`automatic`). Relay still requires sign-in
|
|
* at QR time; the UI can keep Anywhere selected while signed out.
|
|
*/
|
|
export function resolveMobilePairingConnectionMode(
|
|
saved: MobilePairingConnectionMode | null | undefined
|
|
): MobilePairingConnectionMode {
|
|
return saved === 'local-only' ? 'local-only' : 'automatic'
|
|
}
|
|
|
|
/**
|
|
* Mode encoded into a pairing QR. Anywhere cannot be committed without a
|
|
* signed-in desktop session for Relay.
|
|
*/
|
|
export function effectiveMobilePairingConnectionMode(args: {
|
|
preferred: MobilePairingConnectionMode
|
|
signedIn: boolean
|
|
}): MobilePairingConnectionMode {
|
|
if (args.preferred === 'automatic' && !args.signedIn) {
|
|
return 'local-only'
|
|
}
|
|
return args.preferred
|
|
}
|
|
|
|
/**
|
|
* Whether a scannable pairing offer may be minted for the selected path. Anywhere
|
|
* (Relay) needs a signed-in desktop; minting a local-only QR under the Relay
|
|
* label would misrepresent what the code encodes, so both surfaces gate
|
|
* generation on this rather than silently degrading to local-only.
|
|
*/
|
|
export function canMintMobilePairingOffer(args: {
|
|
connectionMode: MobilePairingConnectionMode
|
|
signedIn: boolean
|
|
}): boolean {
|
|
return !(args.connectionMode === 'automatic' && !args.signedIn)
|
|
}
|