Skip to content

feat: add per-participant admin mute/unmute toggle - #750

Merged
eyevinn-developer[bot] merged 1 commit into
mainfrom
frontend/676-admin-mute-toggle
Nov 5, 2026
Merged

eyevinn-developer[bot] merged 1 commit into
mainfrom
frontend/676-admin-mute-toggle

Conversation

@eyevinn-developer

Copy link
Copy Markdown
Contributor

Summary

Test plan

  • Tests pass (npm test)
  • TypeScript compiles (npm run typecheck)
  • Lint clean (npm run lint)
  • Join one SMB line from two+ browsers, open the admin panel, click a participant's mute button and confirm their input is silenced and the row shows the muted/unmute state in every connected client; click again to unmute and confirm it reverses.

What a human does next

Nothing to configure. To verify manually: join one SMB line from two+ browsers, open the admin panel, click a participant's mute button and confirm their input is silenced and the row shows the muted/unmute state in every connected client; click again to unmute and confirm it reverses (advisory — the target can still unmute locally, matching the merged self-mute model).

Closes #676

🤖 Generated with Claude Code

Make the admin-panel mute control functional: a per-participant
mute/unmute toggle that issues the existing SMB EndpointMessage
remote-mute directive (muteParticipant: 'mute' | 'unmute') plus the
#678 global mute-state broadcast, and reflects each participant's
current advisory admin-mute state from participantMuteState (#749).

- Extract a reusable setParticipantMute(endpointId, muted) send helper
  in production-line.tsx; refactor the existing confirm-modal mute path
  to use it.
- Replace the disabled mute placeholder in admin-panel.tsx with a state-
  reflecting toggle; kick stays a placeholder until #638.
- Extend admin-panel tests to cover mute, unmute and state reflection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

@eyevinn-pr-reviewer eyevinn-pr-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

Verdict: LGTM

Summary: A clean, well-scoped extension of the already-merged advisory mute model (#749) into a per-participant admin toggle. It correctly reuses the participantMuteState map, the UPDATE_PARTICIPANT_MUTE_STATE reducer action, and the existing data-channel send/broadcast pattern rather than reinventing them; the AdminPanel component is well tested. Two non-blocking warnings: the net-new setParticipantMute send-path logic is untested, and the panel toggle silently no-ops when the data channel is closed.

Blocking

None.

Warnings

  • src/components/ui/production-line/production-line.tsx:642-685 — The net-new behavior for #676 lives in setParticipantMute (the "unmute" payload branch, the parameterized broadcast with participantId: endpointId, and the false/"data channel not open" return path) and has no unit or integration test. admin-panel.test.tsx only asserts that the AdminPanel invokes the onToggleMute callback with the right arguments; it does not exercise the actual directive/broadcast JSON construction or the closed-channel branch. Consider extracting the message-construction logic into a pure helper (like data-channel-parser.ts on the receive side) so it can be unit tested, or add coverage for the send path.
  • src/components/ui/production-line/admin-panel.tsx:222 — The toggle calls onToggleMute(p.endpointId, !isMuted) and discards the boolean it returns. When the data channel is closed, setParticipantMute returns false, dispatches nothing, and logs internally — so an admin clicking mute/unmute in the panel gets a silent no-op with no UI feedback and no change to the button state. The sibling UserList/confirmation path surfaces this via setMuteError. The panel path should give equivalent feedback or at least not appear to succeed.

Suggestions

  • src/components/ui/production-line/admin-panel.tsx:84,224 — The SVG fill is hardcoded to #f96c6c (error red) in both states, and an unmuted participant renders the MicMuted (crossed-mic) icon as the "click to mute" affordance. Combined with the always-red fill it can read as "this participant is muted" even when they are not. Consider differentiating the icon fill by state.

Domain Note

This change affects data channel parsing and the advisory mute directive/broadcast lifecycle. The send path is consistent with the receive side (data-channel-parser.ts maps "unmute" → muted: false), so both mute and unmute round-trip correctly. Advisory (non-server-enforced) mute semantics match the merged self-mute model.


Reviewed by eyevinn-pr-reviewer via daily-backlog-pr Phase 3.

@eyevinn-developer
eyevinn-developer Bot merged commit 1009edc into main Nov 5, 2026
6 checks passed
@eyevinn-developer
eyevinn-developer Bot deleted the frontend/676-admin-mute-toggle branch November 5, 2026 12:48
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.

Admin panel: global mute/unmute button per participant (UI + data-channel directive)

0 participants