add filters to fast search and disable data collection installations go bottom

This commit is contained in:
Yinyin Liu 2026-04-16 14:21:24 +02:00
parent 3fbb2eeee0
commit 4a6caa9ed3
5 changed files with 166 additions and 73 deletions

View File

@ -96,8 +96,12 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
break; break;
} }
// Sort by status (alarms first) // Sort by status (alarms first); data-collection-disabled sinks below offline.
return filtered.sort((a, b) => { return filtered.sort((a, b) => {
const aDisabled = a.dataCollectionEnabled === false;
const bDisabled = b.dataCollectionEnabled === false;
if (aDisabled !== bDisabled) return aDisabled ? 1 : -1;
const a_status = a.status; const a_status = a.status;
const b_status = b.status; const b_status = b.status;

View File

@ -1,4 +1,4 @@
import React, { useState } from 'react'; import React, { useMemo, useState } from 'react';
import { import {
Card, Card,
CircularProgress, CircularProgress,
@ -31,34 +31,40 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
const [selectedInstallation, setSelectedInstallation] = useState<number>(-1); const [selectedInstallation, setSelectedInstallation] = useState<number>(-1);
const currentLocation = useLocation(); const currentLocation = useLocation();
const baseRoute = props.product === 5 ? routes.sodistorepro_installations : routes.sodiohome_installations; const baseRoute = props.product === 5 ? routes.sodistorepro_installations : routes.sodiohome_installations;
//
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) { const sortedInstallations = useMemo(() => {
return -1; return [...props.installations].sort((a, b) => {
} // Data-collection-disabled installations sink below everything (even offline).
if (a_status < b_status) { const aDisabled = a.dataCollectionEnabled === false;
return 1; const bDisabled = b.dataCollectionEnabled === false;
} if (aDisabled !== bDisabled) return aDisabled ? 1 : -1;
// Then sort by status (alarms first)
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; return 0;
}); });
}, [props.installations]);
const handleSelectOneInstallation = (installationID: number): void => { const handleSelectOneInstallation = (installationID: number): void => {
if (selectedInstallation != installationID) { if (selectedInstallation != installationID) {
setSelectedInstallation(installationID); setSelectedInstallation(installationID);
setSelectedInstallation(-1); setSelectedInstallation(-1);
const target = props.installations.find((i) => i.id === installationID);
const landingTab =
target?.dataCollectionEnabled === false ? routes.information : routes.live;
navigate( navigate(
baseRoute + baseRoute +
routes.list + routes.list +
routes.installation + routes.installation +
`${installationID}` + `${installationID}` +
'/' + '/' +
routes.live, landingTab,
{ {
replace: true replace: true
} }
@ -77,18 +83,16 @@ const FlatInstallationView = (props: FlatInstallationViewProps) => {
} }
})); }));
const isListView =
currentLocation.pathname === baseRoute + 'list' ||
currentLocation.pathname === baseRoute + routes.list;
return ( return (
<Grid container spacing={1} sx={{ marginTop: 0.1 }}> <Grid container spacing={1} sx={{ marginTop: 0.1 }}>
<Grid <Grid
item item
sx={{ sx={{
display: display: isListView ? 'block' : 'none'
currentLocation.pathname ===
baseRoute + 'list' ||
currentLocation.pathname ===
baseRoute + routes.list
? 'block'
: 'none'
}} }}
> >
<Card> <Card>

View File

@ -489,12 +489,14 @@ function SodioHomeInstallation(props: singleInstallationProps) {
</div> </div>
</div> </div>
{loading && {loading &&
!dataCollectionDisabled &&
currentTab != 'information' && currentTab != 'information' &&
// currentTab != 'manage' && // currentTab != 'manage' &&
currentTab != 'history' && currentTab != 'history' &&
currentTab != 'log' && currentTab != 'log' &&
currentTab != 'report' && currentTab != 'report' &&
currentTab != 'installationTickets' && ( currentTab != 'installationTickets' &&
currentTab != 'documents' && (
<Container <Container
maxWidth="xl" maxWidth="xl"
sx={{ sx={{
@ -670,7 +672,7 @@ function SodioHomeInstallation(props: singleInstallationProps) {
<Route <Route
path={'*'} path={'*'}
element={<Navigate to={routes.live}></Navigate>} element={<Navigate to={dataCollectionDisabled ? routes.information : routes.live}></Navigate>}
/> />
</Routes> </Routes>
</Grid> </Grid>

View File

@ -1,7 +1,15 @@
import React, { useMemo, useState } from 'react'; import React, { useMemo, useState } from 'react';
import { FormControl, Grid, InputAdornment, TextField } from '@mui/material'; import {
FormControl,
Grid,
InputAdornment,
InputLabel,
MenuItem,
Select,
TextField
} from '@mui/material';
import SearchTwoToneIcon from '@mui/icons-material/SearchTwoTone'; import SearchTwoToneIcon from '@mui/icons-material/SearchTwoTone';
import { useIntl } from 'react-intl'; import { FormattedMessage, useIntl } from 'react-intl';
import { I_Installation } from '../../../interfaces/InstallationTypes'; import { I_Installation } from '../../../interfaces/InstallationTypes';
import { Route, Routes, useLocation } from 'react-router-dom'; import { Route, Routes, useLocation } from 'react-router-dom';
import routes from '../../../Resources/routes.json'; import routes from '../../../Resources/routes.json';
@ -16,9 +24,10 @@ interface installationSearchProps {
function InstallationSearch(props: installationSearchProps) { function InstallationSearch(props: installationSearchProps) {
const intl = useIntl(); const intl = useIntl();
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [sortByStatus, setSortByStatus] = useState('All Installations');
const [sortByAction, setSortByAction] = useState('All Installations');
const currentLocation = useLocation(); const currentLocation = useLocation();
const baseRoute = props.product === 5 ? routes.sodistorepro_installations : routes.sodiohome_installations; const baseRoute = props.product === 5 ? routes.sodistorepro_installations : routes.sodiohome_installations;
// const [filteredData, setFilteredData] = useState(props.installations);
const indexedData = useMemo(() => { const indexedData = useMemo(() => {
return props.installations.map((item) => ({ return props.installations.map((item) => ({
@ -30,39 +39,63 @@ function InstallationSearch(props: installationSearchProps) {
}, [props.installations]); }, [props.installations]);
const filteredData = useMemo(() => { const filteredData = useMemo(() => {
return indexedData.filter( let list = indexedData.filter(
(item) => (item) =>
item.nameLower.includes(searchTerm.toLowerCase()) || item.nameLower.includes(searchTerm.toLowerCase()) ||
item.locationLower.includes(searchTerm.toLowerCase()) || item.locationLower.includes(searchTerm.toLowerCase()) ||
item.regionLower.includes(searchTerm.toLowerCase()) item.regionLower.includes(searchTerm.toLowerCase())
); );
}, [searchTerm, indexedData]);
switch (sortByStatus) {
case 'Installations With Alarm':
list = list.filter((i) => i.status === 2);
break;
case 'Installations with Warning':
list = list.filter((i) => i.status === 1);
break;
case 'Functional Installations':
list = list.filter((i) => i.status === 0);
break;
case 'Offline Installations':
list = list.filter((i) => i.status === -1);
break;
case 'Installations Without Data Collection':
list = list.filter((i) => i.dataCollectionEnabled === false);
break;
}
switch (sortByAction) {
case 'Installations With Action Flag':
list = list.filter((i) => i.testingMode === true);
break;
case 'Installations Without Action Flag':
list = list.filter((i) => i.testingMode === false);
break;
}
return list;
}, [searchTerm, indexedData, sortByStatus, sortByAction]);
const isListView =
currentLocation.pathname === baseRoute + 'list' ||
currentLocation.pathname === baseRoute + routes.list;
return ( return (
<> <>
{isListView && (
<Grid container> <Grid container>
<Grid <Grid item xs={12}>
item
xs={12}
md={6}
sx={{
display:
currentLocation.pathname ===
baseRoute + 'list' ||
currentLocation.pathname ===
baseRoute + routes.list
? 'block'
: 'none'
}}
>
<div <div
style={{ style={{
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'row',
alignItems: 'flex-start' alignItems: 'center',
gap: '16px',
width: '100%',
flexWrap: 'wrap'
}} }}
> >
<FormControl variant="outlined"> <FormControl variant="outlined" sx={{ width: 280 }}>
<TextField <TextField
placeholder={intl.formatMessage({ id: 'search' })} placeholder={intl.formatMessage({ id: 'search' })}
value={searchTerm} value={searchTerm}
@ -77,9 +110,55 @@ function InstallationSearch(props: installationSearchProps) {
}} }}
/> />
</FormControl> </FormControl>
<FormControl sx={{ width: 280 }}>
<InputLabel>
<FormattedMessage id="sortByStatus" defaultMessage="Sort By Status" />
</InputLabel>
<Select
value={sortByStatus}
onChange={(e) => setSortByStatus(e.target.value)}
label={intl.formatMessage({ id: 'sortByStatus' })}
>
{[
'All Installations',
'Installations With Alarm',
'Installations with Warning',
'Functional Installations',
'Offline Installations',
'Installations Without Data Collection'
].map((type) => (
<MenuItem key={type} value={type}>
{type}
</MenuItem>
))}
</Select>
</FormControl>
<FormControl sx={{ width: 280 }}>
<InputLabel>
<FormattedMessage id="sortByActionFlag" defaultMessage="Sort By Action Flag" />
</InputLabel>
<Select
value={sortByAction}
onChange={(e) => setSortByAction(e.target.value)}
label={intl.formatMessage({ id: 'sortByActionFlag' })}
>
{[
'All Installations',
'Installations With Action Flag',
'Installations Without Action Flag'
].map((type) => (
<MenuItem key={type} value={type}>
{type}
</MenuItem>
))}
</Select>
</FormControl>
</div> </div>
</Grid> </Grid>
</Grid> </Grid>
)}
<FlatInstallationView installations={filteredData} product={props.product} /> <FlatInstallationView installations={filteredData} product={props.product} />
<Routes> <Routes>

View File

@ -17,12 +17,16 @@ function InstallationTree() {
useContext(InstallationsContext); useContext(InstallationsContext);
const sortedInstallations = [...foldersAndInstallations].sort((a, b) => { const sortedInstallations = [...foldersAndInstallations].sort((a, b) => {
// Compare the status field of each installation and sort them based on the status. // Folders stay on top (existing behavior).
//Installations with alarms go first
if (a.type == 'Folder') { if (a.type == 'Folder') {
return -1; return -1;
} }
// Data-collection-disabled installations sink below everything (even offline).
const aDisabled = (a as any).dataCollectionEnabled === false;
const bDisabled = (b as any).dataCollectionEnabled === false;
if (aDisabled !== bDisabled) return aDisabled ? 1 : -1;
// Then sort by status (alarms first).
let a_status = a.status; let a_status = a.status;
let b_status = b.status; let b_status = b.status;