Commit Graph
488 Commits
Author SHA1 Message Date
Quentin Gliech f03c39e773 Render the island error boundary without the page layout
The boundary only wraps islands, which already sit in the page layout and have no React Query client for the footer, so a render error (e.g. a blocked captcha script) left a blank island.
2026-10-16 11:17:12 +02:00
Quentin Gliech 3870a479d4 Add a back button to the password registration step
The step change does not touch the browser history, so without it the provider buttons were out of reach once on the password step.
2026-10-16 11:17:12 +02:00
Quentin Gliech 5a649f0424 Lowercase usernames without the browser locale
`toLocaleLowerCase()` follows the browser locale, so with a Turkish locale `I` became a dotless `ı`, which is not a valid localpart and does not match what the server does with `to_lowercase`.
2026-10-16 11:17:12 +02:00
Quentin Gliech 7232057685 Render the registration form with React
The server-rendered registration form is replaced by a React island mounted
on `/register`, which renders the CAPTCHA in-page, gives live password
complexity feedback, and lays out the upstream provider buttons and the
sign-in link the way `/login` does. The island owns the whole form, so every
variant of the page is rendered from the mount data alone, and the user fills
it in one step. Server-side validation errors are threaded back into it
through the mount node, so a rejected submission re-renders with the errors
attached to the fields they belong to, until the user edits them.

`RegisterContext` resolves the provider names and the sign-in link server-side
so that the island only has to render them. The sign-in link is derived from
the post-auth action in the query string instead of the `PostAuthContext`
loaded from the database, which drops a round trip from both the GET and the
invalid-form re-render.

