Repository navigation
refactor: apply url actions in the test route (@miodec) - #8475
Conversation
# Conflicts: # frontend/src/index.html # frontend/src/ts/components/common/Setting.tsx # frontend/src/ts/components/mount.tsx # frontend/src/ts/components/pages/test/TestPage.tsx # frontend/src/ts/components/pages/test/result/replay.ts # frontend/src/ts/controllers/chart-controller.ts # frontend/src/ts/elements/caret.ts # frontend/src/ts/elements/test-init-failed.ts # frontend/src/ts/event-handlers/test.ts # frontend/src/ts/index.ts # frontend/src/ts/test/caret.ts # frontend/src/ts/test/funbox/layoutfluid-funbox-timer.ts # frontend/src/ts/test/funbox/memory-funbox-timer.ts # frontend/src/ts/test/pace-caret.ts # frontend/src/ts/test/result.ts # frontend/src/ts/test/test-logic.ts # frontend/src/ts/test/test-screenshot.ts # frontend/src/ts/test/test-ui.ts
Adopt master's test page unmount (bindTestElements, optional carets) over the branch's placeholder refs; test page show/hide logic stays in TestPage, driven by the router signals. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LFv5oixtD54uhzpzvLu34N
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LFv5oixtD54uhzpzvLu34N
- move route/loading/fade/transitioning state into router/page-transition.ts, driven by events from the router, withLoading and Pages - route load failures go through tanstack (loaders throw) instead of a global error flag - render the test page like every other page (drop the always-mounted shell) - route replaceSearch through the router so its location stays in sync - add isTestPageActive memo - remove leftover lorem ipsum from settings page Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LFv5oixtD54uhzpzvLu34N
- move navigation guards from navigate() into a router history blocker (covers links, navigate() and back/forward; redirects and replaceSearch bypass it) - register router type so `to` is checked against the route tree - Button takes `to`/`params` and renders Link; `href` is external only - provide router context to all component roots so Link works outside RouterProvider - remove initRouter click delegate, router-link attr and css hack - remove unused `force` option from navigate() Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…into solid-pages # Conflicts: # frontend/src/ts/components/layout/footer/ScrollToTop.tsx
…ith plain signals and functions Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous page fades out before the next one mounts, tracked by a local signal in Pages. Navigation is no longer blocked during fades - the fade always swaps to the latest target. startTest checks the route instead. isTestPageActive is set by TestPage while mounted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
router.state is backed by solid signals, so the route page and load error are memos over its matches instead of copies set in router events. The router instance is a signal in navigate.ts so state modules can read it without importing the route tree. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resize re-centering, autofocus, refocus restarts and the monkey/modifier key listeners are registered by bindTestElements and removed when the test page unmounts, instead of global listeners checking the active page. Code that touches test elements checks TestUI.isMounted(). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Components use useMatchRoute, vanilla code uses isTestRoute (router.matchRoute over the router signal). TestPage no longer sets global state. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The route page only changes once the next route has loaded, so check the target page instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
useIsTestRoute wraps useMatchRoute for components, listenForKeyState is shared by the monkey and modifier listeners, and the loading page reset reuses the initial indicator. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…loaded signals getSignal/signals read node values directly instead of the rAF-synced mirror, signals registered after startup are tracked, and a hot reloaded signal replaces the stale one with the same name and source. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- drop isTestRoute/useIsTestRoute, use getRoutePage() everywhere - loading-page.ts owns the loading page flag (hideLoadingPage) - createSearchState + readSearchOnEnter for url search params - test page lifecycle (ads, funbox, incomplete tests) moves into bindTestElements - replaceSearch logs when the router isn't initialised Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Query reads inside the router suspend the nearest boundary (every route is one), blanking the whole page. AsyncContent now wraps itself in Suspense: its loader is the fallback, or its content without data when alwaysShowContent is set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The router holder is typed as the app router via a type-only import, and
navigate takes typed { to, params, search } options instead of url
strings, so a broken internal link fails the type check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Anime: apply the initial state at once, start the enter animation on the next frame (content mounting right after insertion no longer eats it) - AnimePresence: an element that exits and comes back fades in again - AnimeShow: animate the fallback like the content - AnimeSuspense: Suspense that fades between fallback and content - tests for the above, AnimePresence exitBeforeEnter ordering tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- PageSwitcher: keyed Show in AnimePresence instead of createSwitchTransition
(page wrapper keeps the full-width grid layout)
- the router's pending component renders nothing: PageSwitcher shows the
loading page; the loading page wrapper lives in PageSwitcher
- Page: a suspending page shows the loading page's spinner ("X page is
still loading...")
- LoadingPage: no stale bar text under the spinner, spinner prop
- app-shell harness: animations finish at once, tests check the shown page.
Fade ordering is tested with AnimePresence, plus a page's fade in starting
after its content mounted
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # frontend/__tests__/components/common/anime/AnimePresence.spec.tsx
- comments still describing the createSwitchTransition page fade, the loading page as the router's pending component and the removed ADR - PageSwitcher story: LoadingRoutePage is no longer exported, use an empty pending component like the app router Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… place Content was read in Show/Suspense, so every change to it built a new wrapper and animated it in again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Errors outside a loading step showed only their message. They now read
"Failed to load the {page} page: ...". Loading step failures throw a
LoadingStepError and keep their message.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Moves controllers/url-handler into router/url-actions. The test route's beforeLoad applies shared links (testSettings, customTheme, challenge) and the discord oauth hash once the user data is in, then redirects to drop them from the url. Values are read from the raw search string so base64 and lz "+" survive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L8M7QTTf7Guriio4KfYJXv
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L8M7QTTf7Guriio4KfYJXv
Each action (challenge, custom theme, test settings, discord oauth) owns its link format: building the link and applying it. Typed as UrlSearchAction or UrlHashAction, apply.ts applies them in order. The discord oauth redirect_uri moves from /verify to /; old /verify links are rewritten to / until they're gone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| options: { history?: RouterHistory } = {}, | ||
| ) { | ||
| const history = options.history ?? createBrowserHistory(); | ||
| // TODO: remove once links started before the discord oauth redirect moved |
There was a problem hiding this comment.
A new Todo was discovered. If it is not a priority right now,consider marking it for later attention.
TODO: remove once links started before the discord oauth redirect moved
| isDevEnvironment() | ||
| ? `http%3A%2F%2Flocalhost%3A3000%2Fverify` | ||
| : `https%3A%2F%2Fmonkeytype.com%2Fverify` | ||
| ? `http%3A%2F%2Flocalhost%3A3000%2F` |
There was a problem hiding this comment.
should use getFrontendUrl. Is /verifyremoved on purpose?
is the redirect uri validated by discord and need to be updated there as well?
Port pipeDelimiter=false fix (#8263) into url-actions test-settings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
It reworks the auth/OAuth and routing entry flow with documented behavior changes and a backend redirect-URI change that depends on external Discord config, and it is explicitly not browser-tested.
1 open issue
What changed in this PR
Folds the legacy controllers/url-handler.tsx (an authStateChanged side-effect that re-read window.location on every auth change) into the TanStack router. URL actions (shared test settings, custom theme, challenge, Discord OAuth token) are now applied once in the test route's beforeLoad, after user data loads, then stripped from the URL via a replace redirect so they aren't re-applied on reload or sign-in/out. Each action is a self-contained module behind a small framework (action.ts), and raw params are read from searchStr/hash to preserve + in base64/lz values. The Discord OAuth redirect now targets / instead of /verify, with /verify still handled for old links.
Changes:
- Replaced the global auth-driven URL handler with per-action modules applied by the test route, driven by
applyUrlActions(location). - Removed the
verifyroute (now a pre-router/verify→/rewrite) and pointed the backend Discord redirect URI at/. - Removed
findGetParameter/checkIfGetParameterExistsfrommisc.ts; migrated link builders and moved/added tests.
| File | Description |
|---|---|
frontend/src/ts/url-actions/action.ts |
New action framework: encode/decode, readUrlAction, link builder. |
frontend/src/ts/url-actions/apply.ts |
applyUrlActions entry point: detects, applies in order, drops params. |
frontend/src/ts/url-actions/actions/test-settings.ts |
Test-settings action + link builder, legacy format preserved. |
frontend/src/ts/url-actions/actions/custom-theme.ts |
Custom-theme action + link builder with revert-on-error. |
frontend/src/ts/url-actions/actions/challenge.ts |
Challenge action with case-insensitive name lookup. |
frontend/src/ts/url-actions/actions/discord-oauth.ts |
Discord token action reading the OAuth hash. |
frontend/src/ts/router/routes.ts |
Test route beforeLoad applies actions + redirect; verify route removed. |
frontend/src/ts/router/create-router.ts |
Pre-router /verify→/ history rewrite for old links. |
frontend/src/ts/index.tsx |
Dropped the url-handler side-effect import. |
frontend/src/ts/controllers/url-handler.tsx |
Deleted (folded into url-actions). |
frontend/src/ts/utils/misc.ts |
Removed findGetParameter/checkIfGetParameterExists. |
frontend/src/ts/components/pages/settings/custom-setting/Theme.tsx |
Uses buildCustomThemeLink. |
frontend/src/ts/components/modals/ShareTestSettings.tsx |
Uses buildTestSettingsLink. |
frontend/src/ts/collections/utils/blocking-download.ts |
Renamed getStateWhenReady→stateWhenReady to match collections. |
frontend/__tests__/url-actions/*.spec.ts |
New/moved unit tests for actions and applyUrlActions. |
frontend/__tests__/router/app-shell.spec.tsx |
Integration tests for applying/dropping actions and Discord flow. |
frontend/__tests__/controllers/url-handler.spec.ts |
Deleted (replaced by url-actions specs). |
backend/src/utils/discord.ts |
Discord OAuth redirect_uri changed /verify→/. |
Review effort: Balanced
| ? `http%3A%2F%2Flocalhost%3A3000%2F` | ||
| : `https%3A%2F%2Fmonkeytype.com%2F` |

Description
Stacked on #8459. Folds
controllers/url-handler.tsxinto the router.controllers/url-handler.tsx->router/url-actions.ts. Loaders take the value instead of readingwindow.location;applyUrlActions(location)is the single entry point and returns the search/hash left over.beforeLoadappliestestSettings,customTheme,challengeand the discord oauth hash (/verifyalready redirects to/keeping the hash), then redirects to drop them. Skipped on preload.location.searchStrviafindGetParameter, not the parsed search:URLSearchParamsturns the+of base64 (customTheme) and lz (testSettings) into spaces.index.tsx.Behaviour changes:
/(all generated links point there; discord goes through/verify).history.replaceState(null, "", "/")also dropped the search.Evidence
url-actions.spec.ts: existing test settings cases moved over, plusapplyUrlActionscases (no actions, rest kept, raw+kept, discord hash dropped).app-shell.spec.tsx: actions applied and dropped from the url, applied after/verify, not applied on hover.Generated by Claude Code