Skip to content

feat(ui): move channel config into dialogs + VoIP surface (#19)#1348

Open
dolho wants to merge 3 commits into
feature/18-reframe-sharing-external-clientsfrom
feature/19-channel-config-dialogs
Open

feat(ui): move channel config into dialogs + VoIP surface (#19)#1348
dolho wants to merge 3 commits into
feature/18-reframe-sharing-external-clientsfrom
feature/19-channel-config-dialogs

Conversation

@dolho

@dolho dolho commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Implements trinity-enterprise#19 (Access/Sharing redesign epic, trinity-enterprise#16). Frontend-only; no API changes.

⛓️ Stacked on #1347 (#18) — base is feature/18-reframe-sharing-external-clients so the diff is #19-only. Retarget to dev once #1347 merges.

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 the ConfirmDialog idiom.
  • 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 (shared api client) refetches on dialog close so the row reflects edits.
  • SharingPanel.vue — wires Slack / Telegram / WhatsApp / VoIP through ChannelConfigRow with 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 on voip_available).
  • Distribution (public links, file sharing) keeps the collapsible disclosure — outside this issue's scope.

Acceptance criteria

  • Slack/Telegram/WhatsApp panels rendered inside dialogs, not inline
  • Each channel shows a summary row (connected/off + brief status) with a Configure button opening its dialog
  • VoIP gets a UI surface here (gated on voip_available)
  • No loss of existing channel functionality (panels reused as-is in the dialog)

Verification

  • 3 SFCs compile via vue/compiler-sfc; npm run check:tokens passes.
  • Vite transforms all three modules on the live local dev server (HTTP 200) — verified against the running instance on this branch.

🤖 Generated with Claude Code

dolho and others added 2 commits June 25, 2026 12:40
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>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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.

Suggested change
<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">

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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">

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[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>
@dolho

dolho commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

Applied the review fixes in 304c1a1:

  • [Medium] Status label now truncates — min-w-0 on the label + shrink-0 on the dots and "· setup needed" span, so a long connected label (e.g. whatsapp:+14155238886) clips instead of overflowing the row.
  • [Low] Collapsed the redundant triple-gating to a single mechanism: the dialog mounts only via the parent v-if="dialogOpen"; dropped the always-true :open prop and ChannelConfigDialog's internal v-if="open" (Escape now binds for the component lifetime via onMounted/onUnmounted).
  • [Low — a11y] Left as-is: focus-trap/scroll-lock would be new behavior beyond the existing ConfirmDialog parity (not a regression).

Verified: both SFCs compile (vue/compiler-sfc), check:tokens passes, Vite serves the updated modules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant