Automations and webhooks for the AT Protocol airglow.run

Automation detail page shows times in the server timezone #10

Closed tyb.there-hugo.dev
Closed opened by tyb.there-hugo.dev

Problem #

app/routes/u/[handle]/[rkey]/index.tsx:261 formats "Last delivery" with new Date(...).toLocaleString() during SSR, which uses the server's timezone (UTC). Lines 226 and 235 (disabledAt) do the same. The delivery log island formats in the browser's local time, so the two disagree.

Seen in the session #

In https://www.youtube.com/watch?v=5MnT-ZgbBIc:

  • Throughout, e.g. 10:49 PM on the detail page vs 6:49 PM in the logs.

Fix direction #

Render a <time datetime> and format it on the client, or reuse the log island's formatting.

Details: docs/brainstorms/2026-10-17-graze-conference-automation-feedback.md (B6).

Queued: the loop will work on this version of the issue.

loop:queued cid=bafyreigey3djc25cfyomfdpbcpmf2qvomba2gzt5om7v3mdzqobgf4va4a

Working on this, attempt 1.

loop:claim run=contribute-20261026-144940-3my32eyebxx22 branch=loop/3my32eyebxx22 attempt=1 issue=10

fix(automations): show detail page times in the viewer timezone

The automation detail page formatted its timestamps with toLocaleString() during SSR, so they came out in the server's timezone (UTC) while the delivery log island showed the browser's local time: 10:49 PM against 6:49 PM for the same delivery. Those times now go through a new LocalTime island that renders <time datetime="..."> and formats it in the browser exactly the way the delivery log does (new Date(ts).toLocaleString()), so the two match.

Covered on app/routes/u/[handle]/[rkey]/index.tsx: "Last delivery", the disabledAt date in both auto-disabled alerts (rate limit and dry-run expiry), and the "Filtered out ... last on" time, which has the same bug on the same card.

Verification #

  • pnpm run check: passes (format, lint, types).
  • pnpm run test: passes (166 files, 2591 tests).
  • New app/islands/LocalTime.test.tsx (happy-dom) checks the datetime attribute and that the client text matches the delivery log's formatting. The route tests in index.test.tsx now check that the last delivery, last filtered and both disabledAt times render as <time datetime="...Z">, with a server text labelled UTC.
  • pnpm run build: the island gets its own client chunk and is registered as an island in dist/server.js, so it hydrates. I did not check it in a real browser because there is no dev server or PDS in this sandbox.

Acceptance criteria #

Decisions you can reverse #

  • The server-rendered text is UTC with a label (for example "10/17/2026, 10:49:00 PM UTC"), not an unlabelled server-zone time. Without JS, or until the island hydrates, the viewer sees a correct time that says it is UTC. Once hydrated, the island shows the local time with no label, matching the log.
  • I also fixed the "last on" time on the Filtered out line. The issue does not name it, but it is the same bug on the same card. Other pages with the same bug are left for the follow-up.
  • It is an island, not a client script in client.ts. That follows the project's islands pattern. Each use costs one small <honox-island> wrapper.

Follow-up, filed as a new issue on merge if the review agrees:

fix(ui): format the remaining server-rendered times in the viewer timezone

Two more pages format timestamps with toLocaleString() during SSR, so they show the server's timezone (UTC) rather than the viewer's, the same bug #10 fixed on the automation detail page:

  • app/routes/u/[handle]/[rkey]/logs.tsx:87: the "did not pass its conditions ... the last on

loop:pushed run=contribute-20261026-144940-3my32eyebxx22 sha=40f9f0528aab181559db3fcd5cf5e9f5e8bce119

Merge. The branch does what issue #10 asks. "Last delivery" and both disabledAt times on the automation detail page now go through a new LocalTime island. It renders <time datetime="...Z"> and, in the browser, formats the time with new Date(ts).toLocaleString(), the same call DeliveryLog.tsx uses, so the two now agree. pnpm run check and pnpm run test (166 files, 2591 tests) both pass on 40f9f05.

What I checked:

  • Acceptance criteria, against the code: I checked lines 261, 226 and 235 of index.tsx. All three now render LocalTime and no longer call toLocaleString() on the server.
  • Hydration: HonoX's client hydrates with hono/jsx/dom render by default (node_modules/honox/dist/client/client.js), which replaces the server markup. So the UTC text from the server (labelled "UTC") is swapped for the local-time text after hydration, with no mismatch warning. The only prop is a number, which serializes cleanly.
  • Text around the times: the JSX whitespace still gives "... on



loop:verdict run=review-20261026-145716-3my32eyebxx22 sha=40f9f0528aab181559db3fcd5cf5e9f5e8bce119 verdict=merge followup=1

Merged onto main as 54eb7d072fd74786ccba2c4205fa2bbf0826f4a4.

loop:merged sha=54eb7d072fd74786ccba2c4205fa2bbf0826f4a4 head=40f9f0528aab181559db3fcd5cf5e9f5e8bce119

Filed the follow-up as a new issue, not marked ready: fix(ui): format the remaining server-rendered times in the viewer timezone

loop:filed issue=3myryfwaicj2m

Sign up or Sign in to add to the discussion.