time input: replace hand-rolled fields with react-aria-components TimeField
All checks were successful
Build and Push Docker Image / build (push) Successful in 49s
All checks were successful
Build and Push Docker Image / build (push) Successful in 49s
the previous TimeInput was a bespoke two-field widget. correct in behaviour
but off-policy: we don't roll our own ui primitives when a maintained
library solves it. swap for react-aria-components + @internationalized/date
pinned to hourCycle={24}, granularity=minute, shouldForceLeadingZeros so
the output is always strict HH:MM regardless of browser/OS locale.
wrapper lives at src/shared/components/ui/time-input.tsx and keeps the
existing string-based API (value: "HH:MM", onChange(next)) so callers don't
change.
also updates the stack docs: web-stack.md now pins react-aria-components
as THE required library for every date/time ui; iOS and Android entries
mark their canonical component as TBD and explicitly forbid rolling our
own without user sign-off.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -77,6 +77,7 @@ mise exec bun -- bun start # production: Hono serves dist/ + API on :3000
|
||||
|
||||
## Forward-looking rules
|
||||
- [Schema changes need migrations going forward](feedback_schema_migrations.md) — resurrect the try/catch ALTER TABLE pattern in `server/db/index.ts` whenever touching table columns
|
||||
- [Never use locale-aware time/number widgets](feedback_iso8601_no_locale.md) — use `TimeInput` + `formatThousands`, never `<input type="time">` or `toLocaleString()`
|
||||
|
||||
## Workflow rules
|
||||
- **Always bump version** in `package.json` before committing/pushing. CalVer with dot-suffix per global AGENTS.md (`YYYY.MM.DD.N`). `.gitea/workflows/build.yml` tags a Docker image with this version, so the `+N` form breaks CI with `invalid reference format`.
|
||||
|
||||
17
.claude/memory/feedback_iso8601_no_locale.md
Normal file
17
.claude/memory/feedback_iso8601_no_locale.md
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Never use locale-aware time/number widgets
|
||||
description: Use src/shared/components/ui/time-input.tsx (wraps react-aria-components TimeField) and formatThousands helper — never `<input type="time">` or `toLocaleString()`
|
||||
type: feedback
|
||||
originSessionId: de22fecc-a14b-436f-b6c2-55e545bca160
|
||||
---
|
||||
In this project, times render as 24h `HH:MM` and numbers with a comma thousands separator **regardless of browser/OS locale**. Never reach for:
|
||||
|
||||
- `<input type="time">`, `<input type="date">`, `<input type="datetime-local">` — Chrome on macOS in en-US renders AM/PM, Safari in de-DE renders `DD.MM.YYYY`, no attribute overrides this reliably.
|
||||
- `Date.prototype.toLocaleString()`, `toLocaleDateString()`, `toLocaleTimeString()`, `Number.prototype.toLocaleString()` — silently flip separators/format per locale.
|
||||
|
||||
**Use instead:**
|
||||
- `TimeInput` from `src/shared/components/ui/time-input.tsx` — a thin wrapper around `react-aria-components` `TimeField` pinned to `hourCycle={24}`, `granularity="minute"`, emits strict `HH:MM`.
|
||||
- `formatThousands()` from `src/shared/lib/utils.ts` for number grouping.
|
||||
- If a new need (date field, range picker) appears, extend using the **same** `react-aria-components` / `@internationalized/date` toolkit — we are committed to that library for every date/time UI on this project. Do **not** hand-roll a parallel component (the user stopped me on 2026-04-13 when I started doing that — they want maintained libraries, not bespoke inputs).
|
||||
|
||||
**Why:** AGENTS-web-stack.md now mandates this stack-wide. The user was emphatic ("FUCK THIS" on AM/PM, 2026-04-13); keeping ISO 8601 consistent is a core product constraint, not a nice-to-have.
|
||||
14
.claude/memory/feedback_schema_migrations.md
Normal file
14
.claude/memory/feedback_schema_migrations.md
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Schema changes need migrations going forward
|
||||
description: From 2026-04-13 onwards, any media_items/media_streams/review_plans schema change must ship an idempotent ALTER TABLE migration in server/db/index.ts — don't rely on the factory-reset button
|
||||
type: feedback
|
||||
originSessionId: de22fecc-a14b-436f-b6c2-55e545bca160
|
||||
---
|
||||
When adding or altering a column in `server/db/schema.ts`, also add an idempotent `ALTER TABLE ... ADD COLUMN` migration in `server/db/index.ts` so existing deployments (the Unraid container with a persistent `./data` volume) pick it up without losing scan state.
|
||||
|
||||
**Why:** On 2026-04-13 we wiped the schema twice in one day (canonical-language rewrite, schedule split). The first time I deleted the old try/catch migration shims because the user said "drop the whole scan database" — fine for local dev, but the production container's volume silently carried the old schema and the scan loop crashed with `table media_items has no column named original_title`. We then re-added migrations, then deleted them again because a factory-reset button now handles the upgrade path. The user's intent after that last removal was *not* "migrations are dead forever" — it was "for this one upcoming reset, we don't need them." Future schema changes should resurrect the pattern.
|
||||
|
||||
**How to apply:**
|
||||
- The pattern: a local `addColumn(table, column, type)` helper inside `getDb()` (or a dedicated `applyMigrations(db)` function) that wraps each `ALTER TABLE ... ADD COLUMN` in try/catch, because SQLite has no `ADD COLUMN IF NOT EXISTS`. Keep entries forever — fresh installs get the column from `SCHEMA`; upgrading installs get it from the migration function. Removing an entry breaks any install that didn't apply it yet.
|
||||
- For destructive changes (renames, type changes, dropped columns) the factory-reset button in Settings → Danger Zone is the escape hatch — tell the user to click it.
|
||||
- When in doubt, check git history around 2026-04-13: commit `c06172f` added the migration function back, commit `a3fde7c` removed it as a temporary simplification.
|
||||
Reference in New Issue
Block a user