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:
parent
17fdcbd529
commit
6b201572cf
|
@ -11,6 +11,7 @@ import fr from './lang/fr.json';
|
||||||
import SuspenseLoader from './components/SuspenseLoader';
|
import SuspenseLoader from './components/SuspenseLoader';
|
||||||
import SidebarLayout from './layouts/SidebarLayout';
|
import SidebarLayout from './layouts/SidebarLayout';
|
||||||
import { TokenContext } from './contexts/tokenContext';
|
import { TokenContext } from './contexts/tokenContext';
|
||||||
|
import { TestModeProvider } from './contexts/TestModeContext';
|
||||||
import ResetPassword from './components/ResetPassword';
|
import ResetPassword from './components/ResetPassword';
|
||||||
import InstallationTabs from './content/dashboards/Installations/index';
|
import InstallationTabs from './content/dashboards/Installations/index';
|
||||||
import routes from 'src/Resources/routes.json';
|
import routes from 'src/Resources/routes.json';
|
||||||
|
@ -142,7 +143,9 @@ function App() {
|
||||||
element={
|
element={
|
||||||
<AccessContextProvider>
|
<AccessContextProvider>
|
||||||
<InstallationsContextProvider>
|
<InstallationsContextProvider>
|
||||||
|
<TestModeProvider>
|
||||||
<InstallationTabs />
|
<InstallationTabs />
|
||||||
|
</TestModeProvider>
|
||||||
</InstallationsContextProvider>
|
</InstallationsContextProvider>
|
||||||
</AccessContextProvider>
|
</AccessContextProvider>
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,9 @@ import {
|
||||||
IconButton,
|
IconButton,
|
||||||
Modal,
|
Modal,
|
||||||
TextField,
|
TextField,
|
||||||
useTheme
|
useTheme,
|
||||||
|
Switch,
|
||||||
|
FormControlLabel
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import Typography from '@mui/material/Typography';
|
import Typography from '@mui/material/Typography';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
@ -18,6 +20,7 @@ import { AxiosError, AxiosResponse } from 'axios/index';
|
||||||
import routes from '../../../Resources/routes.json';
|
import routes from '../../../Resources/routes.json';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { TokenContext } from '../../../contexts/tokenContext';
|
import { TokenContext } from '../../../contexts/tokenContext';
|
||||||
|
import { useTestMode } from '../../../contexts/TestModeContext';
|
||||||
import { Action } from '../../../interfaces/S3Types';
|
import { Action } from '../../../interfaces/S3Types';
|
||||||
import Button from '@mui/material/Button';
|
import Button from '@mui/material/Button';
|
||||||
import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers';
|
import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers';
|
||||||
|
@ -45,7 +48,12 @@ function HistoryOfActions(props: HistoryProps) {
|
||||||
timestamp: actionDate.toDate(),
|
timestamp: actionDate.toDate(),
|
||||||
description: ''
|
description: ''
|
||||||
});
|
});
|
||||||
|
const { testModeMap, setTestMode } = useTestMode();
|
||||||
|
const isTestMode = testModeMap[props.id]||false;
|
||||||
|
|
||||||
|
const handleTestModeToggle = () => {
|
||||||
|
setTestMode(props.id,!isTestMode);
|
||||||
|
};
|
||||||
const handleDateChange = (newdate) => {
|
const handleDateChange = (newdate) => {
|
||||||
setActionDate(newdate);
|
setActionDate(newdate);
|
||||||
setNewAction({
|
setNewAction({
|
||||||
|
@ -132,15 +140,26 @@ function HistoryOfActions(props: HistoryProps) {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
|
{/*<DateTimePicker*/}
|
||||||
|
{/* label="Select Action Date"*/}
|
||||||
|
{/* name="timestamp"*/}
|
||||||
|
{/* value={actionDate}*/}
|
||||||
|
{/* onChange={(newDate) => handleDateChange(newDate)}*/}
|
||||||
|
{/* sx={{*/}
|
||||||
|
{/* width: 450,*/}
|
||||||
|
{/* marginTop: 2*/}
|
||||||
|
{/* }}*/}
|
||||||
|
{/*/>*/}
|
||||||
<DateTimePicker
|
<DateTimePicker
|
||||||
label="Select Action Date"
|
label="Select Action Date"
|
||||||
name="timestamp"
|
|
||||||
value={actionDate}
|
value={actionDate}
|
||||||
onChange={(newDate) => handleDateChange(newDate)}
|
onChange={handleDateChange}
|
||||||
sx={{
|
renderInput={(params) => (
|
||||||
width: 450,
|
<TextField
|
||||||
marginTop: 2
|
{...params}
|
||||||
}}
|
sx={{ width: 450, marginTop: 2 }}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<TextField
|
<TextField
|
||||||
|
@ -166,8 +185,14 @@ function HistoryOfActions(props: HistoryProps) {
|
||||||
alignItems: 'center'
|
alignItems: 'center'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<FormControlLabel
|
||||||
|
control={<Switch checked={isTestMode} onChange={handleTestModeToggle} />}
|
||||||
|
label="Test Mode"
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
sx={{
|
sx={{
|
||||||
|
marginLeft: 2,
|
||||||
textTransform: 'none',
|
textTransform: 'none',
|
||||||
bgcolor: '#ffc04d',
|
bgcolor: '#ffc04d',
|
||||||
color: '#111111',
|
color: '#111111',
|
||||||
|
|
|
@ -14,7 +14,9 @@ import {
|
||||||
} from '@mui/material';
|
} from '@mui/material';
|
||||||
import { I_Installation } from 'src/interfaces/InstallationTypes';
|
import { I_Installation } from 'src/interfaces/InstallationTypes';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import BuildIcon from '@mui/icons-material/Build';
|
||||||
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
|
import { WebSocketContext } from 'src/contexts/WebSocketContextProvider';
|
||||||
|
import { useTestMode } from 'src/contexts/TestModeContext';
|
||||||
import { FormattedMessage } from 'react-intl';
|
import { FormattedMessage } from 'react-intl';
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
import routes from '../../../Resources/routes.json';
|
import routes from '../../../Resources/routes.json';
|
||||||
|
@ -30,6 +32,7 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
|
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
|
||||||
const currentLocation = useLocation();
|
const currentLocation = useLocation();
|
||||||
|
const { testModeMap } = useTestMode();
|
||||||
|
|
||||||
const sortedInstallations = [...props.installations].sort((a, b) => {
|
const sortedInstallations = [...props.installations].sort((a, b) => {
|
||||||
// Compare the status field of each installation and sort them based on the status.
|
// Compare the status field of each installation and sort them based on the status.
|
||||||
|
@ -242,6 +245,20 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||||
: 'green'
|
: '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>
|
</div>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
|
|
|
@ -18,6 +18,7 @@ import Overview from '../Overview/overview';
|
||||||
import Configuration from '../Configuration/Configuration';
|
import Configuration from '../Configuration/Configuration';
|
||||||
import { fetchData } from 'src/content/dashboards/Installations/fetchData';
|
import { fetchData } from 'src/content/dashboards/Installations/fetchData';
|
||||||
import CancelIcon from '@mui/icons-material/Cancel';
|
import CancelIcon from '@mui/icons-material/Cancel';
|
||||||
|
import BuildIcon from '@mui/icons-material/Build';
|
||||||
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
|
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
|
||||||
import routes from '../../../Resources/routes.json';
|
import routes from '../../../Resources/routes.json';
|
||||||
import Information from '../Information/Information';
|
import Information from '../Information/Information';
|
||||||
|
@ -25,6 +26,7 @@ import BatteryView from '../BatteryView/BatteryView';
|
||||||
import { UserType } from '../../../interfaces/UserTypes';
|
import { UserType } from '../../../interfaces/UserTypes';
|
||||||
import HistoryOfActions from '../History/History';
|
import HistoryOfActions from '../History/History';
|
||||||
import PvView from '../PvView/PvView';
|
import PvView from '../PvView/PvView';
|
||||||
|
import { useTestMode } from '../../../contexts/TestModeContext';
|
||||||
|
|
||||||
interface singleInstallationProps {
|
interface singleInstallationProps {
|
||||||
current_installation?: I_Installation;
|
current_installation?: I_Installation;
|
||||||
|
@ -43,6 +45,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
const [values, setValues] = useState<TopologyValues | null>(null);
|
const [values, setValues] = useState<TopologyValues | null>(null);
|
||||||
const status = getStatus(props.current_installation.id);
|
const status = getStatus(props.current_installation.id);
|
||||||
const [connected, setConnected] = useState(true);
|
const [connected, setConnected] = useState(true);
|
||||||
|
const { testModeMap } = useTestMode();
|
||||||
|
|
||||||
if (props.current_installation == undefined) {
|
if (props.current_installation == undefined) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -346,6 +349,20 @@ function Installation(props: singleInstallationProps) {
|
||||||
: 'green'
|
: '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>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue