Fixed bug in database backup.
Updated view with icons in history actions Increased performance when deleting an action
This commit is contained in:
parent
ce50b7ef3e
commit
44f9fb7f7d
|
@ -808,10 +808,10 @@ public class Controller : ControllerBase
|
|||
|
||||
|
||||
[HttpPost(nameof(DeleteAction))]
|
||||
public async Task<ActionResult<IEnumerable<Object>>> DeleteAction([FromBody] UserAction action, Token authToken)
|
||||
public async Task<ActionResult<IEnumerable<Object>>> DeleteAction(Int64 actionId, Token authToken)
|
||||
{
|
||||
var session = Db.GetSession(authToken);
|
||||
var actionSuccess = await session.DeleteUserAction(action);
|
||||
var actionSuccess = await session.DeleteUserAction(actionId);
|
||||
return actionSuccess ? Ok() : Unauthorized();
|
||||
}
|
||||
|
||||
|
|
|
@ -152,21 +152,19 @@ public static class SessionMethods
|
|||
if (user is null || user.UserType == 0)
|
||||
return false;
|
||||
|
||||
action.UserName = user.Name;
|
||||
|
||||
Db.UpdateAction(action);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public static async Task<Boolean> DeleteUserAction(this Session? session, UserAction action)
|
||||
public static async Task<Boolean> DeleteUserAction(this Session? session, Int64 actionId)
|
||||
{
|
||||
var user = session?.User;
|
||||
|
||||
if (user is null || user.UserType == 0)
|
||||
return false;
|
||||
var action = Db.GetActionById(actionId);
|
||||
|
||||
action.UserName = user.Name;
|
||||
|
||||
Db.Delete(action);
|
||||
Console.WriteLine("---------------Deleted the Action in the database-----------------");
|
||||
|
|
|
@ -115,7 +115,7 @@ public static partial class Db
|
|||
{
|
||||
existingAction.Description = updatedAction.Description;
|
||||
existingAction.Timestamp = updatedAction.Timestamp;
|
||||
//Update(existingAction);
|
||||
Update(existingAction);
|
||||
Console.WriteLine("---------------Updated the Action in the database-----------------");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ set -e
|
|||
|
||||
|
||||
echo -e "\n============================ Deploy ============================\n"
|
||||
ip_addresses_usb0=("10.2.2.118" "10.2.4.155" "10.2.3.244" "10.2.4.127")
|
||||
ip_addresses_usb0=("10.2.2.118" "10.2.4.155" "10.2.3.244" "10.2.4.127" "10.2.4.96")
|
||||
ip_addresses_usb1=("10.2.0.179" )
|
||||
|
||||
|
||||
|
|
|
@ -37,8 +37,12 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
const [openModalFirmwareUpdate, setOpenModalFirmwareUpdate] = useState(false);
|
||||
const [openModalResultFirmwareUpdate, setOpenModalResultFirmwareUpdate] =
|
||||
useState(false);
|
||||
const [openModalDownloadBatteryLog, setOpenModalDownloadBatteryLog] = useState(false);
|
||||
const [openModalStartDownloadBatteryLog, setOpenModalStartDownloadBatteryLog] = useState(false);
|
||||
const [openModalDownloadBatteryLog, setOpenModalDownloadBatteryLog] =
|
||||
useState(false);
|
||||
const [
|
||||
openModalStartDownloadBatteryLog,
|
||||
setOpenModalStartDownloadBatteryLog
|
||||
] = useState(false);
|
||||
const [openModalError, setOpenModalError] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
|
||||
|
@ -153,7 +157,6 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
setOpenModalDownloadBatteryLog(false);
|
||||
};
|
||||
|
||||
|
||||
const DownloadBatteryLogModalHandleProceed = async () => {
|
||||
setOpenModalDownloadBatteryLog(false);
|
||||
setOpenModalStartDownloadBatteryLog(true);
|
||||
|
@ -161,7 +164,9 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
try {
|
||||
// Start the job to generate the battery log
|
||||
const startRes = await axiosConfig.post(
|
||||
`/StartDownloadBatteryLog?batteryNode=${props.batteryData.BatteryId.toString()}&installationId=${props.installationId}`
|
||||
`/StartDownloadBatteryLog?batteryNode=${props.batteryData.BatteryId.toString()}&installationId=${
|
||||
props.installationId
|
||||
}`
|
||||
);
|
||||
|
||||
if (startRes.status === 200) {
|
||||
|
@ -170,27 +175,29 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
// Polling to check the job status
|
||||
const checkJobStatus = async () => {
|
||||
try {
|
||||
const statusRes = await axiosConfig.get(`/GetJobResult?jobId=${jobId}`);
|
||||
const statusRes = await axiosConfig.get(
|
||||
`/GetJobResult?jobId=${jobId}`
|
||||
);
|
||||
|
||||
if (statusRes.status === 200) {
|
||||
const jobStatus = statusRes.data.status;
|
||||
|
||||
switch (jobStatus) {
|
||||
case "Completed":
|
||||
case 'Completed':
|
||||
return statusRes.data.fileName; // Return FileName upon completion
|
||||
case "Failed":
|
||||
throw new Error("Job processing failed.");
|
||||
case "Processing":
|
||||
await new Promise(resolve => setTimeout(resolve, 60000)); // Wait for 60 seconds before next check
|
||||
case 'Failed':
|
||||
throw new Error('Job processing failed.');
|
||||
case 'Processing':
|
||||
await new Promise((resolve) => setTimeout(resolve, 60000)); // Wait for 60 seconds before next check
|
||||
return checkJobStatus();
|
||||
default:
|
||||
throw new Error("Unknown download battery log job status.");
|
||||
throw new Error('Unknown download battery log job status.');
|
||||
}
|
||||
} else {
|
||||
throw new Error("Unexpected error occurred.");
|
||||
throw new Error('Unexpected error occurred.');
|
||||
}
|
||||
} catch (error) {
|
||||
throw new Error("Failed to fetch job status."); // Catch errors from status check
|
||||
throw new Error('Failed to fetch job status.'); // Catch errors from status check
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -198,9 +205,12 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
const fileName = await checkJobStatus();
|
||||
|
||||
// Once job is completed, download the file
|
||||
const res = await axiosConfig.get(`/DownloadBatteryLog?jobId=${jobId}`, {
|
||||
responseType: 'blob',
|
||||
});
|
||||
const res = await axiosConfig.get(
|
||||
`/DownloadBatteryLog?jobId=${jobId}`,
|
||||
{
|
||||
responseType: 'blob'
|
||||
}
|
||||
);
|
||||
|
||||
const finalFileName = fileName || 'unknown_file_name'; // Default filename if not received
|
||||
console.log('Downloaded file name:', finalFileName);
|
||||
|
@ -216,10 +226,13 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
|
||||
// Delete the file after successful download
|
||||
console.log('Deleted file name:', finalFileName);
|
||||
await axiosConfig.delete(`/DeleteBatteryLog`, { params: { fileName: finalFileName } });
|
||||
|
||||
await axiosConfig.delete(`/DeleteBatteryLog`, {
|
||||
params: { fileName: finalFileName }
|
||||
});
|
||||
} else {
|
||||
console.error('Failed to start downloading battery log in the backend.');
|
||||
console.error(
|
||||
'Failed to start downloading battery log in the backend.'
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error:', error.message);
|
||||
|
@ -322,7 +335,8 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
</Typography>
|
||||
|
||||
<Typography variant="body1" gutterBottom>
|
||||
This action requires the battery service to be stopped for around 10-15 minutes.
|
||||
This action requires the battery service to be stopped for around
|
||||
10-15 minutes.
|
||||
</Typography>
|
||||
|
||||
<div
|
||||
|
@ -389,7 +403,8 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
gutterBottom
|
||||
sx={{ fontWeight: 'bold' }}
|
||||
>
|
||||
The battery log is getting downloaded. It will be saved in the Downloads folder. Please wait...
|
||||
The battery log is getting downloaded. It will be saved in the
|
||||
Downloads folder. Please wait...
|
||||
</Typography>
|
||||
|
||||
<div
|
||||
|
@ -429,7 +444,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
width: 420,
|
||||
width: 500,
|
||||
bgcolor: 'background.paper',
|
||||
borderRadius: 4,
|
||||
boxShadow: 24,
|
||||
|
@ -448,7 +463,8 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
</Typography>
|
||||
|
||||
<Typography variant="body1" gutterBottom>
|
||||
This action requires the battery service to be stopped for around 10-15 minutes.
|
||||
This action requires the battery service to be stopped for around
|
||||
10-15 minutes.
|
||||
</Typography>
|
||||
|
||||
<div
|
||||
|
@ -518,9 +534,17 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
{errorMessage}
|
||||
</Typography>
|
||||
|
||||
<div style={{ display: 'flex', alignItems: 'center', marginTop: 10 }}>
|
||||
<div
|
||||
style={{ display: 'flex', alignItems: 'center', marginTop: 10 }}
|
||||
>
|
||||
<Button
|
||||
sx={{ marginTop: 2, textTransform: 'none', bgcolor: '#ffc04d', color: '#111111', '&:hover': { bgcolor: '#f7b34d' } }}
|
||||
sx={{
|
||||
marginTop: 2,
|
||||
textTransform: 'none',
|
||||
bgcolor: '#ffc04d',
|
||||
color: '#111111',
|
||||
'&:hover': { bgcolor: '#f7b34d' }
|
||||
}}
|
||||
onClick={ErrorModalHandleOk}
|
||||
>
|
||||
Ok
|
||||
|
@ -581,7 +605,7 @@ function DetailedBatteryView(props: DetailedBatteryViewProps) {
|
|||
marginLeft: '20px',
|
||||
backgroundColor: '#ffc04d',
|
||||
color: '#000000',
|
||||
'&:hover': { bgcolor: '#f7b34d' },
|
||||
'&:hover': { bgcolor: '#f7b34d' }
|
||||
}}
|
||||
>
|
||||
Download Battery Log
|
||||
|
|
|
@ -5,14 +5,13 @@ import {
|
|||
Card,
|
||||
Container,
|
||||
Divider,
|
||||
FormControlLabel,
|
||||
Grid,
|
||||
IconButton,
|
||||
Modal,
|
||||
TextField,
|
||||
useTheme,
|
||||
Switch,
|
||||
FormControlLabel,
|
||||
Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper
|
||||
TextField,
|
||||
useTheme
|
||||
} from '@mui/material';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
@ -27,7 +26,9 @@ import Button from '@mui/material/Button';
|
|||
import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers';
|
||||
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
||||
import dayjs from 'dayjs';
|
||||
import { UserContext } from 'src/contexts/userContext';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import { UserContext } from '../../../contexts/userContext';
|
||||
|
||||
interface HistoryProps {
|
||||
errorLoadingS3Data: boolean;
|
||||
|
@ -37,14 +38,13 @@ interface HistoryProps {
|
|||
function HistoryOfActions(props: HistoryProps) {
|
||||
const theme = useTheme();
|
||||
const searchParams = new URLSearchParams(location.search);
|
||||
const context = useContext(UserContext);
|
||||
const { currentUser } = context;
|
||||
const [history, setHistory] = useState<Action[]>([]);
|
||||
const navigate = useNavigate();
|
||||
const tokencontext = useContext(TokenContext);
|
||||
const [actionDate, setActionDate] = useState(dayjs());
|
||||
const { removeToken } = tokencontext;
|
||||
const [openModalAddAction, setOpenModalAddAction] = useState(false);
|
||||
|
||||
const requiredFields = ['description', 'timestamp'];
|
||||
const [newAction, setNewAction] = useState<Partial<Action>>({
|
||||
installationId: props.id,
|
||||
|
@ -53,12 +53,15 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
});
|
||||
const { testModeMap, setTestMode } = useTestMode();
|
||||
const isTestMode = testModeMap[props.id] || false;
|
||||
const context = useContext(UserContext);
|
||||
const { currentUser, setUser } = context;
|
||||
const [isRowHovered, setHoveredRow] = useState(-1);
|
||||
const [selectedAction, setSelectedAction] = useState<number>(-1);
|
||||
const [editMode, setEditMode] = useState(false);
|
||||
const handleTestModeToggle = () => {
|
||||
setTestMode(props.id, !isTestMode);
|
||||
};
|
||||
|
||||
const handleDateChange = (newdate) => {
|
||||
setActionDate(newdate);
|
||||
setNewAction({
|
||||
|
@ -76,33 +79,36 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
};
|
||||
|
||||
const resetNewAction = () => {
|
||||
console.log("Reset action to default");
|
||||
console.log('Reset action to default');
|
||||
setActionDate(dayjs());
|
||||
setNewAction({
|
||||
...newAction,
|
||||
['description']: '',
|
||||
['description']: ''
|
||||
});
|
||||
setEditMode(false);
|
||||
};
|
||||
|
||||
const handleAddActionButton = () => {
|
||||
resetNewAction();
|
||||
//setOpenModalAddAction(!openModalAddAction);
|
||||
setOpenModalAddAction(true);
|
||||
};
|
||||
|
||||
const SumbitNewAction = () => {
|
||||
const handleEdit = (action) => {
|
||||
setEditMode(true);
|
||||
setNewAction(action);
|
||||
setOpenModalAddAction(true);
|
||||
};
|
||||
|
||||
const SumbitNewAction = async () => {
|
||||
const endpoint = editMode ? `/UpdateAction` : `/InsertNewAction`;
|
||||
console.log("Add an action", endpoint);
|
||||
const res=axiosConfig.post(endpoint,newAction).catch((err)=>{
|
||||
//console.log('Add an action', endpoint);
|
||||
const res = await axiosConfig.post(endpoint, newAction).catch((err) => {
|
||||
if (err.response) {
|
||||
// setError(true);
|
||||
// setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
if (res) {
|
||||
//setOpenModalAddAction(!openModalAddAction);
|
||||
getHistory();
|
||||
setOpenModalAddAction(false);
|
||||
setEditMode(false);
|
||||
}
|
||||
|
@ -113,19 +119,16 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
setEditMode(false);
|
||||
};
|
||||
|
||||
const HandleDelete = (e) => {
|
||||
console.log("Delete this action");
|
||||
const res = axiosConfig.post(`/DeleteAction`, newAction).catch((err) => {
|
||||
const HandleDelete = async (action) => {
|
||||
const res = await axiosConfig
|
||||
.post(`/DeleteAction?actionId=${action.id}`)
|
||||
.catch((err) => {
|
||||
if (err.response) {
|
||||
// setError(true);
|
||||
// setLoading(false);
|
||||
}
|
||||
});
|
||||
|
||||
if (res) {
|
||||
console.log("Delete this action is successful");
|
||||
setOpenModalAddAction(false);
|
||||
setEditMode(false);
|
||||
getHistory();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -138,34 +141,7 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
return true;
|
||||
};
|
||||
|
||||
const handleSelectOneAction = (action) => {
|
||||
if (selectedAction != action.id) {
|
||||
setSelectedAction(action.id);
|
||||
setSelectedAction(-1);
|
||||
if (action.userName === currentUser.name){
|
||||
console.log("Select this action");
|
||||
setActionDate(dayjs(action.timestamp));
|
||||
setNewAction({ description: action.description, timestamp: action.timestamp });
|
||||
setEditMode(true);
|
||||
setOpenModalAddAction(true);
|
||||
} else {
|
||||
console.log('The user is not authorized to edit this action.');
|
||||
}
|
||||
|
||||
} else {
|
||||
setSelectedAction(-1);
|
||||
}
|
||||
};
|
||||
|
||||
const handleRowMouseEnter = (id) => {
|
||||
setHoveredRow(id);
|
||||
};
|
||||
|
||||
const handleRowMouseLeave = () => {
|
||||
setHoveredRow(-1);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const getHistory = () => {
|
||||
axiosConfig
|
||||
.get(`/GetHistoryForInstallation?id=${props.id}`)
|
||||
.then((res: AxiosResponse<Action[]>) => {
|
||||
|
@ -177,7 +153,10 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
navigate(routes.login);
|
||||
}
|
||||
});
|
||||
console.log("Update the tab:", openModalAddAction);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getHistory();
|
||||
}, [openModalAddAction]);
|
||||
|
||||
return (
|
||||
|
@ -206,27 +185,27 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
}}
|
||||
>
|
||||
<div>
|
||||
{/*<DateTimePicker*/}
|
||||
{/* label="Select Action Date"*/}
|
||||
{/* name="timestamp"*/}
|
||||
{/* value={actionDate}*/}
|
||||
{/* onChange={(newDate) => handleDateChange(newDate)}*/}
|
||||
{/* sx={{*/}
|
||||
{/* width: 450,*/}
|
||||
{/* marginTop: 2*/}
|
||||
{/* }}*/}
|
||||
{/*/>*/}
|
||||
<DateTimePicker
|
||||
label="Select Action Date"
|
||||
value={actionDate}
|
||||
onChange={handleDateChange}
|
||||
renderInput={(params) => (
|
||||
<TextField
|
||||
{...params}
|
||||
sx={{ width: 450, marginTop: 2 }}
|
||||
/>
|
||||
)}
|
||||
name="timestamp"
|
||||
value={editMode ? dayjs(newAction.timestamp) : actionDate}
|
||||
onChange={(newDate) => handleDateChange(newDate)}
|
||||
sx={{
|
||||
width: 450,
|
||||
marginTop: 2
|
||||
}}
|
||||
/>
|
||||
{/*<DateTimePicker*/}
|
||||
{/* label="Select Action Date"*/}
|
||||
{/* value={actionDate}*/}
|
||||
{/* onChange={handleDateChange}*/}
|
||||
{/* renderInput={(params) => (*/}
|
||||
{/* <TextField*/}
|
||||
{/* {...params}*/}
|
||||
{/* sx={{ width: 450, marginTop: 2 }}*/}
|
||||
{/* />*/}
|
||||
{/* )}*/}
|
||||
{/*/>*/}
|
||||
|
||||
<TextField
|
||||
label="Description"
|
||||
|
@ -252,7 +231,12 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
}}
|
||||
>
|
||||
<FormControlLabel
|
||||
control={<Switch checked={isTestMode} onChange={handleTestModeToggle} />}
|
||||
control={
|
||||
<Switch
|
||||
checked={isTestMode}
|
||||
onChange={handleTestModeToggle}
|
||||
/>
|
||||
}
|
||||
label="Test Mode"
|
||||
/>
|
||||
|
||||
|
@ -282,28 +266,12 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
>
|
||||
Cancel
|
||||
</Button>
|
||||
|
||||
{editMode && (
|
||||
<Button
|
||||
sx={{
|
||||
marginLeft: 2,
|
||||
textTransform: 'none',
|
||||
bgcolor: '#ffc04d',
|
||||
color: '#111111',
|
||||
'&:hover': { bgcolor: '#f7b34d' }
|
||||
}}
|
||||
onClick={HandleDelete}
|
||||
>
|
||||
Delete
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</Box>
|
||||
</LocalizationProvider>
|
||||
</Modal>
|
||||
)}
|
||||
|
||||
{!openModalAddAction && (
|
||||
<Container maxWidth="xl">
|
||||
<Grid container>
|
||||
<Grid container>
|
||||
|
@ -328,254 +296,238 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
|
||||
<Grid item xs={12} md={12}>
|
||||
{history.length > 0 && (
|
||||
// <Card sx={{ marginTop: '10px' }}>
|
||||
// <Divider />
|
||||
// <div>
|
||||
// <div
|
||||
// style={{
|
||||
// height: '40px',
|
||||
// marginBottom: '10px',
|
||||
// display: 'flex',
|
||||
// alignItems: 'center'
|
||||
// }}
|
||||
// >
|
||||
// <div
|
||||
// style={{
|
||||
// flex: 2,
|
||||
// marginTop: '15px',
|
||||
// display: 'flex',
|
||||
// alignItems: 'center',
|
||||
// justifyContent: 'center'
|
||||
// }}
|
||||
// >
|
||||
// <Typography
|
||||
// variant="body1"
|
||||
// color="dimgrey"
|
||||
// fontWeight="bold"
|
||||
// fontSize="1rem"
|
||||
// gutterBottom
|
||||
// noWrap
|
||||
// >
|
||||
// <FormattedMessage id="user" defaultMessage="User" />
|
||||
// </Typography>
|
||||
// </div>
|
||||
//
|
||||
// <div
|
||||
// style={{
|
||||
// flex: 1,
|
||||
// marginTop: '15px',
|
||||
// display: 'flex',
|
||||
// alignItems: 'center',
|
||||
// justifyContent: 'center'
|
||||
// }}
|
||||
// >
|
||||
// <Typography
|
||||
// variant="body1"
|
||||
// color="dimgrey"
|
||||
// fontWeight="bold"
|
||||
// fontSize="1rem"
|
||||
// gutterBottom
|
||||
// noWrap
|
||||
// >
|
||||
// <FormattedMessage id="date" defaultMessage="Date" />
|
||||
// </Typography>
|
||||
// </div>
|
||||
// <div
|
||||
// style={{
|
||||
// flex: 1,
|
||||
// marginTop: '15px',
|
||||
// display: 'flex',
|
||||
// alignItems: 'center',
|
||||
// justifyContent: 'center'
|
||||
// }}
|
||||
// >
|
||||
// <Typography
|
||||
// variant="body1"
|
||||
// color="dimgrey"
|
||||
// fontWeight="bold"
|
||||
// fontSize="1rem"
|
||||
// gutterBottom
|
||||
// noWrap
|
||||
// >
|
||||
// <FormattedMessage id="time" defaultMessage="Time" />
|
||||
// </Typography>
|
||||
// </div>
|
||||
// <div
|
||||
// style={{
|
||||
// flex: 6,
|
||||
// marginTop: '15px',
|
||||
// display: 'flex',
|
||||
// alignItems: 'center',
|
||||
// justifyContent: 'center'
|
||||
// }}
|
||||
// >
|
||||
// <Typography
|
||||
// variant="body1"
|
||||
// color="dimgrey"
|
||||
// fontWeight="bold"
|
||||
// fontSize="1rem"
|
||||
// gutterBottom
|
||||
// noWrap
|
||||
// >
|
||||
// <FormattedMessage
|
||||
// id="description"
|
||||
// defaultMessage="Description"
|
||||
// />
|
||||
// </Typography>
|
||||
// </div>
|
||||
// </div>
|
||||
// <Divider />
|
||||
// <div style={{ maxHeight: '400px', overflowY: 'auto' }}>
|
||||
// {history.map((action, index) => {
|
||||
// // Parse the timestamp string to a Date object
|
||||
// const date = new Date(action.timestamp);
|
||||
//
|
||||
// // Extract the date part (e.g., "2023-05-31")
|
||||
// const datePart = date.toLocaleDateString();
|
||||
//
|
||||
// // Extract the time part (e.g., "12:34:56")
|
||||
// const timePart = date.toLocaleTimeString();
|
||||
//
|
||||
// return (
|
||||
// <React.Fragment key={index}>
|
||||
// <Divider />
|
||||
// <div
|
||||
// style={{
|
||||
// minHeight: '40px',
|
||||
// marginBottom: '10px',
|
||||
// display: 'flex',
|
||||
// alignItems: 'center'
|
||||
// }}
|
||||
// >
|
||||
// <div
|
||||
// style={{
|
||||
// flex: 2,
|
||||
// marginTop: '15px',
|
||||
// display: 'flex',
|
||||
// alignItems: 'center',
|
||||
// justifyContent: 'center'
|
||||
// }}
|
||||
// >
|
||||
// <Typography
|
||||
// variant="body1"
|
||||
// fontWeight="bold"
|
||||
// color="text.primary"
|
||||
// gutterBottom
|
||||
// >
|
||||
// {action.userName}
|
||||
// </Typography>
|
||||
// </div>
|
||||
//
|
||||
// <div
|
||||
// style={{
|
||||
// flex: 1,
|
||||
// marginTop: '15px',
|
||||
// display: 'flex',
|
||||
// alignItems: 'center',
|
||||
// justifyContent: 'center'
|
||||
// }}
|
||||
// >
|
||||
// <Typography
|
||||
// variant="body1"
|
||||
// fontWeight="bold"
|
||||
// color="text.primary"
|
||||
// gutterBottom
|
||||
// >
|
||||
// {datePart}
|
||||
// </Typography>
|
||||
// </div>
|
||||
// <div
|
||||
// style={{
|
||||
// flex: 1,
|
||||
// marginTop: '15px',
|
||||
// display: 'flex',
|
||||
// alignItems: 'center',
|
||||
// justifyContent: 'center'
|
||||
// }}
|
||||
// >
|
||||
// <Typography
|
||||
// variant="body1"
|
||||
// fontWeight="bold"
|
||||
// color="text.primary"
|
||||
// gutterBottom
|
||||
// >
|
||||
// {timePart}
|
||||
// </Typography>
|
||||
// </div>
|
||||
//
|
||||
// <div
|
||||
// style={{
|
||||
// flex: 6,
|
||||
// display: 'flex',
|
||||
// marginTop: '15px',
|
||||
// alignItems: 'center',
|
||||
// justifyContent: 'center'
|
||||
// }}
|
||||
// >
|
||||
// <Typography
|
||||
// variant="body1"
|
||||
// fontWeight="bold"
|
||||
// color="text.primary"
|
||||
// gutterBottom
|
||||
// style={{
|
||||
// whiteSpace: 'normal',
|
||||
// wordBreak: 'break-word'
|
||||
// }}
|
||||
// >
|
||||
// {action.description}
|
||||
// </Typography>
|
||||
// </div>
|
||||
// </div>
|
||||
// </React.Fragment>
|
||||
// );
|
||||
// })}
|
||||
// </div>
|
||||
// </div>
|
||||
// </Card>
|
||||
<Card sx={{ marginTop: '10px' }}>
|
||||
<Divider />
|
||||
<TableContainer component={Paper}>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>User</TableCell>
|
||||
<TableCell>Date</TableCell>
|
||||
<TableCell>Time</TableCell>
|
||||
<TableCell>Description</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{history.map((action, index) => {
|
||||
const isActionSelected =
|
||||
action.id === selectedAction;
|
||||
const date = new Date(action.timestamp);
|
||||
const datePart = date.toLocaleDateString();
|
||||
const timePart = date.toLocaleTimeString();
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
height: '40px',
|
||||
marginBottom: '10px',
|
||||
display: 'flex',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
flex: 2,
|
||||
marginTop: '15px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body1"
|
||||
color="dimgrey"
|
||||
fontWeight="bold"
|
||||
fontSize="1rem"
|
||||
gutterBottom
|
||||
noWrap
|
||||
>
|
||||
<FormattedMessage id="user" defaultMessage="User" />
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
const rowStyles = isRowHovered === action.id
|
||||
? { cursor: 'pointer', backgroundColor: 'lightgray' }
|
||||
: {};
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
marginTop: '15px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body1"
|
||||
color="dimgrey"
|
||||
fontWeight="bold"
|
||||
fontSize="1rem"
|
||||
gutterBottom
|
||||
noWrap
|
||||
>
|
||||
<FormattedMessage id="date" defaultMessage="Date" />
|
||||
</Typography>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
marginTop: '15px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body1"
|
||||
color="dimgrey"
|
||||
fontWeight="bold"
|
||||
fontSize="1rem"
|
||||
gutterBottom
|
||||
noWrap
|
||||
>
|
||||
<FormattedMessage id="time" defaultMessage="Time" />
|
||||
</Typography>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 6,
|
||||
marginTop: '15px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body1"
|
||||
color="dimgrey"
|
||||
fontWeight="bold"
|
||||
fontSize="1rem"
|
||||
gutterBottom
|
||||
noWrap
|
||||
>
|
||||
<FormattedMessage
|
||||
id="description"
|
||||
defaultMessage="Description"
|
||||
/>
|
||||
</Typography>
|
||||
</div>
|
||||
</div>
|
||||
<Divider />
|
||||
<div style={{ maxHeight: '600px', overflowY: 'auto' }}>
|
||||
{history.map((action, index) => {
|
||||
// Parse the timestamp string to a Date object
|
||||
const date = new Date(action.timestamp);
|
||||
|
||||
// Extract the date part (e.g., "2023-05-31")
|
||||
const datePart = date.toLocaleDateString();
|
||||
|
||||
// Extract the time part (e.g., "12:34:56")
|
||||
const timePart = date.toLocaleTimeString();
|
||||
const iconStyle =
|
||||
action.userName === currentUser.name
|
||||
? {}
|
||||
: { color: 'rgba(0, 0, 0, 0.26)' };
|
||||
|
||||
return (
|
||||
<TableRow
|
||||
hover
|
||||
key={action.id}
|
||||
selected={isActionSelected}
|
||||
style={rowStyles}
|
||||
onClick={() => handleSelectOneAction(action)}
|
||||
onMouseEnter={() => handleRowMouseEnter(action.id)}
|
||||
onMouseLeave={handleRowMouseLeave}
|
||||
<React.Fragment key={index}>
|
||||
<Divider />
|
||||
<div
|
||||
style={{
|
||||
minHeight: '40px',
|
||||
marginBottom: '10px',
|
||||
display: 'flex',
|
||||
alignItems: 'center'
|
||||
}}
|
||||
>
|
||||
<TableCell>{action.userName}</TableCell>
|
||||
<TableCell>{datePart}</TableCell>
|
||||
<TableCell>{timePart}</TableCell>
|
||||
<TableCell>{action.description}</TableCell>
|
||||
</TableRow>
|
||||
<div
|
||||
style={{
|
||||
flex: 2,
|
||||
marginTop: '15px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body1"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
>
|
||||
{action.userName}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
marginTop: '15px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body1"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
>
|
||||
{datePart}
|
||||
</Typography>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
marginTop: '15px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body1"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
>
|
||||
{timePart}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 6,
|
||||
display: 'flex',
|
||||
marginTop: '15px',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<Typography
|
||||
variant="body1"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
style={{
|
||||
whiteSpace: 'normal',
|
||||
wordBreak: 'break-word'
|
||||
}}
|
||||
>
|
||||
{action.description}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
marginTop: '15px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
}}
|
||||
>
|
||||
<IconButton
|
||||
style={iconStyle}
|
||||
onClick={() => handleEdit(action)}
|
||||
disabled={action.userName != currentUser.name}
|
||||
>
|
||||
<EditIcon />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
style={iconStyle}
|
||||
onClick={() => HandleDelete(action)}
|
||||
disabled={action.userName != currentUser.name}
|
||||
>
|
||||
<DeleteIcon />
|
||||
</IconButton>
|
||||
</div>
|
||||
</div>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</div>
|
||||
</div>
|
||||
</Card>
|
||||
)}
|
||||
|
||||
|
@ -625,7 +577,6 @@ function HistoryOfActions(props: HistoryProps) {
|
|||
)}
|
||||
</Grid>
|
||||
</Container>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import { Card, CircularProgress, Grid, Typography } from '@mui/material';
|
||||
import {
|
||||
Card,
|
||||
CircularProgress,
|
||||
Container,
|
||||
Grid,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
import { I_Installation } from 'src/interfaces/InstallationTypes';
|
||||
import { UserContext } from 'src/contexts/userContext';
|
||||
import AccessContextProvider from 'src/contexts/AccessContextProvider';
|
||||
|
@ -45,6 +51,7 @@ function Installation(props: singleInstallationProps) {
|
|||
const [values, setValues] = useState<TopologyValues | null>(null);
|
||||
const status = getStatus(props.current_installation.id);
|
||||
const [connected, setConnected] = useState(true);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const { testModeMap } = useTestMode();
|
||||
|
||||
if (props.current_installation == undefined) {
|
||||
|
@ -94,9 +101,11 @@ function Installation(props: singleInstallationProps) {
|
|||
|
||||
if (i <= 0) {
|
||||
setConnected(false);
|
||||
setLoading(false);
|
||||
return false;
|
||||
}
|
||||
setConnected(true);
|
||||
setLoading(false);
|
||||
|
||||
const timestamp = Object.keys(res)[Object.keys(res).length - 1];
|
||||
|
||||
|
@ -133,9 +142,11 @@ function Installation(props: singleInstallationProps) {
|
|||
|
||||
if (i <= 0) {
|
||||
setConnected(false);
|
||||
setLoading(false);
|
||||
return false;
|
||||
}
|
||||
setConnected(true);
|
||||
setLoading(false);
|
||||
console.log('NUMBER OF FILES=' + Object.keys(res).length);
|
||||
|
||||
while (continueFetching.current) {
|
||||
|
@ -259,6 +270,7 @@ function Installation(props: singleInstallationProps) {
|
|||
{props.current_installation.name}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
{currentTab == 'live' && values && (
|
||||
<div style={{ display: 'flex', alignItems: 'center' }}>
|
||||
<Typography
|
||||
|
@ -359,13 +371,35 @@ function Installation(props: singleInstallationProps) {
|
|||
borderRadius: '50%',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
marginLeft: status === -1 || status === -2 ? '-23px' : '2px',
|
||||
marginLeft: status === -1 || status === -2 ? '-23px' : '2px'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{loading && currentTab != 'information' && currentTab != 'history' && (
|
||||
<Container
|
||||
maxWidth="xl"
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '70vh'
|
||||
}}
|
||||
>
|
||||
<CircularProgress size={60} style={{ color: '#ffc04d' }} />
|
||||
<Typography
|
||||
variant="body2"
|
||||
style={{ color: 'black', fontWeight: 'bold' }}
|
||||
mt={2}
|
||||
>
|
||||
Connecting to the device...
|
||||
</Typography>
|
||||
</Container>
|
||||
)}
|
||||
|
||||
<Card variant="outlined">
|
||||
<Grid
|
||||
container
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
import { Card, CircularProgress, Grid, Typography } from '@mui/material';
|
||||
import {
|
||||
Card,
|
||||
CircularProgress,
|
||||
Container,
|
||||
Grid,
|
||||
Typography
|
||||
} from '@mui/material';
|
||||
import { I_Installation } from 'src/interfaces/InstallationTypes';
|
||||
import { UserContext } from 'src/contexts/userContext';
|
||||
import { TimeSpan, UnixTime } from 'src/dataCache/time';
|
||||
|
@ -39,6 +45,7 @@ function Installation(props: singleInstallationProps) {
|
|||
setFailedToCommunicateWithInstallation
|
||||
] = useState(0);
|
||||
const [connected, setConnected] = useState(true);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
if (props.current_installation == undefined) {
|
||||
return null;
|
||||
|
@ -90,9 +97,11 @@ function Installation(props: singleInstallationProps) {
|
|||
|
||||
if (i <= 0) {
|
||||
setConnected(false);
|
||||
setLoading(false);
|
||||
return false;
|
||||
}
|
||||
setConnected(true);
|
||||
setLoading(false);
|
||||
console.log('NUMBER OF FILES=' + Object.keys(res).length);
|
||||
|
||||
while (continueFetching.current) {
|
||||
|
@ -267,6 +276,27 @@ function Installation(props: singleInstallationProps) {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
{loading && currentTab != 'information' && currentTab != 'overview' && (
|
||||
<Container
|
||||
maxWidth="xl"
|
||||
sx={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
height: '70vh'
|
||||
}}
|
||||
>
|
||||
<CircularProgress size={60} style={{ color: '#ffc04d' }} />
|
||||
<Typography
|
||||
variant="body2"
|
||||
style={{ color: 'black', fontWeight: 'bold' }}
|
||||
mt={2}
|
||||
>
|
||||
Connecting to the device...
|
||||
</Typography>
|
||||
</Container>
|
||||
)}
|
||||
|
||||
<Card variant="outlined">
|
||||
<Grid
|
||||
|
|
|
@ -92,10 +92,10 @@ function SalidomoInstallationTabs() {
|
|||
/>
|
||||
)
|
||||
},
|
||||
// {
|
||||
// value: 'overview',
|
||||
// label: <FormattedMessage id="overview" defaultMessage="Overview" />
|
||||
// },
|
||||
{
|
||||
value: 'overview',
|
||||
label: <FormattedMessage id="overview" defaultMessage="Overview" />
|
||||
},
|
||||
{
|
||||
value: 'log',
|
||||
label: <FormattedMessage id="log" defaultMessage="Log" />
|
||||
|
|
Loading…
Reference in New Issue