Registering now requires JavaScript, including on the variant with upstream
providers only and on the one without a CAPTCHA: the <noscript> block shows a
notice instead of a duplicate form, which could not work anyway when a CAPTCHA
is configured. While the script loads, the page shows a skeleton of the form
to avoid layout shifts, and a hidden error notice is revealed if it fails to
boot. The server-rendered CAPTCHA component and its entrypoint are removed
with their only consumer.
2026-10-16 11:17:12 +02:00
Quentin Gliech 8e1d4e0f6d Reserve the space of the password confirmation message
The message appears when the confirmation field loses focus, which shifted the
button below it under the click that moved the focus away.
2026-10-16 11:17:12 +02:00
Quentin Gliech 4a64be619d Move the "or" separator styles into a CSS module
The class becomes `or-separator`, as the global `.separator` also matched the
footer's separator. The module is imported by `templates.css` for the SSR
`field.separator()` macro.
2026-10-16 11:17:12 +02:00
Stefan Ceriu a358c7e254 Refresh the browser sessions list after removing a browser session 2026-10-12 09:44:39 +03:00
Quentin Gliech 8cda28a734 Add a shared boot helper for React islands (#5975) 2026-09-16 10:56:12 +02:00
Quentin Gliech 05d2f37423 Add a shared boot helper for React islands
The helper parses the mount node's dataset, waits for the i18n setup
before the first render, and swaps the page to a server-rendered error
notice when booting fails. This fixes the account app staying on its
loading screen forever when fetching the locale data fails, and gives
upcoming server-rendered pages with React islands a common entry point.
Waiting on the setup requires `setupI18n` to return the initialisation
promise, so it now does.
2026-09-15 15:08:00 +02:00
Quentin Gliech 179f1f9b1d Extract the password complexity feedback out of PasswordCreationDoubleInput
The strength meter, the improvement hints and the too-weak error move to
a `PasswordComplexityFeedback` component backed by a
`usePasswordComplexity` hook, so that forms which lay out their password
fields differently can reuse them. `PasswordCreationDoubleInput` takes
the minimum complexity as a plain number instead of a `SiteConfig`
fragment; its two callers already query `siteConfig`, so they pass the
field directly.
2026-09-15 15:08:00 +02:00
Quentin Gliech cd2ef4cbd7 Merge main into quenting/react-captcha 2026-09-08 12:38:14 +02:00
Quentin Gliech 119f3244d6 Remove all the remaining inline <script> tag (#5912) 2026-08-14 16:26:39 +02:00
Quentin Gliech ee1a104705 Render the CAPTCHA widgets with React on server-rendered pages
Instead of provider-specific markup and script tags in the head, the
captcha.form() template macro now emits a placeholder element carrying
the CAPTCHA configuration in data attributes, on which a new entrypoint
mounts the React Captcha component. The widget still injects its hidden
response field inside the form, so the server-side verification flow is
unchanged.

This is the first use of inline React components to progressively
enhance server-rendered pages.
2026-08-14 15:47:19 +02:00
Quentin Gliech d0370a6b3f Simplify the Captcha component back down
The previous commit grew a load timeout, script-tag eviction, an error
boundary and a retry button, and swapped the imperative `CaptchaHandle`
ref for an `onValidChange` callback. None of that is needed to mount a
widget on a server-rendered page, and some of it does not work: removing
the `<script>` tag does not stop a load the browser has already started,
and the timeout deletes the global onload callback, so an SDK which is
merely slow ends up calling into nothing.

Go back to exposing validity through a ref, and keep only the
per-provider placeholder heights, which are what stops the page jumping
once the widget renders. Whatever a React form needs to react to the
captcha being solved belongs with that form.
2026-08-14 15:47:19 +02:00
Quentin Gliech 182e08d0cb Add a React component to render CAPTCHA widgets
Adds a reusable Captcha React component along with the type
definitions for the supported providers (hCaptcha, Cloudflare
Turnstile, Google reCAPTCHA). The provider SDKs are lazy-loaded by the
component itself, suspending the tree while they load, and evicted on
failure so a retry can re-attempt the load. The widgets report
solved/expired state through an `onValidChange` callback.
2026-08-10 16:51:37 +02:00
Quentin Gliech 5d7a66557a Load frontend translations with dynamic imports instead of fetch
`import.meta.glob` now generates lazy loaders for the locale JSON modules
rather than hashed asset URLs, so `Backend.read` awaits an `import()` instead
of doing a `fetch`. This puts translation loading under the `script-src` CSP
directive instead of `connect-src`, and lets the browser preload them as
modules, which the `<link rel="preload" as="fetch">` hint never really did
because of the credentials-mode mismatch.

Dynamic imports are cached for the lifetime of the page, so locale
hot-reloading now triggers a full page reload in dev instead of asking i18next
to re-read its resources.
2026-08-07 17:59:26 +02:00
Quentin Gliech 28ffb064bf Move the Swagger UI OAuth2 redirect script to a frontend entrypoint 2026-08-07 12:24:36 +02:00
Quentin Gliech ded9de23db Move the form_post auto-submit script to a frontend entrypoint 2026-08-07 10:25:04 +02:00
Quentin Gliech 300ede9fe8 Regenerate src/routeTree.gen.ts 2026-08-07 09:39:09 +02:00
Quentin Gliech a1bfbb6cdd Read the entrypoint configuration from data attributes
Instead of injecting configuration through inline <script> tags setting
window globals, server-rendered templates now carry the configuration
as data attributes on the entrypoint mount node, validated client-side
with a valibot schema over element.dataset. This removes all inline
scripts from the templates, which is friendlier to CSP, and gives the
frontend runtime-validated, typed configuration.

The DOM read and the wiring now happen in the entrypoints themselves:
main.tsx parses the mount node dataset, owns the QueryClient, and
injects the basepath and GraphQL endpoint into the router and request
layer instead of those being module-scope singletons.
2026-07-30 20:51:01 +02:00
Quentin Gliech 8f1db5b7b0 Revert "Fix the password complexity refusing to calculate in the frontend"
This reverts commit 6121def51e.
2026-07-16 17:14:00 +02:00
Quentin Gliech 6121def51e Fix the password complexity refusing to calculate in the frontend 2026-07-16 15:07:15 +02:00
Quentin Gliech 47e5f266a1 Regression test for password complexity calculation 2026-07-16 15:07:14 +02:00
Quentin Gliech 8e66532e08 Update test snapshots 2026-07-03 10:55:51 +02:00
Quentin Gliech 239dec3ee0 Adapt to the zxcvbn-ts v4 API, bump @zxcvbn-ts/language-common to match
v4 replaced the global `zxcvbnOptions`/`zxcvbnAsync` singleton with the
`ZxcvbnFactory` class. The warning/suggestion codes and options shape
are unchanged.
2026-07-02 22:22:33 +02:00
Quentin Gliech 42b265d21b Align the page heading and inline form styles with Figma 2026-05-28 13:30:25 +02:00
Quentin Gliech 5e4bc3b7c4 Import the alert component from Compound Web 2026-05-28 13:30:25 +02:00
Quentin Gliech e23b3067b7 Migrate to Tailwind v4 (#5702) 2026-05-26 17:09:55 +02:00
Quentin Gliech 8e65bf198e frontend: migrate to Tailwind 4
Tailwind 4 ships its own Vite plugin and no longer needs PostCSS plumbing.
Drop postcss/autoprefixer/postcss-import/postcss-nesting and the .postcssrc.json,
wire @tailwindcss/vite into vite.config.ts, replace the @tailwind directives
with @import "tailwindcss", and convert the JS tailwind.config.cjs theme
into a CSS @theme block in shared.css. An @source directive points back at
the SSR templates so the Jinja-rendered HTML in templates/ still gets scanned
for utility classes.

The third-party CSS (compound design tokens, compound-web, fontsource) moves
into a new vendor.css entrypoint, loaded ahead of shared.css from main.tsx,
storybook, and base.html. Tailwind v4's @import bundler silently drops the
nested `@import url(...) layer(cpd-base) screen` statements inside the
compound-design-tokens.css barrel, so we have to keep those imports out of
any file that contains Tailwind directives and let Vite's normal CSS pipeline
resolve them instead.
2026-05-25 16:31:36 +02:00
Quentin Gliech e03c953945 Adjust the button sizes to the new t-shirt size. 2026-05-25 16:28:42 +02:00
Quentin Gliech 99395c9e64 Make sure the footer is loaded before rendering the page 2026-05-25 12:46:00 +02:00
Quentin Gliech 41e8929ba5 Stop using the unsupported 'createFileRoute' typescript magic
Support for this ware removed from TanStack Router, so we need to explicitly set a route name when calling 'createFileRoute'.
2026-05-25 12:37:01 +02:00
Quentin Gliech 4bc2bc0e77 Update use of generated GraphQL types 2026-05-25 12:37:01 +02:00
Quentin Gliech ef6ecbbea0 Regenerate GraphQL types 2026-05-25 12:37:01 +02:00
Quentin Gliech f339a10485 Run formatter 2026-05-25 12:37:01 +02:00
Quentin Gliech c7654248ab Inline the browser icons
They are very small and don't need an extra request to load. This is useful as
well for making the snapshots not dependant on where the project is installed
2026-05-25 11:16:55 +02:00
Eric Eastwood d4e33f5121 Fix lints 2026-05-20 15:48:56 -05:00
Eric Eastwood c16eebdc6a Fix potentially typo 2026-05-20 15:47:58 -05:00
Eric Eastwood 1c648edb87 Use safer num_sessions_filtered_header pluralization
See https://github.com/element-hq/matrix-authentication-service/pull/5644#discussion_r3227855225
2026-05-20 15:47:09 -05:00
Eric Eastwood 8861cdbf70 Fix lints 2026-05-12 15:08:24 -05:00
Eric Eastwood 4a9cd47e87 Add NavItemErrorIcon
See https://github.com/element-hq/matrix-authentication-service/pull/5644#discussion_r3227879875
2026-05-12 15:04:40 -05:00
Eric Eastwood 551e2f1dd9 plural hit_session_limit_warning_description/approaching_session_limit_warning_description 2026-05-12 14:47:30 -05:00
Eric Eastwood e19b2f42e9 plural session_limit_info 2026-05-12 14:26:45 -05:00
Eric Eastwood fa6f90f672 plural num_sessions_filtered_header 2026-05-12 13:52:29 -05:00
Eric Eastwood 92f76bcc1f plural num_sessions_header 2026-05-12 13:32:15 -05:00
Eric Eastwood 698ffd7864 Fix fragment masking ($fragmentRefs) problems in tests
See https://github.com/element-hq/matrix-authentication-service/pull/5644#discussion_r3134443493
2026-05-12 12:11:10 -05:00
Eric Eastwood 6d3082e9dc Automatic updates 2026-05-06 09:53:02 -05:00
Eric Eastwood 51ec638b83 Design review: Use info styles for approaching limit warning 2026-05-06 09:48:32 -05:00
Eric Eastwood 336b80173e Merge branch 'main' into madlittlemods/soft-limit-account-session-management 2026-05-05 14:53:20 -05:00
Eric Eastwood d83a3e77f5 Add test to ensure error shown on account page 2026-04-23 18:01:30 -05:00