Commit graph

2 commits

Author SHA1 Message Date
ScreenTinker 618af0811a Translate the labels that never went through t()
A title= is a tooltip the user reads and an aria-label is what a screen reader
says, but fourteen of them were hardcoded English. They were invisible to the
key checks added earlier precisely because they never call t() — so a French
user hovering the only route to workspace members read "Manage members", and a
German screen reader announced every modal's close button as "Close".

The user-visible ones matter most: the workspace switcher's Manage members and
Rename, the video wall's rename and remove, and the dashboard's select-for-wall.
All are translated into every active locale, along with the close buttons.

A test now rejects a capitalised literal in a title or aria-label, since that is
the shape this takes and nothing else catches it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
2026-07-28 19:52:52 -05:00
ScreenTinker ae595a208d feat(admin): Create Organization for platform admins (#35)
MSPs onboarding customers as separate orgs had no way to create one with
AUTO_CREATE_ORG_ON_SIGNUP=false (the only path was signup auto-org). Add a
platform-admin 'Create organization' action.

POST /api/admin/orgs (requirePlatformAdmin) creates the org + its first 'Default'
workspace. organizations.owner_user_id is NOT NULL, so an org can't be ownerless;
the creating admin becomes org_owner + workspace_admin (mirrors the signup
bootstrap in routes/auth.js) - which also surfaces the org in their switcher.
Customer users are then added via the existing Add User / manage-memberships flow.

UI: 'Create organization' button + single-field modal in the Admin area (gated).
Tests: create (201 + memberships + audit), empty-name 400, non-admin/operator 403.
2026-06-09 09:10:15 -05:00