+ }
name="information"
value={formValues.information}
onChange={handleChange}
@@ -129,7 +135,7 @@ function folderForm(props: folderFormProps) {
}}
disabled={!areRequiredFieldsFilled()}
>
- Submit
+
{loading && (
@@ -160,11 +166,14 @@ function folderForm(props: folderFormProps) {
alignItems: 'center'
}}
>
- An error has occurred
+
setError(false)} // Set error state to false on click
+ onClick={() => setError(false)}
sx={{ marginLeft: '4px' }}
>
diff --git a/typescript/frontend-marios2/src/content/dashboards/Users/UsersSearch.tsx b/typescript/frontend-marios2/src/content/dashboards/Users/UsersSearch.tsx
index 3ae60674a..fd585d2db 100644
--- a/typescript/frontend-marios2/src/content/dashboards/Users/UsersSearch.tsx
+++ b/typescript/frontend-marios2/src/content/dashboards/Users/UsersSearch.tsx
@@ -12,6 +12,7 @@ import { UsersContext } from '../../../contexts/UsersContextProvider';
import Button from '@mui/material/Button';
import UserForm from './userForm';
import { UserContext } from '../../../contexts/userContext';
+import { FormattedMessage } from 'react-intl';
function UsersSearch() {
const theme = useTheme();
@@ -55,7 +56,7 @@ function UsersSearch() {
{currentUser.hasWriteAccess && (
)}
diff --git a/typescript/frontend-marios2/src/content/dashboards/Users/userForm.tsx b/typescript/frontend-marios2/src/content/dashboards/Users/userForm.tsx
index 9fa785376..2d69804d1 100644
--- a/typescript/frontend-marios2/src/content/dashboards/Users/userForm.tsx
+++ b/typescript/frontend-marios2/src/content/dashboards/Users/userForm.tsx
@@ -20,6 +20,7 @@ import { TokenContext } from 'src/contexts/tokenContext';
import FormControlLabel from '@mui/material/FormControlLabel';
import Checkbox from '@mui/material/Checkbox';
import { I_Folder, I_Installation } from 'src/interfaces/InstallationTypes';
+import { FormattedMessage } from 'react-intl';
interface userFormProps {
cancel: () => void;
@@ -208,7 +209,7 @@ function userForm(props: userFormProps) {
>
}
name="name"
value={formValues.name}
onChange={handleChange}
@@ -219,7 +220,7 @@ function userForm(props: userFormProps) {
}
name="email"
value={formValues.email}
onChange={handleChange}
@@ -230,7 +231,12 @@ function userForm(props: userFormProps) {
+ }
name="information"
value={formValues.information}
onChange={handleChange}
@@ -249,7 +255,10 @@ function userForm(props: userFormProps) {
backgroundColor: 'transparent'
}}
>
- Grant access to folders
+
@@ -304,7 +313,10 @@ function userForm(props: userFormProps) {
fontSize: 14
}}
>
- Grant access to installations
+
@@ -375,7 +387,7 @@ function userForm(props: userFormProps) {
}}
disabled={!areRequiredFieldsFilled()}
>
- Submit
+
{loading && (
@@ -410,7 +422,7 @@ function userForm(props: userFormProps) {
setError(false)} // Set error state to false on click
+ onClick={() => setError(false)}
sx={{ marginLeft: '4px' }}
>
diff --git a/typescript/frontend-marios2/src/contexts/AccessContextProvider.tsx b/typescript/frontend-marios2/src/contexts/AccessContextProvider.tsx
index 585ea7f74..60e2e2735 100644
--- a/typescript/frontend-marios2/src/contexts/AccessContextProvider.tsx
+++ b/typescript/frontend-marios2/src/contexts/AccessContextProvider.tsx
@@ -1,4 +1,4 @@
-import {
+import React, {
createContext,
ReactNode,
useCallback,
@@ -11,6 +11,7 @@ import {
I_UserWithInheritedAccess,
InnovEnergyUser
} from '../interfaces/UserTypes';
+import { FormattedMessage } from 'react-intl';
interface AccessContextProviderProps {
usersWithDirectAccess: InnovEnergyUser[];
@@ -82,7 +83,15 @@ const AccessContextProvider = ({ children }: { children: ReactNode }) => {
})
.catch((error) => {
setError(true);
- setErrorMessage('Unable to load data');
+
+ const message = (
+
+ ).props.defaultMessage;
+
+ setErrorMessage(message);
});
},
[]
@@ -99,7 +108,13 @@ const AccessContextProvider = ({ children }: { children: ReactNode }) => {
})
.catch((error) => {
setError(true);
- setErrorMessage('Unable to load data');
+ const message = (
+
+ ).props.defaultMessage;
+ setErrorMessage(message);
});
},
[]
@@ -127,7 +142,19 @@ const AccessContextProvider = ({ children }: { children: ReactNode }) => {
resourceType,
current_ResourceId
);
- setUpdatedMessage('Revoked access from user: ' + name);
+
+ const message =
+ (
+
+ ).props.defaultMessage +
+ ' ' +
+ name;
+
+ setUpdatedMessage(message);
+
setUpdated(true);
setTimeout(() => {
setUpdated(false);
@@ -136,7 +163,14 @@ const AccessContextProvider = ({ children }: { children: ReactNode }) => {
})
.catch((error) => {
setError(true);
- setErrorMessage('Unable to revoke access');
+ const message = (
+
+ ).props.defaultMessage;
+
+ setErrorMessage(message);
});
},
[]
diff --git a/typescript/frontend-marios2/src/contexts/InstallationsContextProvider.tsx b/typescript/frontend-marios2/src/contexts/InstallationsContextProvider.tsx
index 8fddbfeee..cd773e16b 100644
--- a/typescript/frontend-marios2/src/contexts/InstallationsContextProvider.tsx
+++ b/typescript/frontend-marios2/src/contexts/InstallationsContextProvider.tsx
@@ -11,7 +11,8 @@ import { I_Folder, I_Installation } from 'src/interfaces/InstallationTypes';
import { TokenContext } from './tokenContext';
interface I_InstallationContextProviderProps {
- data: I_Installation[];
+ installations: I_Installation[];
+ foldersAndInstallations: I_Installation[];
fetchAllInstallations: () => Promise;
fetchAllFoldersAndInstallations: () => Promise;
createInstallation: (value: Partial) => Promise;
@@ -24,14 +25,14 @@ interface I_InstallationContextProviderProps {
setUpdated: (value: boolean) => void;
deleteInstallation: (value: I_Installation, view: string) => Promise;
createFolder: (value: Partial) => Promise;
-
updateFolder: (value: I_Folder) => Promise;
deleteFolder: (value: I_Folder) => Promise;
}
export const InstallationsContext =
createContext({
- data: [],
+ installations: [],
+ foldersAndInstallations: [],
fetchAllInstallations: () => Promise.resolve(),
fetchAllFoldersAndInstallations: () => Promise.resolve(),
createInstallation: () => Promise.resolve(),
@@ -44,7 +45,6 @@ export const InstallationsContext =
setUpdated: () => {},
deleteInstallation: () => Promise.resolve(),
createFolder: () => Promise.resolve(),
-
updateFolder: () => Promise.resolve(),
deleteFolder: () => Promise.resolve()
});
@@ -54,7 +54,8 @@ const InstallationsContextProvider = ({
}: {
children: ReactNode;
}) => {
- const [data, setData] = useState([]);
+ const [installations, setInstallations] = useState([]);
+ const [foldersAndInstallations, setFoldersAndInstallations] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [updated, setUpdated] = useState(false);
@@ -67,7 +68,7 @@ const InstallationsContextProvider = ({
axiosConfig
.get('/GetAllInstallations', {})
.then((res) => {
- setData(res.data);
+ setInstallations(res.data);
})
.catch((err: AxiosError) => {
if (err.response && err.response.status == 401) {
@@ -80,14 +81,14 @@ const InstallationsContextProvider = ({
return axiosConfig
.get('/GetAllFoldersAndInstallations')
.then((res) => {
- setData(res.data);
+ setFoldersAndInstallations(res.data);
})
.catch((err) => {
if (err.response && err.response.status == 401) {
removeToken();
}
});
- }, [setData]);
+ }, []);
const createInstallation = useCallback(
async (formValues: Partial) => {
@@ -235,7 +236,8 @@ const InstallationsContextProvider = ({
return (
(
undefined
);
-// Create a UserContextProvider component
export const LogContextProvider = ({ children }: { children: ReactNode }) => {
const [installationStatus, setInstallationStatus] = useState<
Record
>({});
+ const BUFFER_LENGTH = 5;
+
const handleLogWarningOrError = (installation_id: number, value: number) => {
setInstallationStatus((prevStatus) => {
const newStatus = { ...prevStatus };
@@ -24,16 +25,23 @@ export const LogContextProvider = ({ children }: { children: ReactNode }) => {
newStatus[installation_id] = [];
}
newStatus[installation_id].unshift(value);
- newStatus[installation_id] = newStatus[installation_id].slice(0, 5);
+ newStatus[installation_id] = newStatus[installation_id].slice(
+ 0,
+ BUFFER_LENGTH
+ );
return newStatus;
});
};
const getStatus = (installationId: number) => {
let status;
+
if (!installationStatus.hasOwnProperty(installationId)) {
status = -2;
} else {
+ if (installationId === 2) {
+ console.log(installationStatus[2]);
+ }
if (installationStatus[installationId][0] == -1) {
let i = 0;
for (i; i < installationStatus[installationId].length; i++) {
diff --git a/typescript/frontend-marios2/src/dataCache/dataCache.ts b/typescript/frontend-marios2/src/dataCache/dataCache.ts
index e57b25291..7b446cd1b 100644
--- a/typescript/frontend-marios2/src/dataCache/dataCache.ts
+++ b/typescript/frontend-marios2/src/dataCache/dataCache.ts
@@ -8,6 +8,7 @@ import {RecordSeries} from './data';
import {isUndefined, Maybe} from './utils/maybe';
import {isNumber} from './utils/runtimeTypeChecking';
import {I_CsvEntry} from 'src/content/dashboards/Log/graph.util';
+import {I_S3Credentials} from '../interfaces/S3Types';
export const FetchResult = {
notAvailable: 'N/A',
@@ -33,7 +34,10 @@ function reverseBits(x: number): number {
}
export default class DataCache> {
- readonly _fetch: (t: UnixTime) => Promise>;
+ readonly _fetch: (
+ t: UnixTime,
+ s3Credentials: I_S3Credentials
+ ) => Promise>;
public readonly gotData: Observable;
@@ -41,16 +45,23 @@ export default class DataCache> {
private readonly resolution: TimeSpan;
+ private readonly s3Credentials: I_S3Credentials;
+
private readonly fetchQueue = createDispatchQueue(6);
private readonly fetching: Set = new Set();
constructor(
- fetch: (t: UnixTime) => Promise>,
- resolution: TimeSpan
+ fetch: (
+ t: UnixTime,
+ s3Credentials: I_S3Credentials
+ ) => Promise>,
+ resolution: TimeSpan,
+ s3Credentials: I_S3Credentials
) {
this._fetch = fetch;
this.resolution = resolution;
+ this.s3Credentials = s3Credentials;
this.gotData = new Subject();
}
@@ -71,7 +82,7 @@ export default class DataCache> {
const t = time.ticks;
const node = this.cache.find(t);
- if (node.index !== t) this.fetchData(time);
+ if (node.index !== t) this.fetchData(time, this.s3Credentials);
}
}
@@ -82,7 +93,7 @@ export default class DataCache> {
const node = this.cache.find(t);
if (node.index === t) return node.value;
- if (fetch) this.fetchData(time);
+ if (fetch) this.fetchData(time, this.s3Credentials);
return this.interpolate(node, t);
}
@@ -130,7 +141,7 @@ export default class DataCache> {
return interpolated as T;
}
- private fetchData(time: UnixTime) {
+ private fetchData(time: UnixTime, s3Credentials: I_S3Credentials) {
const t = time.ticks;
if (this.fetching.has(t))
@@ -160,7 +171,7 @@ export default class DataCache> {
(this.gotData as Subject).next(time);
};
- return this._fetch(time)
+ return this._fetch(time, s3Credentials)
.then(
(d) => onSuccess(d),
(f) => onFailure(f)
diff --git a/typescript/frontend-marios2/src/interfaces/S3Types.tsx b/typescript/frontend-marios2/src/interfaces/S3Types.tsx
index 3849aca09..4f04962b6 100644
--- a/typescript/frontend-marios2/src/interfaces/S3Types.tsx
+++ b/typescript/frontend-marios2/src/interfaces/S3Types.tsx
@@ -7,6 +7,8 @@ export interface I_S3Credentials {
}
export interface Notification {
- key: string;
- value: string;
+ device: string;
+ description: string;
+ date: string;
+ time: string;
}
diff --git a/typescript/frontend-marios2/src/lang/de.json b/typescript/frontend-marios2/src/lang/de.json
index edd4d8bc2..e7bf215c7 100644
--- a/typescript/frontend-marios2/src/lang/de.json
+++ b/typescript/frontend-marios2/src/lang/de.json
@@ -16,7 +16,6 @@
"german": "Deutsch",
"groupTabs": "Gruppen",
"groupTree": "Gruppenbaum",
- "information": "Information",
"inheritedAccess": "Vererbter Zugriff von",
"installation": "Installation",
"installationTabs": "Installationen",
@@ -48,5 +47,24 @@
"live": "Live Übertragung",
"deleteInstallation": "Installation löschen",
"errorOccured": "Ein Fehler ist aufgetreten",
- "successfullyUpdated": "Erfolgreich aktualisiert"
+ "successfullyUpdated": "Erfolgreich aktualisiert",
+ "grantAccess": "Zugriff gewähren",
+ "UserswithDirectAccess": "Benutzer mit direktem Zugriff",
+ "UserswithInheritedAccess": "Benutzer mit geerbtem Zugriff",
+ "noerrors": "Es liegen keine Fehler vor",
+ "nowarnings": "Es gibt keine Warnungen",
+ "noUsersWithDirectAccessToThis": "Keine Benutzer mit direktem Zugriff darauf ",
+ "selectUsers": "Wählen Sie Benutzer aus",
+ "cancel": "Stornieren",
+ "addNewFolder": "Neuen Ordner hinzufügen",
+ "addNewInstallation": "Neue Installation hinzufügen",
+ "deleteFolder": "Lösche Ordner",
+ "grantAccessToFolders": "Gewähren Sie Zugriff auf Ordner",
+ "grantAccessToInstallations": "Gewähren Sie Zugriff auf Installationen",
+ "cannotloadloggingdata": "Protokollierungsdaten können nicht geladen werden",
+ "grantedAccessToUsers": "Benutzern Zugriff gewährt: ",
+ "unableToGrantAccess": "Der Zugriff auf kann nicht gewährt werden: ",
+ "unableToLoadData": "Daten können nicht geladen werden",
+ "unableToRevokeAccess": "Der Zugriff kann nicht widerrufen werden",
+ "revokedAccessFromUser": "Zugriff vom Benutzer widerrufen: "
}
diff --git a/typescript/frontend-marios2/src/lang/en.json b/typescript/frontend-marios2/src/lang/en.json
index 03f70214f..71756e085 100644
--- a/typescript/frontend-marios2/src/lang/en.json
+++ b/typescript/frontend-marios2/src/lang/en.json
@@ -1,8 +1,6 @@
{
- "liveView": "Live view",
"allInstallations": "All installations",
"applyChanges": "Apply changes",
- "deleteInstallation": "Delete Installation",
"country": "Country",
"customerName": "Customer name",
"english": "English",
@@ -53,5 +51,24 @@
"live": "Live View",
"deleteInstallation": "Delete Installation",
"errorOccured": "An error has occurred",
- "successfullyUpdated": "Successfully updated"
+ "successfullyUpdated": "Successfully updated",
+ "grantAccess": "Grant Access",
+ "UserswithDirectAccess": "Users with Direct Access",
+ "UserswithInheritedAccess": "Users with Inherited Access",
+ "noerrors": "There are no errors",
+ "nowarnings": "There are no warnings",
+ "noUsersWithDirectAccessToThis": "No users with direct access to this ",
+ "selectUsers": "Select Users",
+ "cancel": "Cancel",
+ "addNewFolder": "Add new Folder",
+ "addNewInstallation": "Add new Installation",
+ "deleteFolder": "Delete Folder",
+ "grantAccessToFolders": "Grant Access to Folders",
+ "grantAccessToInstallations": "Grant Access to Installations",
+ "cannotloadloggingdata": "Cannot load logging data",
+ "grantedAccessToUsers": "Granted access to users: ",
+ "unableToGrantAccess": "Unable to grant access to: ",
+ "unableToLoadData": "Unable to load data",
+ "unableToRevokeAccess": "Unable to revoke access",
+ "revokedAccessFromUser": "Revoked access from user: "
}
diff --git a/typescript/frontend-marios2/src/lang/fr.json b/typescript/frontend-marios2/src/lang/fr.json
index 0f80c8463..b063dddb6 100644
--- a/typescript/frontend-marios2/src/lang/fr.json
+++ b/typescript/frontend-marios2/src/lang/fr.json
@@ -16,7 +16,6 @@
"german": "Allemand",
"groupTabs": "Onglets de groupe",
"groupTree": "Arbre de groupe",
- "information": "Informations",
"inheritedAccess": "Accès hérité de",
"installation": "Installation",
"installationTabs": "Onglets d'installation",
@@ -48,5 +47,24 @@
"live": "Diffusion en direct",
"deleteInstallation": "Supprimer l'installation",
"errorOccured": "Une erreur est survenue",
- "successfullyUpdated": "Mise à jour réussie"
+ "successfullyUpdated": "Mise à jour réussie",
+ "grantAccess": "Accorder l'accès",
+ "UserswithDirectAccess": "Utilisateurs avec accès direct",
+ "UserswithInheritedAccess": "Utilisateurs avec accès hérité",
+ "noerrors": "Il n'y a pas d'erreurs",
+ "nowarnings": "Il n'y a aucun avertissement",
+ "noUsersWithDirectAccessToThis": "Aucun utilisateur ayant un accès direct à ceci ",
+ "selectUsers": "Sélectionnez les utilisateurs",
+ "cancel": "Annuler",
+ "addNewFolder": "Ajouter un nouveau dossier",
+ "addNewInstallation": "Ajouter une nouvelle installation",
+ "deleteFolder": "Supprimer le dossier",
+ "grantAccessToFolders": "Accorder l'accès aux dossiers",
+ "grantAccessToInstallations": "Accorder l'accès aux installations",
+ "cannotloadloggingdata": "Impossible de charger les données de journalisation",
+ "grantedAccessToUsers": "Accès accordé aux utilisateurs: ",
+ "unableToGrantAccess": "Impossible d'accorder l'accès à: ",
+ "unableToLoadData": "Impossible de charger les données",
+ "unableToRevokeAccess": "Impossible de révoquer l'accès",
+ "revokedAccessFromUser": "Accès révoqué de l'utilisateur: "
}
diff --git a/typescript/frontend-marios2/src/layouts/SidebarLayout/Header/Menu/index.tsx b/typescript/frontend-marios2/src/layouts/SidebarLayout/Header/Menu/index.tsx
index 4a50ceaad..b4982a0b8 100644
--- a/typescript/frontend-marios2/src/layouts/SidebarLayout/Header/Menu/index.tsx
+++ b/typescript/frontend-marios2/src/layouts/SidebarLayout/Header/Menu/index.tsx
@@ -4,8 +4,7 @@ import {
ListItem,
ListItemText,
Menu,
- MenuItem,
- Switch
+ MenuItem
} from '@mui/material';
import { useContext, useRef, useState } from 'react';
import { styled } from '@mui/material/styles';
@@ -98,6 +97,11 @@ function HeaderMenu(props: HeaderButtonsProps) {
setOpen(false);
};
+ const handleLanguageSelect = (language) => {
+ props.onSelectLanguage(language);
+ handleClose();
+ };
+
return (
<>
-
diff --git a/typescript/frontend-marios2/src/layouts/SidebarLayout/Sidebar/index.tsx b/typescript/frontend-marios2/src/layouts/SidebarLayout/Sidebar/index.tsx
index 9d4832a66..5dd05300b 100644
--- a/typescript/frontend-marios2/src/layouts/SidebarLayout/Sidebar/index.tsx
+++ b/typescript/frontend-marios2/src/layouts/SidebarLayout/Sidebar/index.tsx
@@ -18,7 +18,7 @@ import SidebarMenu from './SidebarMenu';
const SidebarWrapper = styled(Box)(
({ theme }) => `
width: ${theme.sidebar.width};
- min-width: ${theme.sidebar.width};
+ min-width: "${theme.sidebar.width}";
color: ${theme.colors.alpha.trueWhite[70]};
position: relative;
z-index: 7;
@@ -64,8 +64,7 @@ function Sidebar() {
alt="innovenergy logo"
style={{
maxWidth: '150px', // Maximum width for the image
- maxHeight: '150px', // Maximum height for the image
- marginLeft: '50px' // Adjust the value as needed
+ maxHeight: '150px' // Maximum height for the image
}}
/>
diff --git a/typescript/frontend-marios2/src/layouts/TabsContainerWrapper.tsx b/typescript/frontend-marios2/src/layouts/TabsContainerWrapper.tsx
index b54f1924b..45963184a 100644
--- a/typescript/frontend-marios2/src/layouts/TabsContainerWrapper.tsx
+++ b/typescript/frontend-marios2/src/layouts/TabsContainerWrapper.tsx
@@ -1,4 +1,5 @@
-import { Box, styled } from '@mui/material';
+import { Box, Card, styled } from '@mui/material';
+import Avatar from '@mui/material/Avatar';
export const TabsContainerWrapper = styled(Box)(
({ theme }) => `
@@ -81,3 +82,61 @@ export const TabsContainerWrapper = styled(Box)(
}
`
);
+
+export const AvatarWrapper = styled(Avatar)(
+ ({ theme }) => `
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 60px;
+ margin-top: -5px;
+ height: ${theme.spacing(3.5)};
+ width: ${theme.spacing(3.5)};
+ background: ${
+ theme.palette.mode === 'dark'
+ ? theme.colors.alpha.trueWhite[30]
+ : '#ffffff'
+ };
+
+ img {
+ background: ${theme.colors.alpha.trueWhite[100]};
+ display: block;
+ border-radius: inherit;
+ height: ${theme.spacing(4.5)};
+ width: ${theme.spacing(4.5)};
+ }
+`
+);
+
+export const AvatarAddWrapper = styled(Avatar)(
+ ({ theme }) => `
+ background: ${theme.colors.alpha.black[10]};
+ color: ${theme.colors.primary.main};
+ width: ${theme.spacing(8)};
+ height: ${theme.spacing(8)};
+`
+);
+
+export const CardAddAction = styled(Card)(
+ ({ theme }) => `
+ border: ${theme.colors.primary.main} dashed 1px;
+ height: 100%;
+ color: ${theme.colors.primary.main};
+ transition: ${theme.transitions.create(['all'])};
+
+ .MuiCardActionArea-root {
+ height: 100%;
+ justify-content: center;
+ align-items: center;
+ display: flex;
+ }
+
+ .MuiTouchRipple-root {
+ opacity: .2;
+ }
+
+ &:hover {
+ border-color: ${theme.colors.alpha.black[70]};
+ }
+`
+);
diff --git a/typescript/frontend-marios2/src/theme/schemes/PureLightTheme.ts b/typescript/frontend-marios2/src/theme/schemes/PureLightTheme.ts
index 34d971901..4e4c2a62b 100644
--- a/typescript/frontend-marios2/src/theme/schemes/PureLightTheme.ts
+++ b/typescript/frontend-marios2/src/theme/schemes/PureLightTheme.ts
@@ -240,7 +240,7 @@ export const PureLightTheme = createTheme({
menuItemHeadingColor: colors.layout.sidebar.menuItemHeadingColor,
boxShadow:
'2px 0 3px rgba(159, 162, 191, .18), 1px 0 1px rgba(159, 162, 191, 0.32)',
- width: '290px'
+ width: '200px'
},
header: {
height: '80px',