Discussion

The Activity section of a task: quiet one-line system events, comments as framed cards, and one composer under the thread. The pattern is Linear's "Issue view · Activity". Built in apps/web/src/components/projects/TaskActivitySection.tsx, CSS apps/web/src/ds/task-detail.css (.tdl-act, .tdl-feed, .tdl-ev, .tdl-cm, .tdl-composer). The thread is the polymorphic Comment of the R11 contract (entity_type='task' is the only value in v1). The project Activity tab does not use it; it keeps its own timeline.

Status is beta: the section is built and storied, and waits for the visual check before it is promoted.

When to use

  • A conversation between people on one record, read top to bottom, where anyone involved can add to the end.
  • Where a short system event ("Úkol založen") belongs in the same sequence as the comments.

When not to use

  • A written record attached to an entity that is browsed, not read in sequence — that is note-card.
  • A pure chronology of what happened on a record with no replies — that is timeline.
  • A conversation with the assistant — that is ai-assistant.
  • A thread you have not been able to load. That is the error state, never an empty thread (see Behaviour).

Anatomy

  • Section .tdl-act: 800px column, divider line on top (the single horizontal break that separates the document from what happened around it), heading .tdl-act-h ("Aktivita", --h3, secondary ink).
  • Feed .tdl-feed: events and comments in one column, oldest first.
  • System event .tdl-ev: history glyph, one line of text, time pushed to the right (.tdl-ev-at). No frame, no avatar — an event has no author.
  • Comment .tdl-cm: an <article> with a hairline frame and --radius-md. Header .tdl-cm-h carries the avatar, the name .tdl-cm-nm, the age .tdl-cm-at (with "· upraveno" after an edit) and, for the author, the actions .tdl-cm-acts (pencil, trash). Body .tdl-cm-b keeps line breaks.
  • Editing .tdl-cm-ed: the card body becomes a Textarea with Zrušit and Uložit in .tdl-cm-ed-f.
  • Composer .tdl-composer: one box — the Textarea on top, the footer .tdl-composer-f below with the participants line on the left and the primary Komentovat on the right. The textarea carries no frame of its own, so the box does not show a border twice.

Behaviour

  • Composer under the thread. The thread is read oldest-first and a new comment is appended at the end; a field above would make the user write at the start of what they have not read yet.
  • Weight by kind. An event is a quiet line, a comment is a card. The frame is what says "a person wrote this".
  • Own comments only. Edit and delete are offered where the server marks the comment canEdit, not by comparing author ids in the client. Delete asks for the canonical confirmation first. On a phone the two actions collapse into a ⋮ menu that is always visible; on desktop they appear on hover or focus of the card.
  • Draft survives a failed write. The composer is cleared only after the server accepted the comment, so a rejected write does not cost the user their text. A toast reports the failure.
  • Error is not empty. If the thread does not load, the section shows the error state (EmptyState tone="error", retry) and hides the composer — writing into a thread you could not read is writing blind. An unloaded thread must never fall through to the one creation event, because that would claim the task has no comments.
  • Loading and empty. While the thread is on its way the section shows only the creation event and the composer, with no spinner; a loaded thread with no comments looks the same, plus no participants line until someone is involved.
  • Participants line ("Upozorníme 3 lidi") counts who the comment concerns. The count comes from the contract, by the same rule that will drive notifications; the section never computes it itself. It is visual only in the FE phase — nothing is sent — and the full list with the reason for each person (mentioned, assignee, author of the task, already commented) is in its title.
  • @mention is plain text until the BE phase. The composer is a plain Textarea, not MentionInput; the suggest list queries the live directory and the FE-phase mock has no users in it. The mock understands a written "@Jana Nováková" so the participants line works on the preview. The picker arrives with the BE phase.
  • System events are one so far ("Úkol založen"). More will come from the activity log, not from client-side guessing.

Best practices

Do

  • Keep the composer last in the section, after the whole thread.
  • Keep events one line and unframed; give them no avatar and no actions.
  • Show the error state with retry when the thread fails to load.
  • Resolve the avatar of a comment author from the directory, not from the name alone.

Don't

  • Put the composer above the thread.
  • Frame an event or give it an avatar to make it look like a comment.
  • Show the composer next to the error state, or fall back to an empty thread when loading failed.
  • Decide "can edit" in the client by comparing ids.
  • Promise delivery in the participants line while the FE phase sends nothing.

Content

  • Heading Aktivita; event Úkol založen; actions Upravit komentář, Smazat komentář; primary Komentovat.
  • Placeholder Napsat komentář… (@jméno zmíní kolegu).
  • Participants line follows Czech plural: Upozorníme 1 člověka, 2 lidi, 5 lidí.
  • Age uses the shared relative label (dnes, včera, před 3 dny); an edited comment adds · upraveno.
  • Error: Diskusi se nepodařilo načíst, with the generic reload sentence below it.
  • note-card — a note as a card, browsed rather than read in sequence.
  • timeline — an ordered feed without replies.
  • ai-assistant — the conversation with the assistant.
  • empty-state — the error and empty blocks reused inside the section.
  • Stories: components--discussion--default, --states, --composition.

Source: docs/discussion/discussion.usage.md · GitLab