Communications

Unified messaging surface — email (inbox / sent / trash / unread), alerts (triggered / acknowledged / history), voice calls (inbound / outbound / missed), and the people address book. Section IA lives in YAML and renders into COMMUNICATION_SECTIONS via the shell generator.

binds_to: email, contacts, phone-number, alertdensity: comfortablesource: portal/src/canvas/communication_panel.rs

Declared but not yet dispatched — a real panel whose bound element types do not route to it at runtime today (often intentionally: an anchored popover, a sub-surface of another panel, or a future surface pending other work). See the panel's YAML for the specific reason. Amber means "still to do", not "broken".

Live

The real panel component, mounted here over fixture data — the same shipped chrome the workspace renders, not a sketch.

communications
Communication
Inbox
Loading...

Sketch

Structural preview of the panel chrome. The browser panel renders the real BrowserChrome primitive at miniature scale; the other variants are CSS shape silhouettes. Either way the composition tree below is the authoritative description of what's inside.

Communicationsportal/src/canvas/communication_panel.rspartial

States

  • emptyNo messages in active stream
  • loadingLoading messages...
  • populatedInbox stream with messages and an active selection
  • drag_in_progressDragging a message — drop targets highlighted
  • detail_openViewing message detail (right-side overlay or replacement view)
  • composingComposing a new message (draft auto-saved)
  • phone_claimPhone-number claim flow active

Composition

Click any component name to jump to its component-page entry.

CommunicationPanelRootouterElement-agnostic outer container. The sidebar / list / detail / compose sub-views are switched off CommunicationView (List, Detail, CallDetail, Compose, PhoneClaim) — no element-type branching.
CommunicationSidebarrailLeft rail — collapsible sections (Messages, Alerts, Calls, People) hosting the streams. Sidebar IA is YAML-driven (chemistry/shell/panels/communication/shell.yaml → COMMUNICATION_SECTIONS) so portal code carries no hardcoded folder list.
SidebarSectionrailOne row per section header — collapsible, persists open/closed state in CommunicationManager.sidebar_open. Each section streams render below it when expanded.
SidebarStreamrailOne row per stream within a section. Drop targets (trash, important) accept drag-and-drop messages; non-drop streams suppress the dragover preventDefault so the browser shows 'not allowed'.
UnreadCounterPillstatusPer-stream unread badge. Pulled from CommunicationManager fold over the cached items; updates eagerly when a message is opened (optimistic seal).
CommunicationFilterBarchromeAbove-list filter strip — search input + active stream label + drag-state indicator. Search drives CommunicationManager.filter_query; active_stream drives the body fetch.
CommunicationListViewcontentDefault body view (CommunicationView::List). Renders CommunicationListItem per row with optimistic-seal hover, drag handle, and drop-target highlight when an active drag matches stream_supports_drop.
CommunicationListItemcontentOne row per message / alert / call. Click → set_view(Detail{message_id}); drag-start → mgr.dragging_id; double-click on people-all stream → drill into ContactDetail modal.
PaginationCuecontrolTail of the list — 'Load older' button when next_page_token is Some, 'Loading…' shimmer while loading_more=true. Keeps fetch chunks bounded so 30s SigNoz timeouts don't strand the user.
CommunicationDetailViewcontentWhen CommunicationView::Detail — full message body, header (from / to / subject / received), thread context, and reply / forward / delete actions. Inline thread expansion via Disclosure.
CallDetailViewcontentWhen CommunicationView::CallDetail — call timeline, recording playback (when present), call notes, and follow-up affordances. Replaces the message-detail body without leaving the panel.
CommunicationComposeViewcontentWhen CommunicationView::Compose — to / subject / body fields with localStorage-backed draft survival. Restores on circle change so a refresh-mid-draft still has the user's text.
PeopleListViewcontentWhen active_stream='people-all' — alphabetical list with search + tag chip filter. Read-only at v1; writes (create / DNC / tag) flow through the agent, not this surface.
ContactDetailoverlayModal stacked on top of the panel when a PeopleListView row is clicked. The contact panel (chemistry/panels/contact.yaml) provides this surface — the communications panel is a host, not its owner.
PhoneClaimViewcontentWhen CommunicationView::PhoneClaim — number provisioning flow. Bridges to PhoneManager.readiness; flips back to List automatically when readiness resolves to Ready.
PanelEmptyStatestatePer-stream empty body — 'No messages in <stream>' with a 'Compose' or 'Wait for an alert' CTA depending on stream identity. Empty differs from loading: only renders after the first fetch settles.

Uses Components

Flat list of every component referenced — verifiable against the composition tree by the future generator audit.