@pi/ui's slide toggle hides its input with display: none and gives it
no name: neither the Tab key nor a screen reader could reach the
switches in settings (visibility, the public's proposals, the
definition of done, the link for clients) or the bell's (e-mail copy,
notices on this device). They are pi-checkbox now, each with a name
saying what it turns on: reachable by keyboard, toggled with the space
bar and announced.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@pi/ui gives every button a fixed height, side padding and a minimum
width. Three of ours, laid out by their own component, took it:
- a notice in the bell's panel stayed 40 px tall, so a two-line one ran
over the next;
- a day number in the calendar became a 40 px pill that ran into the
sprint bands under it (today's, coloured, showed it);
- «Responder» under a comment became a grey pill sitting on its line.
They keep their own box now, and «Responder» is a text link.
The home page shows my projects first, right under the greeting: what
most visits come to open.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- What reaches the bell also reaches the devices where the person
turned «Avisos en este dispositivo» on, with TaskStream closed: the
Notifier sends each new notification encrypted (aes128gcm) and signed
with VAPID, and forgets subscriptions the push service dropped
(404/410). A failure never blocks the event stream.
- The API keeps one subscription per device (push_subscriptions) and
exposes the VAPID public key in the notification settings; GraphQL
subscribePush/unsubscribePush, REST /me/push-subscriptions. Without
VAPID_PUBLIC_KEY and VAPID_PRIVATE_KEY push is off.
- The web registers /push-sw.js, a service worker that only shows the
notification and opens its ticket on a tap (no caching, served
without cache by nginx), and a manifest that makes it installable,
which iPhones need for push.
- The bell's toggles show their text next to them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The web pings the live connection, reconnects when it goes quiet and
reloads what each screen shows after reconnecting.
- Dropping a card on a column it cannot go to puts it back.
- Owners and admins get a notice when a proposal arrives.
- The proposal limit lives in Redis, so it holds across instances.
- REST tells whether I voted; pasted images leave the attachment list.
- Deleting a project removes its Git integration; no lint warnings left.
- Reactions and the blocked badge are components of their own.
- Docs: what is done and what is left (chapter 10), Word and PDF.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A comment can answer another one (replyTo), one level deep: answering a
reply joins the same thread, and it must be on the same ticket. Whoever
wrote the comment gets a new REPLIED notification, and the activity says
"respondió a un comentario".
A comment deleted while it has replies stays, without its text
(deleted: true), so the thread still reads; it goes with its last reply
and does not count in commentCount.
The ticket page shows threads with their replies indented and a
"Responder" box; REST, GraphQL and the MCP (add_comment, get_issue) take
and show replyTo. Existing comments are unchanged. Docs, Word and PDF
updated.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mention project members in comments with @, follow and unfollow tickets,
and get told when something changes on the tickets you follow. Commenting
on a ticket starts following it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Derived from events and kept per person: whoever a ticket is assigned to,
whoever reports or works on it when it moves, fails QA or gets a comment,
and whoever joins a project. Never about what you did yourself, once per
event. They arrive live through a subscription to a bell in the header,
and are copied by e-mail to whoever turns it on when SMTP_URL is set.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>