Update frontend to support fast search in salidomo.
Also, the user can sort based on status and action flag Update aggregator for Salidomo so that it uses json
This commit is contained in:
parent
41ca486edb
commit
96359fab08
|
|
@ -137,9 +137,6 @@ public static class Aggregator
|
|||
var jsonObject = JObject.Parse(jsonData);
|
||||
|
||||
//Console.WriteLine(jsonObject);
|
||||
// Console.WriteLine(jsonObject["GridMeter"]);
|
||||
|
||||
|
||||
if (jsonObject["Battery"] != null && jsonObject["Battery"]["Soc"] != null)
|
||||
{
|
||||
batterySoc.Add((double)jsonObject["Battery"]["Soc"]);
|
||||
|
|
@ -166,86 +163,11 @@ public static class Aggregator
|
|||
Console.WriteLine("power import is "+jsonObject["GridMeter"]["ActivePowerImportT3"]);
|
||||
gridPowerImport.Add((double)jsonObject["GridMeter"]["ActivePowerImportT3"]);
|
||||
}
|
||||
if (jsonObject["Battery"] != null && jsonObject["Battery"]["HeatingPower"] != null)
|
||||
{
|
||||
heatingPower.Add((double)jsonObject["Battery"]["HeatingPower"]);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine($"Failed to parse JSON file {jsonFile}: {e.Message}");
|
||||
}
|
||||
|
||||
|
||||
// using var reader = new StreamReader(jsonFile);
|
||||
//
|
||||
// while (!reader.EndOfStream)
|
||||
// {
|
||||
//
|
||||
// var line = reader.ReadLine();
|
||||
// var lines = line?.Split(';');
|
||||
//
|
||||
// // Assuming there are always three columns (variable name and its value)
|
||||
// if (lines is { Length: 3 })
|
||||
// {
|
||||
// var variableName = lines[0].Trim();
|
||||
//
|
||||
// if (TryParse(lines[1].Trim(), out var value))
|
||||
// {
|
||||
// switch (variableName)
|
||||
// {
|
||||
// case "/Battery/Soc":
|
||||
// batterySoc.Add(value);
|
||||
// break;
|
||||
//
|
||||
// case "/PvOnDc/DcWh" :
|
||||
// pvPowerSum.Add(value);
|
||||
// break;
|
||||
//
|
||||
// case "/Battery/Dc/Power":
|
||||
//
|
||||
// if (value < 0)
|
||||
// {
|
||||
// batteryDischargePower.Add(value);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// batteryChargePower.Add(value);
|
||||
//
|
||||
// }
|
||||
// break;
|
||||
//
|
||||
// case "/GridMeter/ActivePowerExportT3":
|
||||
// // we are using different register to check which value from the grid meter we need to use
|
||||
// // At the moment register 8002 amd 8012. in KWh
|
||||
// gridPowerExport.Add(value);
|
||||
// break;
|
||||
// case "/GridMeter/ActivePowerImportT3":
|
||||
// gridPowerImport.Add(value);
|
||||
// break;
|
||||
// case "/Battery/HeatingPower":
|
||||
// heatingPower.Add(value);
|
||||
// break;
|
||||
// // Add more cases as needed
|
||||
// default:
|
||||
// // Code to execute when variableName doesn't match any condition
|
||||
// break;
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// //Handle cases where variableValue is not a valid number
|
||||
// // Console.WriteLine(
|
||||
// // $"Invalid numeric value for variable {variableName}:{lines[1].Trim()}");
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // Handle invalid column format
|
||||
// //Console.WriteLine("Invalid format in column");
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -262,7 +184,6 @@ public static class Aggregator
|
|||
|
||||
var dischargingEnergy = (batteryDischargePower.Any() ? batteryDischargePower.Average() : 0.0) / 3600;
|
||||
var chargingEnergy = (batteryChargePower.Any() ? batteryChargePower.Average() : 0.0) / 3600;
|
||||
var heatingPowerAvg = (heatingPower.Any() ? heatingPower.Average() : 0.0) / 3600;
|
||||
|
||||
var dMaxSoc = batterySoc.Any() ? batterySoc.Max() : 0.0;
|
||||
var dMinSoc = batterySoc.Any() ? batterySoc.Min() : 0.0;
|
||||
|
|
@ -280,7 +201,7 @@ public static class Aggregator
|
|||
GridExportPower = dSumGridExportPower,
|
||||
GridImportPower = dSumGridImportPower,
|
||||
PvPower = dSumPvPower,
|
||||
HeatingPower = heatingPowerAvg
|
||||
HeatingPower = 0
|
||||
};
|
||||
|
||||
// Print the stored JSON data for verification
|
||||
|
|
|
|||
|
|
@ -1,8 +1,13 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Card,
|
||||
CircularProgress,
|
||||
FormControl,
|
||||
Grid,
|
||||
InputAdornment,
|
||||
InputLabel,
|
||||
MenuItem,
|
||||
Select,
|
||||
styled,
|
||||
Table,
|
||||
TableBody,
|
||||
|
|
@ -10,6 +15,7 @@ import {
|
|||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
TextField,
|
||||
Typography,
|
||||
useTheme
|
||||
} from '@mui/material';
|
||||
|
|
@ -19,42 +25,23 @@ import { useLocation, useNavigate } from 'react-router-dom';
|
|||
import routes from '../../../Resources/routes.json';
|
||||
import CancelIcon from '@mui/icons-material/Cancel';
|
||||
import BuildIcon from '@mui/icons-material/Build';
|
||||
import SearchTwoToneIcon from '@mui/icons-material/SearchTwoTone';
|
||||
|
||||
interface FlatInstallationViewProps {
|
||||
installations: I_Installation[];
|
||||
}
|
||||
|
||||
const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
||||
// const webSocketContext = useContext(WebSocketContext);
|
||||
// const { getSortedInstallations } = webSocketContext;
|
||||
const navigate = useNavigate();
|
||||
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
|
||||
const currentLocation = useLocation();
|
||||
//
|
||||
const sortedInstallations = [...props.installations].sort((a, b) => {
|
||||
// Compare the status field of each installation and sort them based on the status.
|
||||
//Installations with alarms go first
|
||||
let a_status = a.status;
|
||||
let b_status = b.status;
|
||||
|
||||
if (a_status > b_status) {
|
||||
return -1;
|
||||
}
|
||||
if (a_status < b_status) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
// const sortedInstallations = useMemo(() => {
|
||||
// return [...props.installations].sort((a, b) => {
|
||||
// const a_status = getStatus(a.id) || 0;
|
||||
// const b_status = getStatus(b.id) || 0;
|
||||
// return b_status - a_status;
|
||||
// });
|
||||
// }, [props.installations, getStatus]);
|
||||
|
||||
// const sortedInstallations = getSortedInstallations();
|
||||
const BATCH_SIZE = 50;
|
||||
const [visibleCount, setVisibleCount] = useState(BATCH_SIZE);
|
||||
const observerRef = useRef<IntersectionObserver | null>(null);
|
||||
const loadMoreRef = useRef<HTMLDivElement>(null);
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [sortByStatus, setSortByStatus] = useState('All Installations');
|
||||
const [sortByAction, setSortByAction] = useState('All Installations');
|
||||
|
||||
const handleSelectOneInstallation = (installationID: number): void => {
|
||||
if (selectedInstallation != installationID) {
|
||||
|
|
@ -86,265 +73,454 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
|
|||
}
|
||||
}));
|
||||
|
||||
const indexedData = useMemo(() => {
|
||||
return props.installations.map((item) => ({
|
||||
...item,
|
||||
nameLower: item.name.toLowerCase(),
|
||||
locationLower: item.location.toLowerCase(),
|
||||
regionLower: item.region.toLowerCase()
|
||||
}));
|
||||
}, [props.installations]);
|
||||
|
||||
const sortedInstallations = useMemo(() => {
|
||||
let filtered = indexedData.filter(
|
||||
(item) =>
|
||||
item.nameLower.includes(searchTerm.toLowerCase()) ||
|
||||
item.locationLower.includes(searchTerm.toLowerCase()) ||
|
||||
item.regionLower.includes(searchTerm.toLowerCase())
|
||||
);
|
||||
|
||||
// Apply the 'showOnly' filter
|
||||
switch (sortByStatus) {
|
||||
case 'Installations With Alarm':
|
||||
filtered = filtered.filter((i) => i.status === 2);
|
||||
break;
|
||||
case 'Installations with Warning':
|
||||
filtered = filtered.filter((i) => i.status === 1);
|
||||
break;
|
||||
case 'Functional Installations':
|
||||
filtered = filtered.filter((i) => i.status === 0);
|
||||
break;
|
||||
case 'Offline Installations':
|
||||
filtered = filtered.filter((i) => i.status === -1);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (sortByAction) {
|
||||
case 'Installations With Action Flag':
|
||||
filtered = filtered.filter((i) => i.testingMode === true);
|
||||
break;
|
||||
case 'Installations Without Action Flag':
|
||||
filtered = filtered.filter((i) => i.testingMode === false);
|
||||
break;
|
||||
}
|
||||
|
||||
// Sort by status (alarms first)
|
||||
return filtered.sort((a, b) => {
|
||||
const a_status = a.status;
|
||||
const b_status = b.status;
|
||||
|
||||
if (a_status > b_status) return -1;
|
||||
if (a_status < b_status) return 1;
|
||||
return 0;
|
||||
});
|
||||
}, [searchTerm, indexedData, sortByAction, sortByStatus]);
|
||||
|
||||
useEffect(() => {
|
||||
if (observerRef.current) {
|
||||
observerRef.current.disconnect();
|
||||
}
|
||||
|
||||
observerRef.current = new IntersectionObserver(
|
||||
(entries) => {
|
||||
if (entries[0].isIntersecting) {
|
||||
setVisibleCount((prev) => prev + BATCH_SIZE);
|
||||
}
|
||||
},
|
||||
{
|
||||
rootMargin: '600px', // triggers before the element fully enters view
|
||||
threshold: 0.5 // triggers when 10% of it is visible
|
||||
}
|
||||
);
|
||||
|
||||
if (loadMoreRef.current) {
|
||||
observerRef.current.observe(loadMoreRef.current);
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (observerRef.current) {
|
||||
observerRef.current.disconnect();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Grid container spacing={1} sx={{ marginTop: 0.1 }}>
|
||||
<Grid
|
||||
item
|
||||
sx={{
|
||||
display:
|
||||
currentLocation.pathname ===
|
||||
routes.salidomo_installations + 'list' ||
|
||||
currentLocation.pathname ===
|
||||
routes.salidomo_installations + routes.list
|
||||
? 'block'
|
||||
: 'none'
|
||||
}}
|
||||
>
|
||||
<Card>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<FormattedMessage id="name" defaultMessage="Name" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="location" defaultMessage="Location" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="region" defaultMessage="Region" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="country" defaultMessage="Country" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="VRM Link" defaultMessage="VRM Link" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="Device" defaultMessage="Device" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="status" defaultMessage="Status" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{sortedInstallations
|
||||
// .filter(
|
||||
// (installation) =>
|
||||
// installation.status === -1 &&
|
||||
// installation.testingMode == false
|
||||
// )
|
||||
.map((installation) => {
|
||||
const isInstallationSelected =
|
||||
installation.id === selectedInstallation;
|
||||
<>
|
||||
<Grid container spacing={1}>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
md={6}
|
||||
sx={{
|
||||
display:
|
||||
currentLocation.pathname ===
|
||||
routes.salidomo_installations + 'list' ||
|
||||
currentLocation.pathname ===
|
||||
routes.salidomo_installations + routes.list
|
||||
? 'block'
|
||||
: 'none'
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: '16px', // spacing between elements
|
||||
width: '100%'
|
||||
}}
|
||||
>
|
||||
<FormControl sx={{ flex: 1 }}>
|
||||
<TextField
|
||||
placeholder="Search"
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
fullWidth
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchTwoToneIcon />
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
|
||||
const status = installation.status;
|
||||
<FormControl sx={{ width: 240 }}>
|
||||
<InputLabel>
|
||||
<FormattedMessage
|
||||
id="sortByStatus"
|
||||
defaultMessage="Sort By Status"
|
||||
/>
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={sortByStatus}
|
||||
onChange={(e) => setSortByStatus(e.target.value)}
|
||||
label="Show Only"
|
||||
>
|
||||
{[
|
||||
'All Installations',
|
||||
'Installations With Alarm',
|
||||
'Installations with Warning',
|
||||
'Functional Installations',
|
||||
'Offline Installations'
|
||||
].map((type) => (
|
||||
<MenuItem key={type} value={type}>
|
||||
{type}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
|
||||
return (
|
||||
<HoverableTableRow
|
||||
key={installation.id}
|
||||
onClick={() =>
|
||||
handleSelectOneInstallation(installation.id)
|
||||
}
|
||||
>
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
{installation.name}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<FormControl sx={{ width: 240 }}>
|
||||
<InputLabel>
|
||||
<FormattedMessage
|
||||
id="sortByActionFlag"
|
||||
defaultMessage="Sort By Action Flag"
|
||||
/>
|
||||
</InputLabel>
|
||||
<Select
|
||||
value={sortByAction}
|
||||
onChange={(e) => setSortByAction(e.target.value)}
|
||||
label="Show Only"
|
||||
>
|
||||
{[
|
||||
'All Installations',
|
||||
'Installations With Action Flag',
|
||||
'Installations Without Action Flag'
|
||||
].map((type) => (
|
||||
<MenuItem key={type} value={type}>
|
||||
{type}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
{installation.location}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<Grid container spacing={1} sx={{ marginTop: 0.1 }}>
|
||||
<Grid
|
||||
item
|
||||
sx={{
|
||||
display:
|
||||
currentLocation.pathname ===
|
||||
routes.salidomo_installations + 'list' ||
|
||||
currentLocation.pathname ===
|
||||
routes.salidomo_installations + routes.list
|
||||
? 'block'
|
||||
: 'none'
|
||||
}}
|
||||
>
|
||||
<Card>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>
|
||||
<FormattedMessage id="name" defaultMessage="Name" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage
|
||||
id="location"
|
||||
defaultMessage="Location"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="region" defaultMessage="Region" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="country" defaultMessage="Country" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage
|
||||
id="VRM Link"
|
||||
defaultMessage="VRM Link"
|
||||
/>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="Device" defaultMessage="Device" />
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<FormattedMessage id="status" defaultMessage="Status" />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{sortedInstallations
|
||||
.slice(0, visibleCount)
|
||||
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
{installation.region}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
// .filter(
|
||||
// (installation) =>
|
||||
// installation.status === -1 &&
|
||||
// installation.testingMode == false
|
||||
// )
|
||||
.map((installation) => {
|
||||
const isInstallationSelected =
|
||||
installation.id === selectedInstallation;
|
||||
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
{installation.country}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
const status = installation.status;
|
||||
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
<a
|
||||
href={
|
||||
'https://vrm.victronenergy.com/installation/' +
|
||||
installation.vrmLink +
|
||||
'/dashboard'
|
||||
}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{
|
||||
display: 'inline-block',
|
||||
padding: '0'
|
||||
}} // Style the link
|
||||
onClick={(e) => e.stopPropagation()} // Prevent the click event from bubbling up to the table row
|
||||
return (
|
||||
<HoverableTableRow
|
||||
key={installation.id}
|
||||
onClick={() =>
|
||||
handleSelectOneInstallation(installation.id)
|
||||
}
|
||||
>
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
VRM link
|
||||
</a>
|
||||
</Typography>
|
||||
</TableCell>
|
||||
{installation.name}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginLeft: '5px'
|
||||
}}
|
||||
>
|
||||
{installation.device === 1 ? (
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
Cerbo
|
||||
</Typography>
|
||||
) : installation.device === 2 ? (
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
Venus
|
||||
</Typography>
|
||||
) : (
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
Device not specified
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
{installation.location}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginLeft: '15px'
|
||||
}}
|
||||
>
|
||||
{status === -1 ? (
|
||||
<CancelIcon
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
{installation.region}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
{installation.country}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
<a
|
||||
href={
|
||||
'https://vrm.victronenergy.com/installation/' +
|
||||
installation.vrmLink +
|
||||
'/dashboard'
|
||||
}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
style={{
|
||||
width: '23px',
|
||||
height: '23px',
|
||||
color: 'red',
|
||||
borderRadius: '50%'
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
{status === -2 ? (
|
||||
<CircularProgress
|
||||
size={20}
|
||||
sx={{
|
||||
color: '#f7b34d'
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
display: 'inline-block',
|
||||
padding: '0'
|
||||
}} // Style the link
|
||||
onClick={(e) => e.stopPropagation()} // Prevent the click event from bubbling up to the table row
|
||||
>
|
||||
VRM link
|
||||
</a>
|
||||
</Typography>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<div
|
||||
style={{
|
||||
width: '20px',
|
||||
height: '20px',
|
||||
marginLeft: '2px',
|
||||
borderRadius: '50%',
|
||||
backgroundColor:
|
||||
status === 2
|
||||
? 'red'
|
||||
: status === 1
|
||||
? 'orange'
|
||||
: status === -1 || status === -2
|
||||
? 'transparent'
|
||||
: 'green'
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginLeft: '5px'
|
||||
}}
|
||||
/>
|
||||
{installation.testingMode && (
|
||||
<BuildIcon
|
||||
>
|
||||
{installation.device === 1 ? (
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
Cerbo
|
||||
</Typography>
|
||||
) : installation.device === 2 ? (
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
Venus
|
||||
</Typography>
|
||||
) : (
|
||||
<Typography
|
||||
variant="body2"
|
||||
fontWeight="bold"
|
||||
color="text.primary"
|
||||
gutterBottom
|
||||
noWrap
|
||||
sx={{ marginTop: '10px', fontSize: 'small' }}
|
||||
>
|
||||
Device not specified
|
||||
</Typography>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
|
||||
<TableCell>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
marginLeft: '15px'
|
||||
}}
|
||||
>
|
||||
{status === -1 ? (
|
||||
<CancelIcon
|
||||
style={{
|
||||
width: '23px',
|
||||
height: '23px',
|
||||
color: 'red',
|
||||
borderRadius: '50%'
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
{status === -2 ? (
|
||||
<CircularProgress
|
||||
size={20}
|
||||
sx={{
|
||||
color: '#f7b34d'
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
|
||||
<div
|
||||
style={{
|
||||
width: '23px',
|
||||
height: '23px',
|
||||
color: 'purple',
|
||||
width: '20px',
|
||||
height: '20px',
|
||||
marginLeft: '2px',
|
||||
borderRadius: '50%',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
marginLeft: status != -1 ? '25px' : '0px'
|
||||
backgroundColor:
|
||||
status === 2
|
||||
? 'red'
|
||||
: status === 1
|
||||
? 'orange'
|
||||
: status === -1 || status === -2
|
||||
? 'transparent'
|
||||
: 'green'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
</HoverableTableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Card>
|
||||
{installation.testingMode && (
|
||||
<BuildIcon
|
||||
style={{
|
||||
width: '23px',
|
||||
height: '23px',
|
||||
color: 'purple',
|
||||
borderRadius: '50%',
|
||||
position: 'relative',
|
||||
zIndex: 1,
|
||||
marginLeft: status != -1 ? '25px' : '0px'
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</TableCell>
|
||||
</HoverableTableRow>
|
||||
);
|
||||
})}
|
||||
<TableRow>
|
||||
<TableCell colSpan={7} align="center">
|
||||
<div ref={loadMoreRef} style={{ height: '40px' }} />
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Card>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
import React, { useMemo, useState } from 'react';
|
||||
import { FormControl, Grid, InputAdornment, TextField } from '@mui/material';
|
||||
import SearchTwoToneIcon from '@mui/icons-material/SearchTwoTone';
|
||||
import React from 'react';
|
||||
import FlatInstallationView from './FlatInstallationView';
|
||||
import { I_Installation } from '../../../interfaces/InstallationTypes';
|
||||
import { Route, Routes, useLocation } from 'react-router-dom';
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import routes from '../../../Resources/routes.json';
|
||||
import SalidomoInstallation from './Installation';
|
||||
|
||||
|
|
@ -12,74 +10,11 @@ interface installationSearchProps {
|
|||
}
|
||||
|
||||
function InstallationSearch(props: installationSearchProps) {
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const currentLocation = useLocation();
|
||||
// const [filteredData, setFilteredData] = useState(props.installations);
|
||||
|
||||
const indexedData = useMemo(() => {
|
||||
return props.installations.map((item) => ({
|
||||
...item,
|
||||
nameLower: item.name.toLowerCase(),
|
||||
locationLower: item.location.toLowerCase(),
|
||||
regionLower: item.region.toLowerCase()
|
||||
}));
|
||||
}, [props.installations]);
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
return indexedData.filter(
|
||||
(item) =>
|
||||
item.nameLower.includes(searchTerm.toLowerCase()) ||
|
||||
item.locationLower.includes(searchTerm.toLowerCase()) ||
|
||||
item.regionLower.includes(searchTerm.toLowerCase())
|
||||
);
|
||||
}, [searchTerm, indexedData]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Grid container>
|
||||
<Grid
|
||||
item
|
||||
xs={12}
|
||||
md={6}
|
||||
sx={{
|
||||
display:
|
||||
currentLocation.pathname ===
|
||||
routes.salidomo_installations + 'list' ||
|
||||
currentLocation.pathname ===
|
||||
routes.salidomo_installations + routes.list
|
||||
? 'block'
|
||||
: 'none'
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
alignItems: 'flex-start'
|
||||
}}
|
||||
>
|
||||
<FormControl variant="outlined">
|
||||
<TextField
|
||||
placeholder="Search"
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
fullWidth
|
||||
InputProps={{
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">
|
||||
<SearchTwoToneIcon />
|
||||
</InputAdornment>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</FormControl>
|
||||
</div>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<FlatInstallationView installations={filteredData} />
|
||||
<FlatInstallationView installations={props.installations} />
|
||||
<Routes>
|
||||
{filteredData.map((installation) => {
|
||||
{props.installations.map((installation) => {
|
||||
return (
|
||||
<Route
|
||||
key={installation.id}
|
||||
|
|
|
|||
Loading…
Reference in New Issue