Added history tab
This commit is contained in:
parent
b55cc076cf
commit
e6c32b7162
|
@ -29,7 +29,6 @@ import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import axiosConfig from '../../../Resources/axiosConfig';
|
import axiosConfig from '../../../Resources/axiosConfig';
|
||||||
import utc from 'dayjs/plugin/utc';
|
import utc from 'dayjs/plugin/utc';
|
||||||
import { Action } from '../../../interfaces/S3Types';
|
|
||||||
import { UserContext } from '../../../contexts/userContext';
|
import { UserContext } from '../../../contexts/userContext';
|
||||||
|
|
||||||
interface ConfigurationProps {
|
interface ConfigurationProps {
|
||||||
|
@ -136,14 +135,6 @@ function Configuration(props: ConfigurationProps) {
|
||||||
.add(localOffset, 'minute')
|
.add(localOffset, 'minute')
|
||||||
.toDate()
|
.toDate()
|
||||||
};
|
};
|
||||||
|
|
||||||
const historyAction: Action = {
|
|
||||||
configuration: configurationToSend,
|
|
||||||
date: new Date().toISOString().split('T')[0], // Gets the current date in YYYY-MM-DD format
|
|
||||||
time: new Date().toISOString().split('T')[1].split('.')[0], // Gets the current time in HH:MM:SS format
|
|
||||||
user: currentUser.name
|
|
||||||
};
|
|
||||||
|
|
||||||
// console.log('will send ', dayjs(formValues.calibrationChargeDate));
|
// console.log('will send ', dayjs(formValues.calibrationChargeDate));
|
||||||
|
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
@ -160,23 +151,10 @@ function Configuration(props: ConfigurationProps) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res) {
|
if (res) {
|
||||||
const historyRes = await axiosConfig
|
|
||||||
.post(
|
|
||||||
`/UpdateActionHistory?installationId=${props.id}`,
|
|
||||||
historyAction
|
|
||||||
)
|
|
||||||
.catch((err) => {
|
|
||||||
if (err.response) {
|
|
||||||
setError(true);
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (historyRes) {
|
|
||||||
setUpdated(true);
|
setUpdated(true);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleOkOnErrorDateModal = () => {
|
const handleOkOnErrorDateModal = () => {
|
||||||
|
|
|
@ -122,30 +122,42 @@ function HistoryOfActions(props: HistoryProps) {
|
||||||
<FormattedMessage id="time" defaultMessage="Time" />
|
<FormattedMessage id="time" defaultMessage="Time" />
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
{/*<div*/}
|
<div
|
||||||
{/* style={{*/}
|
style={{
|
||||||
{/* flex: 1,*/}
|
flex: 1,
|
||||||
{/* marginTop: '15px',*/}
|
marginTop: '15px',
|
||||||
{/* display: 'flex',*/}
|
display: 'flex',
|
||||||
{/* alignItems: 'center',*/}
|
alignItems: 'center',
|
||||||
{/* justifyContent: 'center'*/}
|
justifyContent: 'center'
|
||||||
{/* }}*/}
|
}}
|
||||||
{/*>*/}
|
>
|
||||||
{/* <Typography*/}
|
<Typography
|
||||||
{/* variant="body1"*/}
|
variant="body1"
|
||||||
{/* color="dimgrey"*/}
|
color="dimgrey"
|
||||||
{/* fontWeight="bold"*/}
|
fontWeight="bold"
|
||||||
{/* fontSize="1rem"*/}
|
fontSize="1rem"
|
||||||
{/* gutterBottom*/}
|
gutterBottom
|
||||||
{/* noWrap*/}
|
noWrap
|
||||||
{/* >*/}
|
>
|
||||||
{/* <FormattedMessage id="seen" defaultMessage="Seen" />*/}
|
<FormattedMessage
|
||||||
{/* </Typography>*/}
|
id="description"
|
||||||
{/*</div>*/}
|
defaultMessage="Description"
|
||||||
|
/>
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Divider />
|
<Divider />
|
||||||
<div style={{ maxHeight: '400px', overflowY: 'auto' }}>
|
<div style={{ maxHeight: '400px', overflowY: 'auto' }}>
|
||||||
{history.map((action, index) => (
|
{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 (
|
||||||
<>
|
<>
|
||||||
<Divider />
|
<Divider />
|
||||||
<div
|
<div
|
||||||
|
@ -173,7 +185,7 @@ function HistoryOfActions(props: HistoryProps) {
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
>
|
>
|
||||||
{action.user}
|
{action.userName}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -193,7 +205,7 @@ function HistoryOfActions(props: HistoryProps) {
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
>
|
>
|
||||||
{action.date}
|
{datePart}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
@ -212,12 +224,33 @@ function HistoryOfActions(props: HistoryProps) {
|
||||||
gutterBottom
|
gutterBottom
|
||||||
noWrap
|
noWrap
|
||||||
>
|
>
|
||||||
{action.time}
|
{timePart}
|
||||||
|
</Typography>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
flex: 3,
|
||||||
|
display: 'flex',
|
||||||
|
marginTop: '15px',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Typography
|
||||||
|
variant="body1"
|
||||||
|
fontWeight="bold"
|
||||||
|
color="text.primary"
|
||||||
|
gutterBottom
|
||||||
|
noWrap
|
||||||
|
>
|
||||||
|
{action.description}
|
||||||
</Typography>
|
</Typography>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
|
@ -24,6 +24,7 @@ import Information from '../Information/Information';
|
||||||
import BatteryView from '../BatteryView/BatteryView';
|
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';
|
||||||
|
|
||||||
interface singleInstallationProps {
|
interface singleInstallationProps {
|
||||||
current_installation?: I_Installation;
|
current_installation?: I_Installation;
|
||||||
|
@ -124,6 +125,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
currentTab == 'live' ||
|
currentTab == 'live' ||
|
||||||
|
currentTab == 'pvview' ||
|
||||||
currentTab == 'configuration' ||
|
currentTab == 'configuration' ||
|
||||||
location.includes('batteryview')
|
location.includes('batteryview')
|
||||||
) {
|
) {
|
||||||
|
@ -131,7 +133,8 @@ function Installation(props: singleInstallationProps) {
|
||||||
|
|
||||||
if (
|
if (
|
||||||
currentTab == 'live' ||
|
currentTab == 'live' ||
|
||||||
(location.includes('batteryview') && !location.includes('mainstats'))
|
(location.includes('batteryview') && !location.includes('mainstats')) ||
|
||||||
|
currentTab == 'pvview'
|
||||||
) {
|
) {
|
||||||
fetchDataPeriodically();
|
fetchDataPeriodically();
|
||||||
interval = setInterval(fetchDataPeriodically, 2000);
|
interval = setInterval(fetchDataPeriodically, 2000);
|
||||||
|
@ -144,6 +147,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
return () => {
|
return () => {
|
||||||
if (
|
if (
|
||||||
currentTab == 'live' ||
|
currentTab == 'live' ||
|
||||||
|
currentTab == 'pvview' ||
|
||||||
(location.includes('batteryview') && !location.includes('mainstats'))
|
(location.includes('batteryview') && !location.includes('mainstats'))
|
||||||
) {
|
) {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
|
@ -314,13 +318,7 @@ function Installation(props: singleInstallationProps) {
|
||||||
<Route
|
<Route
|
||||||
path={routes.pvview + '*'}
|
path={routes.pvview + '*'}
|
||||||
element={
|
element={
|
||||||
<PvView
|
<PvView values={values} connected={connected}></PvView>
|
||||||
values={values}
|
|
||||||
s3Credentials={s3Credentials}
|
|
||||||
installationId={props.current_installation.id}
|
|
||||||
productNum={props.current_installation.product}
|
|
||||||
connected={connected}
|
|
||||||
></PvView>
|
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
|
|
||||||
|
|
|
@ -140,15 +140,15 @@ function InstallationTabs() {
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// value: 'history',
|
value: 'history',
|
||||||
// label: (
|
label: (
|
||||||
// <FormattedMessage
|
<FormattedMessage
|
||||||
// id="history"
|
id="history"
|
||||||
// defaultMessage="History Of Actions"
|
defaultMessage="History Of Actions"
|
||||||
// />
|
/>
|
||||||
// )
|
)
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
value: 'pvview',
|
value: 'pvview',
|
||||||
label: <FormattedMessage id="pvview" defaultMessage="Pv View" />
|
label: <FormattedMessage id="pvview" defaultMessage="Pv View" />
|
||||||
|
@ -271,16 +271,16 @@ function InstallationTabs() {
|
||||||
defaultMessage="Configuration"
|
defaultMessage="Configuration"
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: 'history',
|
||||||
|
label: (
|
||||||
|
<FormattedMessage
|
||||||
|
id="history"
|
||||||
|
defaultMessage="History Of Actions"
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// value: 'history',
|
|
||||||
// label: (
|
|
||||||
// <FormattedMessage
|
|
||||||
// id="history"
|
|
||||||
// defaultMessage="History Of Actions"
|
|
||||||
// />
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
]
|
]
|
||||||
: currentUser.userType == UserType.partner
|
: currentUser.userType == UserType.partner
|
||||||
? [
|
? [
|
||||||
|
|
|
@ -37,8 +37,8 @@ export type ConfigurationValues = {
|
||||||
|
|
||||||
export interface Pv {
|
export interface Pv {
|
||||||
PvId: number;
|
PvId: number;
|
||||||
Voltage: I_BoxDataValue;
|
|
||||||
Power: I_BoxDataValue;
|
Power: I_BoxDataValue;
|
||||||
|
Voltage: I_BoxDataValue;
|
||||||
Current: I_BoxDataValue;
|
Current: I_BoxDataValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,6 +86,8 @@ export interface Battery {
|
||||||
MaxDischargePower: I_BoxDataValue;
|
MaxDischargePower: I_BoxDataValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const PvKeys = ['PvId', 'Power', 'Voltage', 'Current'];
|
||||||
|
|
||||||
const BatteryKeys = [
|
const BatteryKeys = [
|
||||||
'BatteryId',
|
'BatteryId',
|
||||||
'FwVersion',
|
'FwVersion',
|
||||||
|
@ -177,10 +179,15 @@ type TopologyPaths = { [key in keyof TopologyValues]: string[] };
|
||||||
|
|
||||||
const batteryIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
const batteryIds = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
|
||||||
|
const pvIds = [
|
||||||
|
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
|
||||||
|
23, 24, 25, 26, 27, 28, 29, 30
|
||||||
|
];
|
||||||
|
|
||||||
const PvPaths = [
|
const PvPaths = [
|
||||||
|
'/PvOnDc/Strings/%id%/Power',
|
||||||
'/PvOnDc/Strings/%id%/Voltage',
|
'/PvOnDc/Strings/%id%/Voltage',
|
||||||
'/PvOnDc/Strings/%id%/Current',
|
'/PvOnDc/Strings/%id%/Current'
|
||||||
'/PvOnDc/Strings/%id%/Power'
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const batteryPaths = [
|
const batteryPaths = [
|
||||||
|
@ -305,7 +312,7 @@ export const topologyPaths: TopologyPaths = {
|
||||||
batteryPaths.map((path) => path.replace('%id%', id.toString()))
|
batteryPaths.map((path) => path.replace('%id%', id.toString()))
|
||||||
),
|
),
|
||||||
|
|
||||||
pvView: batteryIds.flatMap((id) =>
|
pvView: pvIds.flatMap((id) =>
|
||||||
PvPaths.map((path) => path.replace('%id%', id.toString()))
|
PvPaths.map((path) => path.replace('%id%', id.toString()))
|
||||||
),
|
),
|
||||||
|
|
||||||
|
@ -336,9 +343,6 @@ export const extractValues = (
|
||||||
timeSeriesData: DataPoint
|
timeSeriesData: DataPoint
|
||||||
): TopologyValues | null => {
|
): TopologyValues | null => {
|
||||||
const extractedValues: TopologyValues = {} as TopologyValues;
|
const extractedValues: TopologyValues = {} as TopologyValues;
|
||||||
|
|
||||||
// console.log('timeSeriesData=', timeSeriesData);
|
|
||||||
|
|
||||||
for (const topologyKey of Object.keys(topologyPaths)) {
|
for (const topologyKey of Object.keys(topologyPaths)) {
|
||||||
//Each topologykey may have more than one paths (for example inverter)
|
//Each topologykey may have more than one paths (for example inverter)
|
||||||
const paths = topologyPaths[topologyKey];
|
const paths = topologyPaths[topologyKey];
|
||||||
|
@ -346,12 +350,6 @@ export const extractValues = (
|
||||||
|
|
||||||
if (topologyKey === 'pvView') {
|
if (topologyKey === 'pvView') {
|
||||||
extractedValues[topologyKey] = [];
|
extractedValues[topologyKey] = [];
|
||||||
const node_ids_from_csv = timeSeriesData.value[
|
|
||||||
'/Config/Devices/BatteryNodes'
|
|
||||||
].value
|
|
||||||
.toString()
|
|
||||||
.split(',');
|
|
||||||
|
|
||||||
let pv_index = 0;
|
let pv_index = 0;
|
||||||
let pathIndex = 0;
|
let pathIndex = 0;
|
||||||
|
|
||||||
|
@ -359,16 +357,16 @@ export const extractValues = (
|
||||||
let pv = {};
|
let pv = {};
|
||||||
let existingKeys = 0;
|
let existingKeys = 0;
|
||||||
|
|
||||||
//We prepare a battery object for each node. We extract the nodes from the '/Config/Devices/BatteryNodes' path. For example, nodes can be [2,4,5,6] (one is missing)
|
//We prepare a pv object for each node. We extract the number of nodes from the '/PvOnDc/NbrOfStrings' path.
|
||||||
//BatteryKeys[0] is the battery id. We set the battery id to the corresponding node id.
|
//PvKeys[0] is the pv id.
|
||||||
battery[BatteryKeys[0]] = node_ids_from_csv[pv_index];
|
pv[PvKeys[0]] = pv_index;
|
||||||
//Then, search all the remaining battery keys
|
//Then, search all the remaining battery keys
|
||||||
for (let i = 1; i < BatteryKeys.length; i++) {
|
for (let i = 1; i < PvKeys.length; i++) {
|
||||||
const path = paths[pathIndex];
|
const path = paths[pathIndex];
|
||||||
if (timeSeriesData.value.hasOwnProperty(path)) {
|
if (timeSeriesData.value.hasOwnProperty(path)) {
|
||||||
existingKeys++;
|
existingKeys++;
|
||||||
|
|
||||||
battery[BatteryKeys[i]] = {
|
pv[PvKeys[i]] = {
|
||||||
unit: timeSeriesData.value[path].unit.includes('~')
|
unit: timeSeriesData.value[path].unit.includes('~')
|
||||||
? timeSeriesData.value[path].unit.replace('~', '')
|
? timeSeriesData.value[path].unit.replace('~', '')
|
||||||
: timeSeriesData.value[path].unit,
|
: timeSeriesData.value[path].unit,
|
||||||
|
@ -380,14 +378,12 @@ export const extractValues = (
|
||||||
}
|
}
|
||||||
pathIndex++;
|
pathIndex++;
|
||||||
}
|
}
|
||||||
battery_index++;
|
pv_index++;
|
||||||
if (existingKeys > 0) {
|
if (existingKeys > 0) {
|
||||||
extractedValues[topologyKey].push(battery as Battery);
|
extractedValues[topologyKey].push(pv as Pv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (topologyKey === 'batteryView') {
|
||||||
|
|
||||||
if (topologyKey === 'batteryView') {
|
|
||||||
extractedValues[topologyKey] = [];
|
extractedValues[topologyKey] = [];
|
||||||
const node_ids_from_csv = timeSeriesData.value[
|
const node_ids_from_csv = timeSeriesData.value[
|
||||||
'/Config/Devices/BatteryNodes'
|
'/Config/Devices/BatteryNodes'
|
||||||
|
|
|
@ -0,0 +1,187 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import {
|
||||||
|
Container,
|
||||||
|
Paper,
|
||||||
|
Table,
|
||||||
|
TableBody,
|
||||||
|
TableCell,
|
||||||
|
TableContainer,
|
||||||
|
TableHead,
|
||||||
|
TableRow,
|
||||||
|
Typography
|
||||||
|
} from '@mui/material';
|
||||||
|
import { TopologyValues } from '../Log/graph.util';
|
||||||
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
import routes from '../../../Resources/routes.json';
|
||||||
|
import CircularProgress from '@mui/material/CircularProgress';
|
||||||
|
|
||||||
|
interface PvViewProps {
|
||||||
|
values: TopologyValues;
|
||||||
|
connected: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function PvView(props: PvViewProps) {
|
||||||
|
if (props.values === null && props.connected == true) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const currentLocation = useLocation();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const sortedPvView =
|
||||||
|
props.values != null
|
||||||
|
? [...props.values.pvView].sort((a, b) => a.PvId - b.PvId)
|
||||||
|
: [];
|
||||||
|
|
||||||
|
const [loading, setLoading] = useState(sortedPvView.length == 0);
|
||||||
|
|
||||||
|
const handleMainStatsButton = () => {
|
||||||
|
navigate(routes.mainstats);
|
||||||
|
};
|
||||||
|
|
||||||
|
const findBatteryData = (batteryId: number) => {
|
||||||
|
for (let i = 0; i < props.values.batteryView.length; i++) {
|
||||||
|
if (props.values.batteryView[i].BatteryId == batteryId) {
|
||||||
|
return props.values.batteryView[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (sortedPvView.length == 0) {
|
||||||
|
setLoading(true);
|
||||||
|
} else {
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
}, [sortedPvView]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{!props.connected && (
|
||||||
|
<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}
|
||||||
|
>
|
||||||
|
Unable to communicate with the installation
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" style={{ color: 'black' }}>
|
||||||
|
Please wait or refresh the page
|
||||||
|
</Typography>
|
||||||
|
</Container>
|
||||||
|
)}
|
||||||
|
{loading && props.connected && (
|
||||||
|
<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}
|
||||||
|
>
|
||||||
|
Battery service is not available at the moment
|
||||||
|
</Typography>
|
||||||
|
<Typography variant="body2" style={{ color: 'black' }}>
|
||||||
|
Please wait or refresh the page
|
||||||
|
</Typography>
|
||||||
|
</Container>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{!loading && props.connected && (
|
||||||
|
<Container maxWidth="xl">
|
||||||
|
<TableContainer
|
||||||
|
component={Paper}
|
||||||
|
sx={{
|
||||||
|
marginTop: '20px',
|
||||||
|
marginBottom: '20px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Table sx={{ minWidth: 250 }} aria-label="simple table">
|
||||||
|
<TableHead>
|
||||||
|
<TableRow>
|
||||||
|
<TableCell align="center">Pv</TableCell>
|
||||||
|
<TableCell align="center">Power</TableCell>
|
||||||
|
<TableCell align="center">Voltage</TableCell>
|
||||||
|
<TableCell align="center">Current</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
</TableHead>
|
||||||
|
<TableBody>
|
||||||
|
{sortedPvView.map((pv) => (
|
||||||
|
<TableRow
|
||||||
|
key={pv.PvId}
|
||||||
|
style={{
|
||||||
|
height: '10px'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TableCell
|
||||||
|
component="th"
|
||||||
|
scope="row"
|
||||||
|
align="center"
|
||||||
|
sx={{ width: '10%', fontWeight: 'bold', color: 'black' }}
|
||||||
|
>
|
||||||
|
{'String ' + pv.PvId}
|
||||||
|
</TableCell>
|
||||||
|
|
||||||
|
<TableCell
|
||||||
|
sx={{
|
||||||
|
width: '10%',
|
||||||
|
textAlign: 'center',
|
||||||
|
backgroundColor:
|
||||||
|
pv.Current.value == 0 ? '#FF033E' : '#32CD32',
|
||||||
|
color: pv.Power.value === '' ? 'white' : 'inherit'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{pv.Power.value + ' ' + pv.Power.unit}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
sx={{
|
||||||
|
width: '10%',
|
||||||
|
textAlign: 'center',
|
||||||
|
|
||||||
|
backgroundColor:
|
||||||
|
pv.Current.value == 0 ? '#FF033E' : '#32CD32',
|
||||||
|
color: pv.Voltage.value === '' ? 'white' : 'inherit'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{pv.Voltage.value + ' ' + pv.Voltage.unit}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell
|
||||||
|
sx={{
|
||||||
|
width: '10%',
|
||||||
|
textAlign: 'center',
|
||||||
|
backgroundColor:
|
||||||
|
pv.Current.value == 0 ? '#FF033E' : '#32CD32',
|
||||||
|
color: pv.Current.value === '' ? 'white' : 'inherit'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{pv.Current.value + ' ' + pv.Current.unit}
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</TableContainer>
|
||||||
|
</Container>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PvView;
|
|
@ -1,5 +1,3 @@
|
||||||
import { ConfigurationValues } from '../content/dashboards/Log/graph.util';
|
|
||||||
|
|
||||||
export interface I_S3Credentials {
|
export interface I_S3Credentials {
|
||||||
s3Region: string;
|
s3Region: string;
|
||||||
s3Provider: string;
|
s3Provider: string;
|
||||||
|
@ -20,8 +18,9 @@ export interface ErrorMessage {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Action {
|
export interface Action {
|
||||||
configuration: ConfigurationValues;
|
id: number;
|
||||||
date: string;
|
userName: string;
|
||||||
time: string;
|
installationId: number;
|
||||||
user: string;
|
timestamp: string;
|
||||||
|
description: String;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue