1111 * Design: Matches RecordingQuickControl / OSDToggle pattern.
1212 */
1313
14- import React , { useState } from 'react' ;
14+ import React , { useState , useEffect } from 'react' ;
1515import {
1616 Box , Chip , Select , MenuItem , FormControl , InputLabel , IconButton ,
1717 Typography , Tooltip , CircularProgress , Button ,
18+ Dialog , DialogTitle , DialogContent , DialogActions ,
1819} from '@mui/material' ;
1920import SmartToyIcon from '@mui/icons-material/SmartToy' ;
2021import SwapHorizIcon from '@mui/icons-material/SwapHoriz' ;
@@ -23,14 +24,16 @@ import OpenInNewIcon from '@mui/icons-material/OpenInNew';
2324import MemoryIcon from '@mui/icons-material/Memory' ;
2425import KeyboardIcon from '@mui/icons-material/Keyboard' ;
2526import { Link } from 'react-router-dom' ;
26- import { useActiveModel , useModels , useSwitchModel } from '../hooks/useModels' ;
27+ import { useActiveModel , useModels , useSwitchModel , useModelLabels } from '../hooks/useModels' ;
2728
2829const ModelQuickControl = ( ) => {
2930 const { activeModel, runtime, loading : activeLoading } = useActiveModel ( 5000 ) ;
3031 const { models, loading : modelsLoading } = useModels ( 15000 ) ;
3132 const { switchModel, switching } = useSwitchModel ( ) ;
33+ const { fetchLabels, loading : labelsLoading } = useModelLabels ( ) ;
3234 const [ selectedModelPath , setSelectedModelPath ] = useState ( '' ) ;
3335 const [ selectedDevice , setSelectedDevice ] = useState ( 'auto' ) ;
36+ const [ labelsDialog , setLabelsDialog ] = useState ( { open : false , labels : [ ] , modelName : '' } ) ;
3437
3538 // activeModel is the full active_model_summary object from /api/models/active
3639 const modelName = runtime ?. model_name || activeModel ?. model_name || 'None' ;
@@ -44,10 +47,26 @@ const ModelQuickControl = () => {
4447
4548 const modelList = models ? Object . entries ( models ) : [ ] ;
4649
50+ // Pre-select the active model in the dropdown when it changes
51+ const activeModelPath = activeModel ?. model_path || '' ;
52+ useEffect ( ( ) => {
53+ if ( activeModelPath ) {
54+ setSelectedModelPath ( activeModelPath ) ;
55+ }
56+ } , [ activeModelPath ] ) ;
57+
4758 const handleSwitch = async ( ) => {
4859 if ( ! selectedModelPath ) return ;
4960 await switchModel ( selectedModelPath , selectedDevice ) ;
50- setSelectedModelPath ( '' ) ;
61+ } ;
62+
63+ const handleViewLabels = async ( ) => {
64+ const modelId = activeModel ?. model_id ;
65+ if ( ! modelId ) return ;
66+ const result = await fetchLabels ( modelId ) ;
67+ if ( result . success ) {
68+ setLabelsDialog ( { open : true , labels : result . labels , modelName : modelName } ) ;
69+ }
5170 } ;
5271
5372 if ( activeLoading ) {
@@ -110,9 +129,20 @@ const ModelQuickControl = () => {
110129 < Typography variant = "caption" color = "text.secondary" sx = { { fontSize : 10 } } >
111130 Task: < b > { task } </ b >
112131 </ Typography >
113- < Typography variant = "caption" color = "text.secondary" sx = { { fontSize : 10 } } >
114- Classes: < b > { numLabels } </ b >
115- </ Typography >
132+ < Tooltip title = { hasModel ? 'Click to view class labels' : '' } >
133+ < Typography
134+ variant = "caption"
135+ color = { hasModel ? 'primary' : 'text.secondary' }
136+ onClick = { hasModel ? handleViewLabels : undefined }
137+ sx = { {
138+ fontSize : 10 ,
139+ cursor : hasModel ? 'pointer' : 'default' ,
140+ '&:hover' : hasModel ? { textDecoration : 'underline' } : { } ,
141+ } }
142+ >
143+ Classes: < b > { labelsLoading ? '...' : numLabels } </ b >
144+ </ Typography >
145+ </ Tooltip >
116146 </ Box >
117147
118148 { /* Quick Switch Row */ }
@@ -184,6 +214,37 @@ const ModelQuickControl = () => {
184214 </ Typography >
185215 </ Tooltip >
186216 </ Box >
217+
218+ { /* Labels Dialog */ }
219+ < Dialog
220+ open = { labelsDialog . open }
221+ onClose = { ( ) => setLabelsDialog ( { open : false , labels : [ ] , modelName : '' } ) }
222+ maxWidth = "sm"
223+ fullWidth
224+ >
225+ < DialogTitle > Labels: { labelsDialog . modelName } </ DialogTitle >
226+ < DialogContent dividers >
227+ { labelsDialog . labels . length === 0 ? (
228+ < Typography color = "text.secondary" > No labels available.</ Typography >
229+ ) : (
230+ < Box sx = { { display : 'flex' , flexWrap : 'wrap' , gap : 0.5 } } >
231+ { labelsDialog . labels . map ( ( item , idx ) => (
232+ < Chip
233+ key = { idx }
234+ label = { typeof item === 'object' ? `${ item . class_id } : ${ item . label } ` : `${ idx } : ${ item } ` }
235+ size = "small"
236+ variant = "outlined"
237+ />
238+ ) ) }
239+ </ Box >
240+ ) }
241+ </ DialogContent >
242+ < DialogActions >
243+ < Button onClick = { ( ) => setLabelsDialog ( { open : false , labels : [ ] , modelName : '' } ) } >
244+ Close
245+ </ Button >
246+ </ DialogActions >
247+ </ Dialog >
187248 </ Box >
188249 ) ;
189250} ;
0 commit comments