-
Notifications
You must be signed in to change notification settings - Fork 0
feat: one source of login state, a login page, a demo coach and delete a gymnast #141
Merged
+2,620
−218
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
…mnast The menu, the protected pages and the gymnasts page now read the same answer from the server (me) through useAuth(), so they cannot disagree and a reload keeps a logged-in coach on the page. Log in goes to a login page with the demo coach and the test coach; ProtectedRoute waits for the answer and remembers where the visitor was going. A gymnast can be deleted after a confirmation. Part of #136, #138
…uld need Adds docs/AUTHENTICATION.md with what the course asks for, everything we tried before choosing the test login (Google, https, passwords, our own encryption), how the login is guarded, what it does not protect, and what we would do with https. Updates the README, API.md, VM_SETUP.md, UI_PLANS.md and AI_USAGE.md. Closes #136, #138
- Follow the theme: the page, the cards, the form and the login page use theme values that have a dark value (new tokens for the circle, the field, the red and the "No, keep it" button), and the contrast is tested. - Bigger cards and text, a smaller circle, and a red trash button that is 48 by 48 CSS pixels so it can be pressed on a phone. - Add form: the field with a save tick and a close cross at the end of it, no heading and no Cancel button, Enter saves and Escape closes. - Name: at most 70 characters can be typed or pasted, at least 3 to save. - The title of the page has the same style as the Elements page. - Delete dialog: a warning icon, "Delete gymnast", what is lost as a list, and "No, keep it" and "Yes, delete" with a visible edge and a shadow. Refs: #136, #138
|
Really solid work! 🎉 Tested in a clean copy with a seeded database: tsc, lint, the build and all 498 tests pass, and I also tried it in the browser, since the PR says it was not tried by hand: Small things:
Generated with Claude Code |
- The save tick is green in both themes (white tick on green in light mode, dark tick on green in dark mode) and is no longer the color of the card. - The hint "3 to 70 characters" is gone. An error shows only after Save or Enter, in red: "Name is required" for an empty name, as the API asks for 1 to 70 characters. No more than 70 can still be typed or pasted. - The gymnast cards get a tint and a deeper shadow on hover (both themes), and a pointer, to show that they can be pressed one day. - "No, keep it" has white text in dark mode only, on a dark fill with a light 2px edge (9.6:1 on the card). White text and a fill that is 3:1 on the card cannot both be had, so the edge carries the contrast of the control. - The test of the whole path gets more time when all the tests run at once. Refs: #136, #138
…dark mode The outline variant of the button sets colors of its own in dark mode (dark:bg-input/30), and they won over the green of the save tick and the fill of "No, keep it", so neither had the intended color in dark mode. Both now use the default variant, and the hover of the two ghost buttons is set for dark mode too. A test fails when an outline button does not also set its colors for dark mode. The test of the whole path answers the new CatalogStructure query. Refs: #136
The tab said the name of the project on /login and while "Checking your login…" was shown (WCAG 2.4.2). Both now use PageTitle like the other pages. The title test of the gymnasts page matches the name exactly, because the hidden "Delete <name>" would also match a pattern. Refs: #136
The extra check for 6:1 was a design choice that only pinned the current color. The limits of the rule stay: 3:1 for the edge of a control and 4.5:1 for the text. Refs: #136
A blue-grey line (3.6:1 on the card, above the 3:1 of WCAG 1.4.11) does not draw the eye first, as the lighter line did. Refs: #136
Sign in
to join this conversation on GitHub.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Summary
The menu and the "Your gymnasts" page no longer disagree about who is logged in, "Log in" leads somewhere, and the project has a demo coach that the staff and the students who review it can use to save and delete things. The reasons for the login we have, everything we tried before choosing it, and what a real system would do are written in a new
docs/AUTHENTICATION.md.Closes #136, #138. (#137, accounts with passwords, is closed as not planned: see "Choices".)
What is in it
AuthProviderasks the servermeonce, anduseAuth()givesloading,authenticatedoranonymous. The navbar,ProtectedRouteand the gymnasts page read it. TheisLoggedInuseStateinApp.tsxis gone.false, so a logged-in coach was sent away from/gymnasts; and the menu could say "Log out" while the page said "Log in".ProtectedRoutewaits while the answer is on its way ("Checking your login…") and does not send anyone away. The menu shows neither "Log in" nor "Log out" until the server has answered.resetStore), which asksmeagain, so the menu and the page change at once (clearStoreonly cleared the cache)./login). "Log in" in the menu goes there, andProtectedRoutesends a visitor who is not logged in there with the page they wanted; after the login they go to it (only a path on this site;//evil.exampleis ignored). It has "Log in as the demo coach" (one click) and the form for a test coach of your own. The page says when it is served over http from another computer that it is not encrypted.variables.css.docs/API.md).global.css).npm run db:demomakes the demo coach (demo@wag-planner.example) with three gymnasts, each with three elements from the catalog. Run again, it deletes what the demo coach has and puts the example data back; other coaches are never touched.docs/AUTHENTICATION.md(new), and the README ("Try the app with the demo coach"),docs/API.md,docs/VM_SETUP.md,docs/UI_PLANS.mdanddocs/AI_USAGE.md.Choices
devLogin) and a seeded demo coachme, throughuseAuth()docs/AUTHENTICATION.mdhas the full list of what we looked at (Google, https on the VM, a trusted certificate, passwords, encrypting the password ourselves with a sealed box or OPAQUE, a guest key, passkeys and magic links), what the test login does not protect, and what we would do in production.Not done (still open)
docs/API.md).Testing
npx tsc -b,npx eslint .,npx vite buildandnpx vitest runpass: 49 test files, 488 tests, none skipped (the backend tests run against a local database).ProtectedRoute(waits, lets in, sends to the login page with the page they wanted),LoginPage(demo coach, own test coach,fromthat leaves the site, errors, double click),isInsecureConnection, the delete button,resetDemoCoach(including that the test login finds the same coach), the session functions of the client, and one test of the whole path insrc/App.flow.test.tsx: log in, save a gymnast, reload, log out, log in again and see the gymnast, delete it.isLoggedInprop, "Log in" is a link),App.test.tsx(the old test clicked the local toggle; replaced by three tests that use the server's answer), and the gymnast page tests (they need the providers; names are matched exactly, because the delete button has the hidden text "Delete "). No expectation was removed to make a test pass; the test of the login form on the gymnasts page moved toLoginPage.test.tsx.fromthat leaves the site, and resetting the store after a login. The last one was not caught by the flow test (it replaces the login functions), soclient.test.tswas added, and fails whenresetStoreis replaced byclearStore.🤖 Generated with Claude Code