11// Copyright (C) 2025 Intel Corporation
22// SPDX-License-Identifier: Apache-2.0
33
4- import { FormEvent , useState } from 'react' ;
4+ import { useState } from 'react' ;
55
6- import { Button , ButtonGroup , Divider , Flex , Form , Grid , Loading , NumberField , Text , TextField , View } from '@geti/ui' ;
7- import { isEqual } from 'lodash-es' ;
6+ import { Button , ButtonGroup , Divider , Flex , Loading , NumberField , Text , TextField } from '@geti/ui' ;
87
9- import { $api } from '../../api/client' ;
108import {
119 SchemaDisconnectedSourceConfig ,
1210 SchemaImagesFolderSourceConfig ,
1311 SchemaIpCameraSourceConfig ,
1412 SchemaVideoFileSourceConfig ,
1513 SchemaWebcamSourceConfig ,
16- } from '../../api/openapi-spec' ;
17- import { RadioDisclosure } from '../../components/radio-disclosure-group/radio-disclosure-group' ;
18- import { Stream } from '../../features/inference/stream/stream' ;
19- import { useWebRTCConnection } from '../../features/inference/stream/web-rtc-connection-provider' ;
20- import { ReactComponent as Image } from './../../assets/icons/images-folder.svg' ;
21- import { ReactComponent as IpCamera } from './../../assets/icons/ip-camera.svg' ;
22- import { ReactComponent as Video } from './../../assets/icons/video-file.svg' ;
23- import { ReactComponent as Webcam } from './../../assets/icons/webcam.svg' ;
14+ } from '../../../api/openapi-spec' ;
15+ import { ReactComponent as CameraOff } from '../../../assets/icons/camera-off.svg' ;
16+ import { ReactComponent as Image } from '../../../assets/icons/images-folder.svg' ;
17+ import { ReactComponent as IpCamera } from '../../../assets/icons/ip-camera.svg' ;
18+ import { ReactComponent as Video } from '../../../assets/icons/video-file.svg' ;
19+ import { ReactComponent as Webcam } from '../../../assets/icons/webcam.svg' ;
20+ import { RadioDisclosure } from '../../../components/radio-disclosure-group/radio-disclosure-group' ;
21+ import { Stream } from '../stream/stream' ;
22+ import { useWebRTCConnection } from '../stream/web-rtc-connection-provider' ;
2423
25- // TODO: create a new module scss for this file
26- const classes = { canvasContainer : '' } ;
24+ import classes from '../inference.module.scss' ;
2725
2826type SourceConfig =
2927 | SchemaDisconnectedSourceConfig
@@ -68,35 +66,42 @@ const DEFAULT_SOURCE_FORMS: SourceFormRecord = {
6866 } ,
6967} ;
7068
71- const ConnectionPreview = ( ) => {
69+ export const ConnectionPreview = ( ) => {
7270 const [ size , setSize ] = useState ( { height : 608 , width : 892 } ) ;
7371 const { status } = useWebRTCConnection ( ) ;
7472
7573 return (
76- < >
74+ < Flex
75+ alignItems = { 'center' }
76+ justifyContent = { 'center' }
77+ width = { '100%' }
78+ height = { 'size-3000' }
79+ UNSAFE_style = { {
80+ backgroundColor : 'var(--spectrum-global-color-gray-200)' ,
81+ } }
82+ >
7783 { status === 'idle' && (
7884 < div className = { classes . canvasContainer } >
79- < View backgroundColor = { 'gray-200' } width = '100%' height = '100%' >
80- < Flex alignItems = { 'center' } justifyContent = { 'center' } height = '100%' >
81- < Text
82- UNSAFE_style = { {
83- color : 'var(--spectrum-global-color-gray-800)' ,
84- } }
85- >
86- Save camera settings to establish a connection and view the preview.
87- </ Text >
88- </ Flex >
89- </ View >
85+ < Flex direction = { 'column' } justifyContent = { 'center' } alignItems = { 'center' } gap = { 'size-200' } >
86+ < CameraOff />
87+ < Text
88+ UNSAFE_style = { {
89+ color : 'var(--spectrum-global-color-gray-700)' ,
90+ fontSize : 'var(--spectrum-global-dimension-font-size-75)' ,
91+ lineHeight : 'var(--spectrum-global-dimension-size-225)' ,
92+ } }
93+ >
94+ Configure your input source
95+ </ Text >
96+ </ Flex >
9097 </ div >
9198 ) }
9299
93100 { status === 'connecting' && (
94101 < div className = { classes . canvasContainer } >
95- < View backgroundColor = { 'gray-200' } width = '100%' height = '100%' >
96- < Flex alignItems = { 'center' } justifyContent = { 'center' } height = '100%' >
97- < Loading mode = 'inline' />
98- </ Flex >
99- </ View >
102+ < Flex alignItems = { 'center' } justifyContent = { 'center' } height = '100%' >
103+ < Loading mode = 'inline' />
104+ </ Flex >
100105 </ div >
101106 ) }
102107
@@ -105,7 +110,7 @@ const ConnectionPreview = () => {
105110 < Stream size = { size } setSize = { setSize } />
106111 </ div >
107112 ) }
108- </ >
113+ </ Flex >
109114 ) ;
110115} ;
111116
@@ -208,14 +213,21 @@ const ConfigureSource = ({
208213
209214const Label = ( { item } : { item : { name : string ; source_type : SourceType } } ) => {
210215 return (
211- < Flex alignItems = 'center' gap = 'size-200' >
216+ < Flex alignItems = 'center' gap = 'size-200' margin = { 0 } >
212217 < Flex alignItems = 'center' justifyContent = { 'center' } >
213218 { item . source_type === 'video_file' && < Video width = '32px' /> }
214219 { item . source_type === 'webcam' && < Webcam width = '32px' /> }
215220 { item . source_type === 'ip_camera' && < IpCamera width = '32px' /> }
216221 { item . source_type === 'images_folder' && < Image width = '32px' /> }
217222 </ Flex >
218- { item . name }
223+ < Text
224+ UNSAFE_style = { {
225+ fontSize : 'var(--spectrum-global-dimension-font-size-100)' ,
226+ lineHeight : 'var(--spectrum-global-dimension-size-300)' ,
227+ } }
228+ >
229+ { item . name }
230+ </ Text >
219231 </ Flex >
220232 ) ;
221233} ;
@@ -229,59 +241,29 @@ const DEFAULT_SOURCE_ITEMS = [
229241] satisfies Array < { source_type : SourceType ; name : string } > ;
230242
231243export const Source = ( ) => {
232- const { status } = useWebRTCConnection ( ) ;
233- const sources = $api . useSuspenseQuery ( 'get' , '/api/sources' ) ;
234- const sourceMutation = $api . useMutation ( 'post' , '/api/sources' , {
235- onSuccess : async ( ) => {
236- // TODO: Enable this once WebRTC connection works properly
237- // if (status !== 'connected') {
238- // await start();
239- // }
240- } ,
241- } ) ;
242-
243- const [ selectedSourceType , setSelectedSourceType ] = useState < SourceType > (
244- sources . data [ 0 ] ?. source_type ?? DEFAULT_SOURCE_ITEMS [ 0 ] . source_type
245- ) ;
244+ const [ selectedSourceType , setSelectedSourceType ] = useState < SourceType > ( DEFAULT_SOURCE_ITEMS [ 0 ] . source_type ) ;
246245 const [ forms , setForms ] = useState < SourceFormRecord > ( ( ) => {
247246 return DEFAULT_SOURCE_FORMS ;
248247 } ) ;
249248
250- const submitIsDisabled = isEqual ( forms [ selectedSourceType ] , sources . data ) ;
251- const onSubmit = ( event : FormEvent < HTMLFormElement > ) => {
252- event . preventDefault ( ) ;
253-
254- sourceMutation . mutateAsync ( { body : forms [ selectedSourceType ] } ) ;
249+ const handleSaveSource = ( sourceType : SourceType ) => {
250+ setSelectedSourceType ( sourceType ) ;
255251 } ;
256252
253+ const handleSubmit = ( ) => { } ;
254+
257255 return (
258- < Grid
259- areas = { [ 'text text' , 'form canvas' , 'divider divider' , 'buttons buttons' ] }
260- columns = { [ 'auto' , '1fr' ] }
261- gap = 'size-200'
262- >
263- < View
264- gridArea = 'text'
265- UNSAFE_style = { {
266- color : 'var(--spectrum-global-color-gray-700)' ,
267- textAlign : 'center' ,
268- } }
269- >
270- < Text >
271- Please configure the source for your system. Select the appropriate source type and provide the
272- necessary connection details below.
273- </ Text >
274- </ View >
275- < Form gridArea = { 'form' } onSubmit = { onSubmit } >
276- < RadioDisclosure
277- ariaLabel = { 'Select your source' }
278- value = { selectedSourceType }
279- setValue = { setSelectedSourceType }
280- items = { DEFAULT_SOURCE_ITEMS . map ( ( item ) => {
281- return {
282- value : item . source_type ,
283- label : < Label item = { item } /> ,
284- content : (
256+ < Flex direction = { 'column' } gap = { 'size-200' } >
257+ < RadioDisclosure
258+ ariaLabel = { 'Select your source' }
259+ value = { selectedSourceType }
260+ setValue = { setSelectedSourceType }
261+ items = { DEFAULT_SOURCE_ITEMS . map ( ( item ) => {
262+ return {
263+ value : item . source_type ,
264+ label : < Label item = { item } /> ,
265+ content : (
266+ < Flex direction = { 'column' } gap = { 'size-200' } >
285267 < ConfigureSource
286268 source = { forms [ item . source_type ] }
287269 setSource = { ( newSource ) => {
@@ -290,34 +272,24 @@ export const Source = () => {
290272 } ) ;
291273 } }
292274 />
293- ) ,
294- } ;
295- } ) }
296- />
275+ < ButtonGroup >
276+ < Button variant = { 'accent' } onPress = { ( ) => handleSaveSource ( item . source_type ) } >
277+ Save & connect
278+ </ Button >
279+ </ ButtonGroup >
280+ </ Flex >
281+ ) ,
282+ } ;
283+ } ) }
284+ />
297285
298- < ButtonGroup marginTop = { 'size-400' } marginX = 'size-200' >
299- < Button
300- type = 'submit'
301- variant = 'accent'
302- isPending = { sourceMutation . isPending }
303- // TODO: disable only if there are no changes
304- isDisabled = { submitIsDisabled && status === 'connected' }
305- >
306- Save
307- </ Button >
308- </ ButtonGroup >
309- </ Form >
310- < View gridArea = { 'canvas' } height = { '100%' } UNSAFE_style = { { backgroundColor : 'rgba(0, 0, 0, 0.20)' } } >
311- < ConnectionPreview />
312- </ View >
313- < View gridArea = { 'divider' } paddingY = 'size-400' >
314- < Divider size = 'S' orientation = 'horizontal' />
315- </ View >
316- < View gridArea = 'buttons' >
317- < ButtonGroup align = { 'end' } width = { '100%' } >
318- < Button variant = 'accent' > Next</ Button >
319- </ ButtonGroup >
320- </ View >
321- </ Grid >
286+ < Divider size = { 'S' } />
287+
288+ < ButtonGroup alignSelf = { 'end' } >
289+ < Button variant = { 'primary' } onPress = { handleSubmit } >
290+ Submit
291+ </ Button >
292+ </ ButtonGroup >
293+ </ Flex >
322294 ) ;
323295} ;
0 commit comments