add frontend and backend for "Test Mode" toggle in Salimax

this toggle is designed to mark any hardware and software tests on the installation and "lock" the installation from others
this toggle is under "Add New Action" in "History of Action" tab
turn on the toggle when starting test and add test content
turn off the toggle when finishing test
This commit is contained in:
Yinyin Liu 2024-07-16 11:53:37 +02:00
parent 17fdcbd529
commit 6b201572cf
5 changed files with 99 additions and 7 deletions

View File

@ -11,6 +11,7 @@ import fr from './lang/fr.json';
import SuspenseLoader from './components/SuspenseLoader';
import SidebarLayout from './layouts/SidebarLayout';
import { TokenContext } from './contexts/tokenContext';
import { TestModeProvider } from './contexts/TestModeContext';
import ResetPassword from './components/ResetPassword';
import InstallationTabs from './content/dashboards/Installations/index';
import routes from 'src/Resources/routes.json';
@ -142,7 +143,9 @@ function App() {
element={
<AccessContextProvider>
<InstallationsContextProvider>
<TestModeProvider>
<InstallationTabs />
</TestModeProvider>
</InstallationsContextProvider>
</AccessContextProvider>
}

View File

@ -9,7 +9,9 @@ import {
IconButton,
Modal,
TextField,
useTheme
useTheme,
Switch,
FormControlLabel
} from '@mui/material';
import Typography from '@mui/material/Typography';
import { FormattedMessage } from 'react-intl';
@ -18,6 +20,7 @@ import { AxiosError, AxiosResponse } from 'axios/index';
import routes from '../../../Resources/routes.json';
import { useNavigate } from 'react-router-dom';
import { TokenContext } from '../../../contexts/tokenContext';
import { useTestMode } from '../../../contexts/TestModeContext';
import { Action } from '../../../interfaces/S3Types';
import Button from '@mui/material/Button';
import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers';
@ -45,7 +48,12 @@ function HistoryOfActions(props: HistoryProps) {
timestamp: actionDate.toDate(),
description: ''
});
const { testModeMap, setTestMode } = useTestMode();
const isTestMode = testModeMap[props.id]||false;
const handleTestModeToggle = () => {
setTestMode(props.id,!isTestMode);
};
const handleDateChange = (newdate) => {
setActionDate(newdate);
setNewAction({
@ -132,15 +140,26 @@ 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"
name="timestamp"
value={actionDate}
onChange={(newDate) => handleDateChange(newDate)}
sx={{
width: 450,
marginTop: 2
}}
onChange={handleDateChange}
renderInput={(params) => (
<TextField
{...params}
sx={{ width: 450, marginTop: 2 }}
/>
)}
/>
<TextField
@ -166,8 +185,14 @@ function HistoryOfActions(props: HistoryProps) {
alignItems: 'center'
}}
>
<FormControlLabel
control={<Switch checked={isTestMode} onChange={handleTestModeToggle} />}
label="Test Mode"
/>
<Button
sx={{
marginLeft: 2,
textTransform: 'none',
bgcolor: '#ffc04d',
color: '#111111',

View File

@ -14,7 +14,9 @@ import {
} from '@mui/material';
import { I_Installation } from 'src/interfaces/InstallationTypes';
import CancelIcon from '@mui/icons-material/Cancel';
import BuildIcon from '@mui/icons-material/Build';
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
import { useTestMode } from 'src/contexts/TestModeContext';
import { FormattedMessage } from 'react-intl';
import { useLocation, useNavigate } from 'react-router-dom';
import routes from '../../../Resources/routes.json';
@ -30,6 +32,7 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
const navigate = useNavigate();
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
const currentLocation = useLocation();
const { testModeMap } = useTestMode();
const sortedInstallations = [...props.installations].sort((a, b) => {
// Compare the status field of each installation and sort them based on the status.
@ -242,6 +245,20 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
: 'green'
}}
/>
{testModeMap[installation.id] && (
<BuildIcon
style={{
width: '23px',
height: '23px',
color: 'purple',
borderRadius: '50%',
position: 'relative',
zIndex: 1,
marginLeft: status === -1 || status === -2 ? '-23px' : '2px',
}}
/>
)}
</div>
</TableCell>
</TableRow>

View File

@ -18,6 +18,7 @@ import Overview from '../Overview/overview';
import Configuration from '../Configuration/Configuration';
import { fetchData } from 'src/content/dashboards/Installations/fetchData';
import CancelIcon from '@mui/icons-material/Cancel';
import BuildIcon from '@mui/icons-material/Build';
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
import routes from '../../../Resources/routes.json';
import Information from '../Information/Information';
@ -25,6 +26,7 @@ import BatteryView from '../BatteryView/BatteryView';
import { UserType } from '../../../interfaces/UserTypes';
import HistoryOfActions from '../History/History';
import PvView from '../PvView/PvView';
import { useTestMode } from '../../../contexts/TestModeContext';
interface singleInstallationProps {
current_installation?: I_Installation;
@ -43,6 +45,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 { testModeMap } = useTestMode();
if (props.current_installation == undefined) {
return null;
@ -346,6 +349,20 @@ function Installation(props: singleInstallationProps) {
: 'green'
}}
/>
{testModeMap[props.current_installation.id] && (
<BuildIcon
style={{
width: '23px',
height: '23px',
color: 'purple',
borderRadius: '50%',
position: 'relative',
zIndex: 1,
marginLeft: status === -1 || status === -2 ? '-23px' : '2px',
}}
/>
)}
</div>
</div>

View File

@ -0,0 +1,30 @@
import React, { createContext, useContext, useState, ReactNode } from 'react';
interface TestModeContextProps {
testModeMap: { [key: number]: boolean };
setTestMode: (id: number, mode: boolean) => void;
}
const TestModeContext = createContext<TestModeContextProps | undefined>(undefined);
export const useTestMode = () => {
const context = useContext(TestModeContext);
if (!context) {
throw new Error('useTestMode must be used within a TestModeProvider');
}
return context;
};
export const TestModeProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
const [testModeMap, setTestModeMap] = useState<{ [key: number]: boolean }>({});
const setTestMode = (id: number, mode: boolean) => {
setTestModeMap(prev => ({ ...prev, [id]: mode }));
};
return (
<TestModeContext.Provider value={{ testModeMap, setTestMode }}>
{children}
</TestModeContext.Provider>
);
};