Speaker recognition web UI fixes#142
Conversation
WalkthroughThe PR introduces dynamic web UI port configuration during setup based on HTTPS mode (5175 for HTTPS, 5174 for HTTP) and refactors nginx configuration generation with SERVER_IP substitution. Additionally, it adds comprehensive dark mode theming support across the web UI with new theme context, CSS variables, and updated component styling. Changes
Sequence DiagramsequenceDiagram
participant User
participant ThemeContext
participant Components
participant DOM
User->>ThemeSwitcher: Click toggle button
ThemeSwitcher->>ThemeContext: Call toggleTheme()
ThemeContext->>DOM: Update data-theme attribute
DOM->>Components: Apply dark: CSS classes
Components->>User: Render with dark/light colors
sequenceDiagram
participant Setup Script
participant User Input
participant SSL Generation
participant Nginx Config
participant Output
Setup Script->>User Input: Prompt for HTTPS mode
alt HTTPS Mode
Setup Script->>User Input: Prompt for SERVER_IP
Setup Script->>SSL Generation: Generate certificates
SSL Generation->>Setup Script: Certificates ready
else HTTP Mode
Setup Script->>Setup Script: Skip SSL
end
Setup Script->>Nginx Config: Generate with SERVER_IP and WEB_UI_PORT_PLACEHOLDER
Nginx Config->>Setup Script: Substitute values
Setup Script->>Output: Display configuration summary
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~35 minutes
Areas requiring extra attention:
Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
@CodeRabbit review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
extras/speaker-recognition/webui/src/pages/Annotation.tsx (1)
195-210: Critical bug fix: Missing file property added.The addition of
file: audioData.fileat Line 201 fixes a critical issue where the processed audio object was missing the original file reference needed by the speaker identification service.
🧹 Nitpick comments (2)
extras/speaker-recognition/webui/src/components/SpeakerResultsDisplay.tsx (1)
265-269: Consider extending theming to the entire component.The empty state now uses semantic theme tokens (
text-primary,heading-sm,text-muted), which is good. However, the rest of the component (lines 107-332) still uses hardcoded Tailwind colors liketext-gray-500,text-blue-600,bg-gray-50, etc. This creates inconsistent theme support—the empty state will adapt to dark mode, but segments, stats, and other UI elements won't.If complete dark mode support is desired, consider applying semantic tokens throughout the component.
extras/speaker-recognition/webui/src/components/ThemeSwitcher.tsx (1)
10-10: Remove unnecessary empty className attributes.The empty
className=""attributes on the Moon and Sun icons serve no purpose and can be safely removed for cleaner code.Apply this diff:
- {isDark ? <Moon className="" /> : <Sun className="" />} + {isDark ? <Moon /> : <Sun />}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
extras/speaker-recognition/nginx.conf.template(1 hunks)extras/speaker-recognition/setup.sh(3 hunks)extras/speaker-recognition/webui/src/App.tsx(1 hunks)extras/speaker-recognition/webui/src/components/AudioRecordingControls.tsx(3 hunks)extras/speaker-recognition/webui/src/components/ConnectionStatus.tsx(1 hunks)extras/speaker-recognition/webui/src/components/FileUploader.tsx(3 hunks)extras/speaker-recognition/webui/src/components/ProcessingModeSelector.tsx(21 hunks)extras/speaker-recognition/webui/src/components/SpeakerResultsDisplay.tsx(1 hunks)extras/speaker-recognition/webui/src/components/ThemeSwitcher.tsx(1 hunks)extras/speaker-recognition/webui/src/components/UserSelector.tsx(4 hunks)extras/speaker-recognition/webui/src/components/layout/Layout.tsx(4 hunks)extras/speaker-recognition/webui/src/pages/Annotation.tsx(27 hunks)extras/speaker-recognition/webui/src/pages/AudioViewer.tsx(6 hunks)extras/speaker-recognition/webui/src/pages/Enrollment.tsx(11 hunks)extras/speaker-recognition/webui/src/pages/InferLive.tsx(7 hunks)extras/speaker-recognition/webui/src/pages/InferLiveSimplified.tsx(8 hunks)extras/speaker-recognition/webui/src/pages/Inference.tsx(9 hunks)extras/speaker-recognition/webui/src/pages/Speakers.tsx(20 hunks)extras/speaker-recognition/webui/src/styles/components.css(1 hunks)extras/speaker-recognition/webui/tailwind.config.js(1 hunks)
🔇 Additional comments (24)
extras/speaker-recognition/webui/tailwind.config.js (1)
3-3: LGTM! Correct dark mode configuration.The
darkMode: 'class'configuration enables class-based dark mode toggling, which aligns perfectly with the ThemeProvider and ThemeSwitcher implementation throughout the PR.extras/speaker-recognition/webui/src/components/ConnectionStatus.tsx (1)
105-105: LGTM! Appropriate dark mode color adjustment.The lighter gray shades with dark mode variants improve visibility in both themes.
extras/speaker-recognition/webui/src/components/FileUploader.tsx (1)
130-163: LGTM! Consistent use of design tokens.The refactor to semantic tokens (text-primary, text-muted, text-primary-disabled) improves consistency and maintainability across the theme system.
extras/speaker-recognition/webui/src/components/ProcessingModeSelector.tsx (1)
114-510: LGTM! Comprehensive design token adoption.The component has been systematically updated to use semantic design tokens (input-label, text-muted, text-primary, text-secondary, heading-sm) throughout, ensuring consistent theming without altering functionality.
extras/speaker-recognition/webui/src/components/UserSelector.tsx (1)
40-126: LGTM! Consistent token-based styling.All interactive elements (dropdown, forms, buttons) now use semantic design tokens, ensuring proper dark mode support and maintainability.
extras/speaker-recognition/webui/src/styles/components.css (1)
5-92: LGTM! Solid design system foundation.The CSS establishes a comprehensive token-based design system with:
- Root-level theme variables for light/dark modes
- Semantic utility classes (card, text-primary/secondary/muted, heading-, input-, btn-*)
- Consistent dark mode variants throughout
This provides excellent maintainability and ensures theme consistency across the application.
extras/speaker-recognition/webui/src/pages/Speakers.tsx (1)
256-610: LGTM! Comprehensive dark mode styling.The page has been thoroughly updated with dark mode variants across all UI elements (tables, cards, modals, buttons) using semantic design tokens consistently.
extras/speaker-recognition/nginx.conf.template (1)
48-50: LGTM! Dynamic port configuration enabled.The placeholder substitution allows the setup script to configure the web UI port dynamically based on HTTP/HTTPS mode, improving deployment flexibility.
extras/speaker-recognition/webui/src/App.tsx (1)
12-32: LGTM! Theme provider integration is correct.ThemeProvider correctly wraps the Router to provide theming context globally. The React Router future flags ensure compatibility with upcoming v7 features.
extras/speaker-recognition/webui/src/components/AudioRecordingControls.tsx (1)
132-221: LGTM! Theming updates are consistent.The component successfully adopts the new design tokens for dark mode support while preserving all existing functionality.
extras/speaker-recognition/webui/src/components/layout/Layout.tsx (1)
6-89: LGTM! Layout successfully integrates theme switcher and dark mode.The layout properly integrates the ThemeSwitcher component and applies dark mode styling consistently across header, navigation, and footer elements.
extras/speaker-recognition/webui/src/pages/AudioViewer.tsx (1)
185-295: LGTM! Comprehensive dark mode support added.AudioViewer consistently applies dark mode theming across all UI elements while maintaining existing functionality.
extras/speaker-recognition/webui/src/pages/InferLive.tsx (1)
163-295: LGTM! InferLive theming updates are complete and consistent.All UI elements properly support dark mode while preserving the real-time transcription and speaker identification functionality.
extras/speaker-recognition/webui/src/pages/Enrollment.tsx (1)
458-727: LGTM! Enrollment page fully supports dark mode.The quality indicators, recording controls, file uploads, and all UI elements properly support dark mode theming. The enrollment logic remains unchanged and functional.
extras/speaker-recognition/setup.sh (3)
144-156: LGTM! Clean port configuration logic.The dynamic port assignment based on HTTPS mode is well-implemented. The separation of concerns (determine ports → update .env) makes the flow easy to follow.
208-208: LGTM! Dynamic port in user message.Correctly displays the dynamically determined port value, ensuring users see the accurate Web Interface URL.
179-188: No issues found. The verification confirms thatnginx.conf.templatecontains both expected placeholders (TAILSCALE_IPat lines 55 and 144,WEB_UI_PORT_PLACEHOLDERat line 49), and the sed substitution logic in setup.sh correctly targets them.extras/speaker-recognition/webui/src/pages/InferLiveSimplified.tsx (3)
207-214: LGTM! Well-implemented dark mode for connection status.The icon color choices follow proper dark mode conventions, using lighter shades on dark backgrounds for good visibility.
329-331: LGTM! Button states properly handle dark mode.Both start and stop button states include appropriate hover transitions for dark mode.
344-393: LGTM! Comprehensive dark mode support for transcripts.The transcript display has thorough dark mode styling with proper semantic colors for badges, borders, and text states. The visual hierarchy is maintained across both themes.
extras/speaker-recognition/webui/src/pages/Inference.tsx (4)
89-92: LGTM! Consistent design token usage.The header and user prompt sections properly use the semantic design tokens, maintaining consistency with other pages in the PR.
Also applies to: 100-103
167-181: LGTM! Audio quality display with proper semantic colors.The quality level indicators use appropriate semantic colors (green for excellent, red for poor) with proper dark mode variants. The visual feedback is clear in both themes.
209-214: LGTM! Processing progress with dark mode support.The progress indicator maintains proper contrast and visibility in both light and dark modes.
226-276: LGTM! Comprehensive dark mode for results history.The results history section has thorough styling with proper status badge colors, hover states, and visual hierarchy maintained across both themes. The interactive elements (selection, hover, export) are well-defined.
| <p className="text-primary">{new Date(selectedSpeaker.created_at).toLocaleString()}</p> | ||
| </div> | ||
| <div> | ||
| <label className="block text-sm font-medium text-gray-500">Last Updated</label> | ||
| <p className="text-gray-900 dark:text-gray-100">{new Date(selectedSpeaker.updated_at).toLocaleString()}</p> | ||
| <label className="block text-sm font-medium text-muted">Last Updated</label> | ||
| <p className="text-primary">{new Date(selectedSpeaker.updated_at).toLocaleString()}</p> | ||
| </div> | ||
| <div> | ||
| <label className="block text-sm font-medium text-gray-500">Last Enrollment</label> | ||
| <p className="text-gray-900 dark:text-gray-100">{new Date(selectedSpeaker.last_enrollment).toLocaleString()}</p> | ||
| <label className="block text-sm font-medium text-muted">Last Enrollment</label> | ||
| <p className="text-primary">{new Date(selectedSpeaker.last_enrollment).toLocaleString()}</p> |
There was a problem hiding this comment.
Add null safety for optional date fields in the modal.
Lines 613, 617, and 621 call new Date() on potentially undefined values (created_at, updated_at, last_enrollment). If these fields are undefined, this will result in new Date(undefined) which creates an Invalid Date.
Apply this diff to add proper null checks:
<div>
<label className="block text-sm font-medium text-muted">Created</label>
- <p className="text-primary">{new Date(selectedSpeaker.created_at).toLocaleString()}</p>
+ <p className="text-primary">{selectedSpeaker.created_at ? new Date(selectedSpeaker.created_at).toLocaleString() : 'N/A'}</p>
</div>
<div>
<label className="block text-sm font-medium text-muted">Last Updated</label>
- <p className="text-primary">{new Date(selectedSpeaker.updated_at).toLocaleString()}</p>
+ <p className="text-primary">{selectedSpeaker.updated_at ? new Date(selectedSpeaker.updated_at).toLocaleString() : 'N/A'}</p>
</div>
<div>
<label className="block text-sm font-medium text-muted">Last Enrollment</label>
- <p className="text-primary">{new Date(selectedSpeaker.last_enrollment).toLocaleString()}</p>
+ <p className="text-primary">{selectedSpeaker.last_enrollment ? new Date(selectedSpeaker.last_enrollment).toLocaleString() : 'N/A'}</p>
</div>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <p className="text-primary">{new Date(selectedSpeaker.created_at).toLocaleString()}</p> | |
| </div> | |
| <div> | |
| <label className="block text-sm font-medium text-gray-500">Last Updated</label> | |
| <p className="text-gray-900 dark:text-gray-100">{new Date(selectedSpeaker.updated_at).toLocaleString()}</p> | |
| <label className="block text-sm font-medium text-muted">Last Updated</label> | |
| <p className="text-primary">{new Date(selectedSpeaker.updated_at).toLocaleString()}</p> | |
| </div> | |
| <div> | |
| <label className="block text-sm font-medium text-gray-500">Last Enrollment</label> | |
| <p className="text-gray-900 dark:text-gray-100">{new Date(selectedSpeaker.last_enrollment).toLocaleString()}</p> | |
| <label className="block text-sm font-medium text-muted">Last Enrollment</label> | |
| <p className="text-primary">{new Date(selectedSpeaker.last_enrollment).toLocaleString()}</p> | |
| <p className="text-primary">{selectedSpeaker.created_at ? new Date(selectedSpeaker.created_at).toLocaleString() : 'N/A'}</p> | |
| </div> | |
| <div> | |
| <label className="block text-sm font-medium text-muted">Last Updated</label> | |
| <p className="text-primary">{selectedSpeaker.updated_at ? new Date(selectedSpeaker.updated_at).toLocaleString() : 'N/A'}</p> | |
| </div> | |
| <div> | |
| <label className="block text-sm font-medium text-muted">Last Enrollment</label> | |
| <p className="text-primary">{selectedSpeaker.last_enrollment ? new Date(selectedSpeaker.last_enrollment).toLocaleString() : 'N/A'}</p> |
🤖 Prompt for AI Agents
In extras/speaker-recognition/webui/src/pages/Speakers.tsx around lines 613 to
621, the modal renders dates by calling new Date(...) on possibly undefined
fields (created_at, updated_at, last_enrollment); update each date render to
guard against undefined by using optional chaining and a conditional fallback
(e.g. selectedSpeaker?.created_at ? new
Date(selectedSpeaker.created_at).toLocaleString() : '—') so Invalid Date is
never shown and undefined values render a clear placeholder.
Summary by CodeRabbit
New Features
Chores