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, useCallback,
useContext, useContext,
useEffect, useEffect,
useMemo,
useState useState
} from 'react'; } from 'react';
import { import {
Alert, Alert,
Autocomplete,
Box, Box,
Container, Container,
Divider, Divider,
@ -19,6 +21,7 @@ import {
MenuItem, MenuItem,
Modal, Modal,
Select, Select,
TextField,
Typography, Typography,
useTheme useTheme
} from '@mui/material'; } from '@mui/material';
@ -41,6 +44,16 @@ import {
} from '../../../interfaces/InstallationTypes'; } from '../../../interfaces/InstallationTypes';
import axiosConfig from '../../../Resources/axiosConfig'; 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 { interface UserAccessProps {
current_user: InnovEnergyUser; current_user: InnovEnergyUser;
} }
@ -57,16 +70,24 @@ function UserAccess(props: UserAccessProps) {
const context = useContext(UserContext); const context = useContext(UserContext);
const { currentUser } = context; const { currentUser } = context;
const [openFolder, setOpenFolder] = useState(false); const [openFolder, setOpenFolder] = useState(false);
const [openInstallation, setOpenInstallation] = useState(false);
const [openModal, setOpenModal] = useState(false); const [openModal, setOpenModal] = useState(false);
const [selectedFolderNames, setSelectedFolderNames] = useState<string[]>([]); const [selectedFolderNames, setSelectedFolderNames] = useState<string[]>([]);
const [selectedInstallationNames, setSelectedInstallationNames] = useState<string[]>([]); const [selectedInstallations, setSelectedInstallations] = useState<I_Installation[]>([]);
// Available choices for grant modal // Available choices for grant modal
const [availableFolders, setAvailableFolders] = useState<I_Folder[]>([]); const [availableFolders, setAvailableFolders] = useState<I_Folder[]>([]);
const [availableInstallations, setAvailableInstallations] = useState<I_Installation[]>([]); 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 // Direct grants for this user
const [directFolders, setDirectFolders] = useState<{ id: number; name: string }[]>([]); const [directFolders, setDirectFolders] = useState<{ id: number; name: string }[]>([]);
const [directInstallations, setDirectInstallations] = useState<{ id: number; name: string }[]>([]); const [directInstallations, setDirectInstallations] = useState<{ id: number; name: string }[]>([]);
@ -130,7 +151,7 @@ function UserAccess(props: UserAccessProps) {
fetchAvailableInstallations(); fetchAvailableInstallations();
setOpenModal(true); setOpenModal(true);
setSelectedFolderNames([]); setSelectedFolderNames([]);
setSelectedInstallationNames([]); setSelectedInstallations([]);
}; };
const handleRevokeFolder = async (folderId: number, folderName: string) => { const handleRevokeFolder = async (folderId: number, folderName: string) => {
@ -178,8 +199,7 @@ function UserAccess(props: UserAccessProps) {
}); });
} }
for (const installationName of selectedInstallationNames) { for (const installation of selectedInstallations) {
const installation = availableInstallations.find((i) => i.name === installationName);
await axiosConfig await axiosConfig
.post(`/GrantUserAccessToInstallation?UserId=${props.current_user.id}&InstallationId=${installation.id}`) .post(`/GrantUserAccessToInstallation?UserId=${props.current_user.id}&InstallationId=${installation.id}`)
.then(() => { .then(() => {
@ -264,31 +284,27 @@ function UserAccess(props: UserAccessProps) {
</div> </div>
<div> <div>
<FormControl fullWidth sx={{ marginTop: 2, width: 390 }}> <FormControl fullWidth sx={{ marginTop: 1, width: 390 }}>
<InputLabel sx={{ fontSize: 14, backgroundColor: 'white' }}> <Autocomplete<I_Installation, true, false, false>
<FormattedMessage id="grantAccessToInstallations" defaultMessage="Grant access to installations" />
</InputLabel>
<Select
multiple multiple
value={selectedInstallationNames} options={sortedInstallations}
onChange={(e) => setSelectedInstallationNames(e.target.value as string[])} groupBy={(option) => PRODUCT_NAMES[option.product] || 'Unknown'}
open={openInstallation} getOptionLabel={(option) => option.name}
onClose={() => setOpenInstallation(false)} value={selectedInstallations}
onOpen={() => setOpenInstallation(true)} onChange={(_event, newValue) => setSelectedInstallations(newValue)}
renderValue={(selected) => ( isOptionEqualToValue={(option, value) => option.id === value.id}
<div>{selected.map((i) => <span key={i}>{i}, </span>)}</div> 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> </FormControl>
</div> </div>

View File

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

View File

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

View File

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

View File

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