|
|
@ -1,4 +1,12 @@ |
|
|
|
import { FC, FormEventHandler, useMemo, useRef, useState } from 'react'; |
|
|
|
import { Box } from '@mui/material'; |
|
|
|
|
|
|
|
import { |
|
|
|
|
|
|
|
FC, |
|
|
|
|
|
|
|
FormEventHandler, |
|
|
|
|
|
|
|
ReactElement, |
|
|
|
|
|
|
|
useMemo, |
|
|
|
|
|
|
|
useRef, |
|
|
|
|
|
|
|
useState, |
|
|
|
|
|
|
|
} from 'react'; |
|
|
|
|
|
|
|
|
|
|
|
import API_BASE_URL from '../lib/consts/API_BASE_URL'; |
|
|
|
import API_BASE_URL from '../lib/consts/API_BASE_URL'; |
|
|
|
|
|
|
|
|
|
|
@ -13,9 +21,29 @@ import List from './List'; |
|
|
|
import { Panel, PanelHeader } from './Panels'; |
|
|
|
import { Panel, PanelHeader } from './Panels'; |
|
|
|
import periodicFetch from '../lib/fetchers/periodicFetch'; |
|
|
|
import periodicFetch from '../lib/fetchers/periodicFetch'; |
|
|
|
import Spinner from './Spinner'; |
|
|
|
import Spinner from './Spinner'; |
|
|
|
import { BodyText, HeaderText, InlineMonoText } from './Text'; |
|
|
|
import { |
|
|
|
|
|
|
|
BodyText, |
|
|
|
|
|
|
|
HeaderText, |
|
|
|
|
|
|
|
InlineMonoText, |
|
|
|
|
|
|
|
MonoText, |
|
|
|
|
|
|
|
SmallText, |
|
|
|
|
|
|
|
} from './Text'; |
|
|
|
import useIsFirstRender from '../hooks/useIsFirstRender'; |
|
|
|
import useIsFirstRender from '../hooks/useIsFirstRender'; |
|
|
|
import useProtectedState from '../hooks/useProtectedState'; |
|
|
|
import useProtectedState from '../hooks/useProtectedState'; |
|
|
|
|
|
|
|
import SensitiveText from './Text/SensitiveText'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type FormFenceParameterData = { |
|
|
|
|
|
|
|
fenceAgent: string; |
|
|
|
|
|
|
|
fenceName: string; |
|
|
|
|
|
|
|
parameterInputs: { |
|
|
|
|
|
|
|
[parameterInputId: string]: { |
|
|
|
|
|
|
|
isParameterSensitive: boolean; |
|
|
|
|
|
|
|
parameterId: string; |
|
|
|
|
|
|
|
parameterType: string; |
|
|
|
|
|
|
|
parameterValue: string; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const fenceParameterBooleanToString = (value: boolean) => (value ? '1' : '0'); |
|
|
|
const fenceParameterBooleanToString = (value: boolean) => (value ? '1' : '0'); |
|
|
|
|
|
|
|
|
|
|
@ -25,12 +53,7 @@ const getFormFenceParameters = ( |
|
|
|
) => { |
|
|
|
) => { |
|
|
|
const { elements } = target as HTMLFormElement; |
|
|
|
const { elements } = target as HTMLFormElement; |
|
|
|
|
|
|
|
|
|
|
|
return Object.values(elements).reduce<{ |
|
|
|
return Object.values(elements).reduce<FormFenceParameterData>( |
|
|
|
fenceAgent: string; |
|
|
|
|
|
|
|
parameters: { |
|
|
|
|
|
|
|
[parameterId: string]: { type: string; value: string }; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
}>( |
|
|
|
|
|
|
|
(previous, formElement) => { |
|
|
|
(previous, formElement) => { |
|
|
|
const { id: inputId } = formElement; |
|
|
|
const { id: inputId } = formElement; |
|
|
|
const reExtract = new RegExp(`^(fence[^-]+)${ID_SEPARATOR}([^\\s]+)$`); |
|
|
|
const reExtract = new RegExp(`^(fence[^-]+)${ID_SEPARATOR}([^\\s]+)$`); |
|
|
@ -42,7 +65,16 @@ const getFormFenceParameters = ( |
|
|
|
previous.fenceAgent = fenceId; |
|
|
|
previous.fenceAgent = fenceId; |
|
|
|
|
|
|
|
|
|
|
|
const inputElement = formElement as HTMLInputElement; |
|
|
|
const inputElement = formElement as HTMLInputElement; |
|
|
|
const { checked, value } = inputElement; |
|
|
|
const { |
|
|
|
|
|
|
|
checked, |
|
|
|
|
|
|
|
dataset: { sensitive: rawSensitive }, |
|
|
|
|
|
|
|
value, |
|
|
|
|
|
|
|
} = inputElement; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parameterId === 'name') { |
|
|
|
|
|
|
|
previous.fenceName = value; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const { |
|
|
|
const { |
|
|
|
[fenceId]: { |
|
|
|
[fenceId]: { |
|
|
|
parameters: { |
|
|
|
parameters: { |
|
|
@ -51,9 +83,11 @@ const getFormFenceParameters = ( |
|
|
|
}, |
|
|
|
}, |
|
|
|
} = fenceTemplate; |
|
|
|
} = fenceTemplate; |
|
|
|
|
|
|
|
|
|
|
|
previous.parameters[parameterId] = { |
|
|
|
previous.parameterInputs[inputId] = { |
|
|
|
type: parameterType, |
|
|
|
isParameterSensitive: rawSensitive === 'true', |
|
|
|
value: |
|
|
|
parameterId, |
|
|
|
|
|
|
|
parameterType, |
|
|
|
|
|
|
|
parameterValue: |
|
|
|
parameterType === 'boolean' |
|
|
|
parameterType === 'boolean' |
|
|
|
? fenceParameterBooleanToString(checked) |
|
|
|
? fenceParameterBooleanToString(checked) |
|
|
|
: value, |
|
|
|
: value, |
|
|
@ -62,14 +96,58 @@ const getFormFenceParameters = ( |
|
|
|
|
|
|
|
|
|
|
|
return previous; |
|
|
|
return previous; |
|
|
|
}, |
|
|
|
}, |
|
|
|
{ fenceAgent: '', parameters: {} }, |
|
|
|
{ fenceAgent: '', fenceName: '', parameterInputs: {} }, |
|
|
|
); |
|
|
|
); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const buildConfirmFenceParameters = ( |
|
|
|
|
|
|
|
parameterInputs: FormFenceParameterData['parameterInputs'], |
|
|
|
|
|
|
|
) => ( |
|
|
|
|
|
|
|
<List |
|
|
|
|
|
|
|
listItems={parameterInputs} |
|
|
|
|
|
|
|
listItemProps={{ sx: { padding: 0 } }} |
|
|
|
|
|
|
|
renderListItem={( |
|
|
|
|
|
|
|
parameterInputId, |
|
|
|
|
|
|
|
{ isParameterSensitive, parameterId, parameterValue }, |
|
|
|
|
|
|
|
) => { |
|
|
|
|
|
|
|
let textElement: ReactElement; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (parameterValue) { |
|
|
|
|
|
|
|
textElement = isParameterSensitive ? ( |
|
|
|
|
|
|
|
<SensitiveText monospaced>{parameterValue}</SensitiveText> |
|
|
|
|
|
|
|
) : ( |
|
|
|
|
|
|
|
<Box sx={{ maxWidth: '100%', overflowX: 'scroll' }}> |
|
|
|
|
|
|
|
<MonoText lineHeight={2.8} whiteSpace="nowrap"> |
|
|
|
|
|
|
|
{parameterValue} |
|
|
|
|
|
|
|
</MonoText> |
|
|
|
|
|
|
|
</Box> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
textElement = <SmallText>none</SmallText>; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
|
|
|
|
<FlexBox |
|
|
|
|
|
|
|
fullWidth |
|
|
|
|
|
|
|
growFirst |
|
|
|
|
|
|
|
height="2.8em" |
|
|
|
|
|
|
|
key={`confirm-${parameterInputId}`} |
|
|
|
|
|
|
|
maxWidth="100%" |
|
|
|
|
|
|
|
row |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
<BodyText>{parameterId}</BodyText> |
|
|
|
|
|
|
|
{textElement} |
|
|
|
|
|
|
|
</FlexBox> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
const ManageFencesPanel: FC = () => { |
|
|
|
const ManageFencesPanel: FC = () => { |
|
|
|
const isFirstRender = useIsFirstRender(); |
|
|
|
const isFirstRender = useIsFirstRender(); |
|
|
|
|
|
|
|
|
|
|
|
const confirmDialogRef = useRef<ConfirmDialogForwardedRefContent>({}); |
|
|
|
const confirmDialogRef = useRef<ConfirmDialogForwardedRefContent>({}); |
|
|
|
|
|
|
|
const formDialogRef = useRef<ConfirmDialogForwardedRefContent>({}); |
|
|
|
|
|
|
|
|
|
|
|
const [confirmDialogProps, setConfirmDialogProps] = |
|
|
|
const [confirmDialogProps, setConfirmDialogProps] = |
|
|
|
useState<ConfirmDialogProps>({ |
|
|
|
useState<ConfirmDialogProps>({ |
|
|
@ -77,6 +155,11 @@ const ManageFencesPanel: FC = () => { |
|
|
|
content: '', |
|
|
|
content: '', |
|
|
|
titleText: '', |
|
|
|
titleText: '', |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
const [formDialogProps, setFormDialogProps] = useState<ConfirmDialogProps>({ |
|
|
|
|
|
|
|
actionProceedText: '', |
|
|
|
|
|
|
|
content: '', |
|
|
|
|
|
|
|
titleText: '', |
|
|
|
|
|
|
|
}); |
|
|
|
const [fenceTemplate, setFenceTemplate] = useProtectedState< |
|
|
|
const [fenceTemplate, setFenceTemplate] = useProtectedState< |
|
|
|
APIFenceTemplate | undefined |
|
|
|
APIFenceTemplate | undefined |
|
|
|
>(undefined); |
|
|
|
>(undefined); |
|
|
@ -98,7 +181,7 @@ const ManageFencesPanel: FC = () => { |
|
|
|
header |
|
|
|
header |
|
|
|
listItems={fenceOverviews} |
|
|
|
listItems={fenceOverviews} |
|
|
|
onAdd={() => { |
|
|
|
onAdd={() => { |
|
|
|
setConfirmDialogProps({ |
|
|
|
setFormDialogProps({ |
|
|
|
actionProceedText: 'Add', |
|
|
|
actionProceedText: 'Add', |
|
|
|
content: <AddFenceInputGroup fenceTemplate={fenceTemplate} />, |
|
|
|
content: <AddFenceInputGroup fenceTemplate={fenceTemplate} />, |
|
|
|
onSubmitAppend: (event) => { |
|
|
|
onSubmitAppend: (event) => { |
|
|
@ -106,18 +189,34 @@ const ManageFencesPanel: FC = () => { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
getFormFenceParameters(fenceTemplate, event); |
|
|
|
const addData = getFormFenceParameters(fenceTemplate, event); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setConfirmDialogProps({ |
|
|
|
|
|
|
|
actionProceedText: 'Add', |
|
|
|
|
|
|
|
content: buildConfirmFenceParameters(addData.parameterInputs), |
|
|
|
|
|
|
|
titleText: ( |
|
|
|
|
|
|
|
<HeaderText> |
|
|
|
|
|
|
|
Add a{' '} |
|
|
|
|
|
|
|
<InlineMonoText fontSize="inherit"> |
|
|
|
|
|
|
|
{addData.fenceAgent} |
|
|
|
|
|
|
|
</InlineMonoText>{' '} |
|
|
|
|
|
|
|
fence device with the following parameters? |
|
|
|
|
|
|
|
</HeaderText> |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
confirmDialogRef.current.setOpen?.call(null, true); |
|
|
|
}, |
|
|
|
}, |
|
|
|
titleText: 'Add a fence device', |
|
|
|
titleText: 'Add a fence device', |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
confirmDialogRef.current.setOpen?.call(null, true); |
|
|
|
formDialogRef.current.setOpen?.call(null, true); |
|
|
|
}} |
|
|
|
}} |
|
|
|
onEdit={() => { |
|
|
|
onEdit={() => { |
|
|
|
setIsEditFences((previous) => !previous); |
|
|
|
setIsEditFences((previous) => !previous); |
|
|
|
}} |
|
|
|
}} |
|
|
|
onItemClick={({ fenceAgent: fenceId, fenceName, fenceParameters }) => { |
|
|
|
onItemClick={({ fenceAgent: fenceId, fenceName, fenceParameters }) => { |
|
|
|
setConfirmDialogProps({ |
|
|
|
setFormDialogProps({ |
|
|
|
actionProceedText: 'Update', |
|
|
|
actionProceedText: 'Update', |
|
|
|
content: ( |
|
|
|
content: ( |
|
|
|
<EditFenceInputGroup |
|
|
|
<EditFenceInputGroup |
|
|
@ -132,18 +231,34 @@ const ManageFencesPanel: FC = () => { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
getFormFenceParameters(fenceTemplate, event); |
|
|
|
const editData = getFormFenceParameters(fenceTemplate, event); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setConfirmDialogProps({ |
|
|
|
|
|
|
|
actionProceedText: 'Update', |
|
|
|
|
|
|
|
content: buildConfirmFenceParameters(editData.parameterInputs), |
|
|
|
|
|
|
|
titleText: ( |
|
|
|
|
|
|
|
<HeaderText> |
|
|
|
|
|
|
|
Update{' '} |
|
|
|
|
|
|
|
<InlineMonoText fontSize="inherit"> |
|
|
|
|
|
|
|
{editData.fenceName} |
|
|
|
|
|
|
|
</InlineMonoText>{' '} |
|
|
|
|
|
|
|
fence device with the following parameters? |
|
|
|
|
|
|
|
</HeaderText> |
|
|
|
|
|
|
|
), |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
confirmDialogRef.current.setOpen?.call(null, true); |
|
|
|
}, |
|
|
|
}, |
|
|
|
titleText: ( |
|
|
|
titleText: ( |
|
|
|
<HeaderText> |
|
|
|
<HeaderText> |
|
|
|
Update fence device{' '} |
|
|
|
Update fence device{' '} |
|
|
|
<InlineMonoText variant="h4">{fenceName}</InlineMonoText>{' '} |
|
|
|
<InlineMonoText fontSize="inherit">{fenceName}</InlineMonoText>{' '} |
|
|
|
parameters |
|
|
|
parameters |
|
|
|
</HeaderText> |
|
|
|
</HeaderText> |
|
|
|
), |
|
|
|
), |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
confirmDialogRef.current.setOpen?.call(null, true); |
|
|
|
formDialogRef.current.setOpen?.call(null, true); |
|
|
|
}} |
|
|
|
}} |
|
|
|
renderListItem={( |
|
|
|
renderListItem={( |
|
|
|
fenceUUID, |
|
|
|
fenceUUID, |
|
|
@ -201,6 +316,15 @@ const ManageFencesPanel: FC = () => { |
|
|
|
PaperProps: { sx: { minWidth: { xs: '90%', md: '50em' } } }, |
|
|
|
PaperProps: { sx: { minWidth: { xs: '90%', md: '50em' } } }, |
|
|
|
}} |
|
|
|
}} |
|
|
|
formContent |
|
|
|
formContent |
|
|
|
|
|
|
|
scrollBoxProps={{ |
|
|
|
|
|
|
|
padding: '.3em .5em', |
|
|
|
|
|
|
|
}} |
|
|
|
|
|
|
|
scrollContent |
|
|
|
|
|
|
|
{...formDialogProps} |
|
|
|
|
|
|
|
ref={formDialogRef} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
<ConfirmDialog |
|
|
|
|
|
|
|
scrollBoxProps={{ paddingRight: '1em' }} |
|
|
|
scrollContent |
|
|
|
scrollContent |
|
|
|
{...confirmDialogProps} |
|
|
|
{...confirmDialogProps} |
|
|
|
ref={confirmDialogRef} |
|
|
|
ref={confirmDialogRef} |
|
|
|