ProfileEditor.tsx
1 import { Button, Card, CardActions, CardContent, CardHeader } from '@mui/material'; 2 import Grid from '@mui/material/Grid2'; 3 import { Signal, useComputed, useSignal } from '@preact/signals-react'; 4 import { uuid } from 'ipmc-core'; 5 import { IConfigurationService, IConfigurationServiceSymbol, ILibrary, IProfile, isInternalProfile, isRemoteProfile } from 'ipmc-interfaces'; 6 import React from 'react'; 7 import { useService } from '../../context'; 8 import { useTranslation } from '../../hooks'; 9 import { FormList, SelectInput, TextInput } from '../atoms'; 10 import { LibraryEditor } from './LibraryEditor'; 11 12 export function ProfileEditor(props: { profile: IProfile, onCancel: () => void, onSave: () => void; }) { 13 const { profile, onCancel, onSave } = props; 14 const configService = useService<IConfigurationService>(IConfigurationServiceSymbol); 15 const _t = useTranslation(); 16 17 const name = useSignal<string>(profile.name); 18 const type = useSignal<'internal' | 'remote'>(profile.type ?? 'internal'); 19 const apiUrl = useSignal<string>(isRemoteProfile(profile) ? profile.url ?? '' : ''); 20 const swarmKey = useSignal<string>(isInternalProfile(profile) ? profile.swarmKey ?? '' : ''); 21 const port = useSignal<string>(isInternalProfile(profile) ? profile.port?.toString() ?? '' : ''); 22 const bootstrap = useSignal<Signal<string>[]>(isInternalProfile(profile) ? profile.bootstrap?.map(i => new Signal(i)) ?? [] : []); 23 const libraries = useSignal<Signal<ILibrary>[]>(profile.libraries.map(i => new Signal(i))); 24 25 function save() { 26 configService.setProfile(profile.id, { 27 ...(profile ?? {}), 28 name: name.value, 29 type: type.value, 30 ...(type.value === 'internal' ? { 31 swarmKey: swarmKey.value === '' ? undefined : swarmKey.value, 32 port: port.value === '' ? undefined : parseInt(port.value), 33 bootstrap: bootstrap.value.map(s => s.value), 34 } : { 35 apiUrl: apiUrl.value === '' ? undefined : apiUrl.value, 36 }), 37 libraries: libraries.value.map(l => l.value), 38 }); 39 onSave(); 40 } 41 42 return ( 43 <Card sx={{ maxHeight: '100%', overflow: 'auto' }}> 44 <CardHeader title={_t('EditProfile')} /> 45 <CardContent> 46 <Grid container spacing={2}> 47 <Grid size={8}> 48 <TextInput 49 label={_t('Name')} 50 value={name} 51 /> 52 </Grid> 53 <Grid size={4}> 54 <SelectInput 55 value={type} 56 label={_t('ProfileType')} 57 options={{ 58 'internal': _t('Internal'), 59 'remote': _t('Remote'), 60 }} 61 /> 62 </Grid> 63 {useComputed(() => type.value === 'internal' ? (<> 64 <Grid size={12}> 65 <TextInput 66 label={_t('SwarmKey')} 67 value={swarmKey} 68 key={'swarmKey'} 69 multiline={true} 70 rows={3} 71 /> 72 </Grid> 73 <Grid size={12}> 74 <TextInput 75 label={_t('Port')} 76 value={port} 77 key={'port'} 78 /> 79 </Grid> 80 <Grid size={12}> 81 <FormList 82 label={_t('Bootstrap')} 83 values={bootstrap} 84 renderControl={(item) => ( 85 <TextInput 86 value={item} 87 /> 88 )} 89 createItem={() => ''} 90 /> 91 </Grid> 92 </>) : (<> 93 <Grid size={12}> 94 <TextInput 95 label={_t('ApiUrl')} 96 value={apiUrl} 97 key={'apiUrl'} 98 /> 99 </Grid> 100 </>))} 101 <Grid size={12}> 102 <FormList 103 label={_t('Libraries')} 104 values={libraries} 105 renderControl={(item) => ( 106 <LibraryEditor 107 value={item} 108 /> 109 )} 110 createItem={() => ({ 111 id: uuid(), 112 upstream: '', 113 name: '', 114 type: 'movie', 115 } as ILibrary)} 116 /> 117 </Grid> 118 </Grid> 119 </CardContent> 120 <CardActions> 121 <Button onClick={() => onCancel()}>{_t('Cancel')}</Button> 122 <Button onClick={() => save()}>{_t('Save')}</Button> 123 </CardActions> 124 </Card> 125 ); 126 }