You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
6.2 KiB
203 lines
6.2 KiB
import { |
|
Checkbox, |
|
checkboxClasses, |
|
FormControl, |
|
FormControlLabel, |
|
FormGroup, |
|
Grid, |
|
styled, |
|
} from '@mui/material'; |
|
import { |
|
Sync as SyncIcon, |
|
SyncDisabled as SyncDisabledIcon, |
|
} from '@mui/icons-material'; |
|
import { ReactElement, useMemo } from 'react'; |
|
import { v4 as uuidv4 } from 'uuid'; |
|
|
|
import { BLUE, RED, TEXT } from '../../lib/consts/DEFAULT_THEME'; |
|
import { UPLOAD_FILE_TYPES_ARRAY } from '../../lib/consts/UPLOAD_FILE_TYPES'; |
|
|
|
import List from '../List'; |
|
import MenuItem from '../MenuItem'; |
|
import OutlinedInput from '../OutlinedInput'; |
|
import OutlinedInputLabel from '../OutlinedInputLabel'; |
|
import { ExpandablePanel, InnerPanelBody } from '../Panels'; |
|
import Select from '../Select'; |
|
|
|
type FileInfoProps = Pick<FileDetailMetadata, 'fileName' | 'fileLocations'> & |
|
Partial<Pick<FileDetailMetadata, 'fileType'>> & { |
|
isReadonly?: boolean; |
|
onChange?: FileInfoChangeHandler; |
|
}; |
|
|
|
const FILE_INFO_DEFAULT_PROPS: Partial<FileInfoProps> = { |
|
isReadonly: undefined, |
|
onChange: undefined, |
|
}; |
|
|
|
const FileLocationActiveCheckbox = styled(Checkbox)({ |
|
color: RED, |
|
|
|
[`&.${checkboxClasses.checked}`]: { |
|
color: BLUE, |
|
}, |
|
}); |
|
|
|
const FileInfo = ( |
|
{ |
|
fileName, |
|
fileType, |
|
fileLocations, |
|
isReadonly, |
|
onChange, |
|
}: FileInfoProps = FILE_INFO_DEFAULT_PROPS as FileInfoProps, |
|
): JSX.Element => { |
|
const idExtension = uuidv4(); |
|
|
|
const fileNameElementId = `file-name-${idExtension}`; |
|
const fileNameElementLabel = 'File name'; |
|
|
|
const fileTypeElementId = `file-type-${idExtension}`; |
|
const fileTypeElementLabel = 'File type'; |
|
|
|
const anFileLocations = useMemo( |
|
() => |
|
fileLocations.reduce< |
|
Record< |
|
string, |
|
Pick<FileLocation, 'anvilDescription' | 'anvilName' | 'anvilUUID'> & { |
|
flocs: FileLocation[]; |
|
} |
|
> |
|
>((previous, fileLocation) => { |
|
const { anvilDescription, anvilName, anvilUUID } = fileLocation; |
|
|
|
if (!previous[anvilUUID]) { |
|
previous[anvilUUID] = { |
|
anvilDescription, |
|
anvilName, |
|
anvilUUID, |
|
flocs: [], |
|
}; |
|
} |
|
|
|
previous[anvilUUID].flocs.push(fileLocation); |
|
|
|
return previous; |
|
}, {}), |
|
[fileLocations], |
|
); |
|
|
|
return ( |
|
<FormGroup sx={{ '> :not(:first-child)': { marginTop: '1em' } }}> |
|
<FormControl> |
|
<OutlinedInputLabel htmlFor={fileNameElementId}> |
|
{fileNameElementLabel} |
|
</OutlinedInputLabel> |
|
<OutlinedInput |
|
defaultValue={fileName} |
|
disabled={isReadonly} |
|
id={fileNameElementId} |
|
label={fileNameElementLabel} |
|
onChange={({ target: { value } }) => { |
|
onChange?.call(null, { |
|
fileName: value === fileName ? undefined : value, |
|
}); |
|
}} |
|
/> |
|
</FormControl> |
|
{fileType && ( |
|
<FormControl> |
|
<OutlinedInputLabel htmlFor={fileTypeElementId}> |
|
{fileTypeElementLabel} |
|
</OutlinedInputLabel> |
|
<Select |
|
defaultValue={fileType} |
|
disabled={isReadonly} |
|
id={fileTypeElementId} |
|
input={<OutlinedInput label={fileTypeElementLabel} />} |
|
onChange={({ target: { value } }) => { |
|
onChange?.call(null, { |
|
fileType: value === fileType ? undefined : (value as FileType), |
|
}); |
|
}} |
|
> |
|
{UPLOAD_FILE_TYPES_ARRAY.map( |
|
([fileTypeKey, [, fileTypeDisplayString]]) => ( |
|
<MenuItem key={fileTypeKey} value={fileTypeKey}> |
|
{fileTypeDisplayString} |
|
</MenuItem> |
|
), |
|
)} |
|
</Select> |
|
</FormControl> |
|
)} |
|
<List |
|
listItems={anFileLocations} |
|
listProps={{ dense: true, disablePadding: true }} |
|
renderListItem={(anvilUUID, { anvilDescription, anvilName, flocs }) => ( |
|
<ExpandablePanel |
|
header={`${anvilName}: ${anvilDescription}`} |
|
panelProps={{ padding: 0, width: '100%' }} |
|
> |
|
<InnerPanelBody> |
|
<Grid |
|
columns={{ xs: 1, sm: 2, md: 3, lg: 4, xl: 5 }} |
|
columnSpacing="1em" |
|
container |
|
direction="row" |
|
> |
|
{flocs.map<ReactElement>( |
|
({ |
|
fileLocationUUID: flocUUID, |
|
hostName, |
|
hostUUID, |
|
isFileLocationActive, |
|
}) => ( |
|
<Grid item key={`floc-${anvilUUID}-${hostUUID}`} xs={1}> |
|
<FormControlLabel |
|
control={ |
|
<FileLocationActiveCheckbox |
|
checkedIcon={<SyncIcon />} |
|
defaultChecked={isFileLocationActive} |
|
disabled={isReadonly} |
|
edge="start" |
|
icon={<SyncDisabledIcon />} |
|
onChange={({ target: { checked } }) => { |
|
onChange?.call( |
|
null, |
|
{ |
|
isFileLocationActive: |
|
checked === isFileLocationActive |
|
? undefined |
|
: checked, |
|
}, |
|
{ |
|
fileLocationIndex: fileLocations.findIndex( |
|
({ fileLocationUUID }) => |
|
flocUUID === fileLocationUUID, |
|
), |
|
}, |
|
); |
|
}} |
|
/> |
|
} |
|
label={hostName} |
|
sx={{ color: TEXT }} |
|
value={`${hostUUID}-sync`} |
|
/> |
|
</Grid> |
|
), |
|
)} |
|
</Grid> |
|
</InnerPanelBody> |
|
</ExpandablePanel> |
|
)} |
|
/> |
|
</FormGroup> |
|
); |
|
}; |
|
|
|
FileInfo.defaultProps = FILE_INFO_DEFAULT_PROPS; |
|
|
|
export default FileInfo;
|
|
|