feat(ui): move channel config into dialogs + VoIP surface (#19)#1348
feat(ui): move channel config into dialogs + VoIP surface (#19)#1348dolho wants to merge 3 commits into
Conversation
Builds on the Sharing-tab reframe (#18). Replaces the inline collapsible channel panels with compact summary rows that open the existing config panels in a modal — the tab stays a clean summary instead of a wall of forms. - New ChannelConfigDialog.vue — Teleport modal (backdrop + Esc close, scrollable body) matching the ConfirmDialog idiom. - New ChannelConfigRow.vue — summary row showing connected/off + a brief status (channel/handle/number), a Configure/Manage button that opens the dialog, and a lightweight status fetch (shared `api` client) that refetches on dialog close so the row reflects edits. The 4 channel panels render untouched in the dialog slot — no loss of functionality. - SharingPanel wires Slack/Telegram/WhatsApp/VoIP through ChannelConfigRow with per-channel status derivations. VoIP (previously backend-only) now has its Sharing UI surface, gated on `voip_available`. - Distribution (public links, file sharing) keeps the collapsible disclosure — out of scope for the channel-dialog change. Frontend-only; no API changes. Verified: 3 SFCs compile (vue/compiler-sfc), design-token check passes, and Vite transforms all modules on the live dev server (HTTP 200). Related to Abilityai/trinity-enterprise#19 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…llapse) A closed ChannelConfigDialog should collapse to Teleport comment nodes, but under some dev-server HMR states its slotted panel rendered inline as a flex child of the channel row, squeezing the label (esp. WhatsApp, whose panel is the widest) to zero width. Gate the dialog with v-if="dialogOpen" in ChannelConfigRow so the closed dialog — and its slotted panel — never participates in the row's flex layout, and mount the panel on demand. Make the dialog's Escape handler bind immediately so it still works when mounted already-open. Related to Abilityai/trinity-enterprise#19 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| class="inline-block w-2 h-2 rounded-full" | ||
| :class="status.warn ? 'bg-status-warning-500' : 'bg-status-success-500'" | ||
| ></span> | ||
| <span class="text-gray-600 dark:text-gray-300 truncate">{{ status.label || 'Connected' }}</span> |
There was a problem hiding this comment.
[Medium] Status label won’t truncate — long labels overflow the row
This truncate span is a flex child without min-w-0, so it can’t shrink below its content width and a long status label (e.g. WhatsApp’s whatsapp:+14155238886) overflows the row instead of clipping. Same flexbox class of bug the dialog v-if fix addressed, but on the inner status line — latent until a channel actually connects.
| <span class="text-gray-600 dark:text-gray-300 truncate">{{ status.label || 'Connected' }}</span> | |
| <span class="text-gray-600 dark:text-gray-300 truncate min-w-0">{{ status.label || 'Connected' }}</span> |
Optional polish: add shrink-0 to the status dots (lines 11/16/23) and the “· setup needed” span (line 20) so they don’t squish when the label is long.
| <!-- Config dialog: mounted only while open so the closed dialog (and its | ||
| slotted panel) never participates in this row's flex layout. The | ||
| channel panel renders inside the modal, untouched. --> | ||
| <ChannelConfigDialog v-if="dialogOpen" :open="dialogOpen" :title="title" :icon="icon" @close="onDialogClose"> |
There was a problem hiding this comment.
[Low] Redundant triple-gating of the dialog
Now that the dialog is mounted only via v-if="dialogOpen", both :open="dialogOpen" here and ChannelConfigDialog’s internal v-if="open" are always true while mounted — dead weight. Consider either dropping this parent v-if (rely on the internal Teleport + v-if, the original approach) or dropping the open prop + internal v-if (rely purely on mount/unmount). All three together works but is confusing. Not a bug.
| @@ -0,0 +1,67 @@ | |||
| <template> | |||
| <Teleport to="body"> | |||
| <div v-if="open" class="fixed z-50 inset-0 overflow-y-auto" role="dialog" aria-modal="true" :aria-label="title"> | |||
There was a problem hiding this comment.
[Low] Modal a11y: no focus management or scroll lock
role="dialog" aria-modal="true" is set, but focus isn’t moved into the dialog on open, there’s no focus trap, and background scroll isn’t locked. This matches the existing ConfirmDialog.vue, so it’s not a regression — flagging for parity if a shared modal primitive is extracted later.
…log gating Addresses code-review findings on PR #1348: - [Medium] The connected-status label was a flex child without `min-w-0`, so a long label (e.g. WhatsApp `whatsapp:+14155238886`) overflowed the row instead of clipping. Add `min-w-0` to the label and `shrink-0` to the status dots and the "· setup needed" span. - [Low] Collapse the redundant triple-gating to a single mechanism: the dialog is mounted only via the parent `v-if="dialogOpen"`, so drop the now always-true `:open` prop and ChannelConfigDialog's internal `v-if="open"` (Escape binds for the component's lifetime via onMounted/onUnmounted). (Skipped the a11y note — focus-trap/scroll-lock would be new behavior beyond the existing ConfirmDialog parity; not a regression.) Related to Abilityai/trinity-enterprise#19 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Applied the review fixes in 304c1a1:
Verified: both SFCs compile ( |
Implements trinity-enterprise#19 (Access/Sharing redesign epic, trinity-enterprise#16). Frontend-only; no API changes.
Replaces #18's interim collapsible channel rows with the dialog pattern the issue calls for: the tab stays a clean summary; full config opens in a modal.
Changes
ChannelConfigDialog.vue— Teleport modal (backdrop + Esc close, scrollable body) matching theConfirmDialogidiom.ChannelConfigRow.vue— compact summary row: channel glyph, connected/off + brief status (Slack#channel, Telegram@bot, WhatsApp/VoIP number, VoIP "(disabled)"/setup-needed warnings), and a Configure/Manage button that opens the dialog. A lightweight status GET (sharedapiclient) refetches on dialog close so the row reflects edits.SharingPanel.vue— wires Slack / Telegram / WhatsApp / VoIP throughChannelConfigRowwith per-channel status derivations. The 4 existing panels render untouched inside the dialog slot (no loss of functionality). VoIP — previously backend-only — now has its Sharing UI surface (gated onvoip_available).Acceptance criteria
voip_available)Verification
vue/compiler-sfc;npm run check:tokenspasses.🤖 Generated with Claude Code