make allow access to singel installation more easier to find

This commit is contained in:
Yinyin Liu 2026-03-28 18:29:36 +01:00
parent be264c2165
commit dc5b09d1f2
5 changed files with 48 additions and 28 deletions

View File

@ -3,10 +3,12 @@ import React, {
useCallback,
useContext,
useEffect,
useMemo,
useState
} from 'react';
import {
Alert,
Autocomplete,
Box,
Container,
Divider,
@ -19,6 +21,7 @@ import {
MenuItem,
Modal,
Select,
TextField,
Typography,
useTheme
} from '@mui/material';
@ -41,6 +44,16 @@ import {
} from '../../../interfaces/InstallationTypes';
import axiosConfig from '../../../Resources/axiosConfig';
const PRODUCT_GROUP_ORDER: number[] = [2, 5, 4, 3, 0, 1];
const PRODUCT_NAMES: Record<number, string> = {
0: 'Salimax',
1: 'Salidomo',
2: 'Sodistore Home',
3: 'Sodistore Max',
4: 'Sodistore Grid',
5: 'Sodistore Pro'
};
interface UserAccessProps {
current_user: InnovEnergyUser;
}
@ -57,16 +70,24 @@ function UserAccess(props: UserAccessProps) {
const context = useContext(UserContext);
const { currentUser } = context;
const [openFolder, setOpenFolder] = useState(false);
const [openInstallation, setOpenInstallation] = useState(false);
const [openModal, setOpenModal] = useState(false);
const [selectedFolderNames, setSelectedFolderNames] = useState<string[]>([]);
const [selectedInstallationNames, setSelectedInstallationNames] = useState<string[]>([]);
const [selectedInstallations, setSelectedInstallations] = useState<I_Installation[]>([]);
// Available choices for grant modal
const [availableFolders, setAvailableFolders] = useState<I_Folder[]>([]);
const [availableInstallations, setAvailableInstallations] = useState<I_Installation[]>([]);
const sortedInstallations = useMemo(() => {
const orderMap = new Map(PRODUCT_GROUP_ORDER.map((p, i) => [p, i]));
return [...availableInstallations].sort((a, b) => {
const oa = orderMap.get(a.product) ?? 99;
const ob = orderMap.get(b.product) ?? 99;
return oa !== ob ? oa - ob : a.name.localeCompare(b.name);
});
}, [availableInstallations]);
// Direct grants for this user
const [directFolders, setDirectFolders] = useState<{ id: number; name: string }[]>([]);
const [directInstallations, setDirectInstallations] = useState<{ id: number; name: string }[]>([]);
@ -130,7 +151,7 @@ function UserAccess(props: UserAccessProps) {
fetchAvailableInstallations();
setOpenModal(true);
setSelectedFolderNames([]);
setSelectedInstallationNames([]);
setSelectedInstallations([]);
};
const handleRevokeFolder = async (folderId: number, folderName: string) => {
@ -178,8 +199,7 @@ function UserAccess(props: UserAccessProps) {
});
}
for (const installationName of selectedInstallationNames) {
const installation = availableInstallations.find((i) => i.name === installationName);
for (const installation of selectedInstallations) {
await axiosConfig
.post(`/GrantUserAccessToInstallation?UserId=${props.current_user.id}&InstallationId=${installation.id}`)
.then(() => {
@ -264,31 +284,27 @@ function UserAccess(props: UserAccessProps) {
</div>
<div>
<FormControl fullWidth sx={{ marginTop: 2, width: 390 }}>
<InputLabel sx={{ fontSize: 14, backgroundColor: 'white' }}>
<FormattedMessage id="grantAccessToInstallations" defaultMessage="Grant access to installations" />
</InputLabel>
<Select
<FormControl fullWidth sx={{ marginTop: 1, width: 390 }}>
<Autocomplete<I_Installation, true, false, false>
multiple
value={selectedInstallationNames}
onChange={(e) => setSelectedInstallationNames(e.target.value as string[])}
open={openInstallation}
onClose={() => setOpenInstallation(false)}
onOpen={() => setOpenInstallation(true)}
renderValue={(selected) => (
<div>{selected.map((i) => <span key={i}>{i}, </span>)}</div>
options={sortedInstallations}
groupBy={(option) => PRODUCT_NAMES[option.product] || 'Unknown'}
getOptionLabel={(option) => option.name}
value={selectedInstallations}
onChange={(_event, newValue) => setSelectedInstallations(newValue)}
isOptionEqualToValue={(option, value) => option.id === value.id}
renderInput={(params) => (
<TextField
{...params}
label={intl.formatMessage({ id: 'grantAccessToInstallations' })}
placeholder={intl.formatMessage({ id: 'searchInstallations' })}
InputLabelProps={{
...params.InputLabelProps,
sx: { fontSize: 14, backgroundColor: 'white' }
}}
/>
)}
>
{availableInstallations.map((installation) => (
<MenuItem key={installation.id} value={installation.name}>{installation.name}</MenuItem>
))}
<Button
sx={{ marginLeft: '150px', marginTop: '10px', backgroundColor: theme.colors.primary.main, color: 'white', '&:hover': { backgroundColor: theme.colors.primary.dark }, padding: '6px 8px' }}
onClick={() => setOpenInstallation(false)}
>
<FormattedMessage id="submit" defaultMessage="Submit" />
</Button>
</Select>
/>
</FormControl>
</div>

View File

@ -120,6 +120,7 @@
"deleteFolder": "Ordner löschen",
"grantAccessToFolders": "Zugriff auf Ordner gewähren",
"grantAccessToInstallations": "Zugriff auf Installationen gewähren",
"searchInstallations": "Installationen suchen...",
"cannotloadloggingdata": "Log Daten können nicht geladen werden",
"grantedAccessToUsers": "Den Benutzern wurde den Zugriff gewährt",
"unableToGrantAccess": "Der Zugriff kann nicht gewährt werden",

View File

@ -102,6 +102,7 @@
"deleteFolder": "Delete Folder",
"grantAccessToFolders": "Grant Access to Folders",
"grantAccessToInstallations": "Grant Access to Installations",
"searchInstallations": "Search installations...",
"cannotloadloggingdata": "Cannot load logging data",
"grantedAccessToUsers": "Granted access to users: ",
"unableToGrantAccess": "Unable to grant access to: ",

View File

@ -114,6 +114,7 @@
"deleteFolder": "Supprimer le dossier",
"grantAccessToFolders": "Accorder l'accès aux dossiers",
"grantAccessToInstallations": "Accorder l'accès aux installations",
"searchInstallations": "Rechercher des installations...",
"cannotloadloggingdata": "Impossible de charger les données de journalisation",
"grantedAccessToUsers": "Accès accordé aux utilisateurs",
"unableToGrantAccess": "Impossible d'accorder l'accès à",

View File

@ -102,6 +102,7 @@
"deleteFolder": "Elimina cartella",
"grantAccessToFolders": "Concedi accesso alle cartelle",
"grantAccessToInstallations": "Concedi accesso alle installazioni",
"searchInstallations": "Cerca installazioni...",
"cannotloadloggingdata": "Impossibile caricare i dati di registro",
"grantedAccessToUsers": "Accesso concesso agli utenti: ",
"unableToGrantAccess": "Impossibile concedere l'accesso a: ",