Code refactoring, styling

This commit is contained in:
Sina Blattmann 2023-07-20 17:32:10 +02:00
parent 6bf6399ed2
commit 1cb78f7a05
47 changed files with 169 additions and 184 deletions

View File

@ -78,7 +78,7 @@ const App = () => {
bgcolor={colors.greyLight} bgcolor={colors.greyLight}
pt={3} pt={3}
borderTop="2px solid" borderTop="2px solid"
borderColor={colors.darkGrey} borderColor={colors.borderColor}
flex="1 0 auto" flex="1 0 auto"
> >
<Container maxWidth="xl"> <Container maxWidth="xl">

View File

@ -2,8 +2,9 @@ import { createContext, ReactNode, useCallback, useState } from "react";
import axiosConfig from "../../config/axiosConfig"; import axiosConfig from "../../config/axiosConfig";
import { transformArrayToTree } from "../../util/group.util"; import { transformArrayToTree } from "../../util/group.util";
import { I_Folder, I_Installation } from "../../util/types"; import { I_Folder, I_Installation } from "../../util/types";
import { AxiosError } from "axios";
interface GroupContextProviderProps { interface I_GroupContextProviderProps {
currentType: string; currentType: string;
setCurrentType: (value: string) => void; setCurrentType: (value: string) => void;
data: (I_Folder | I_Installation)[]; data: (I_Folder | I_Installation)[];
@ -11,10 +12,10 @@ interface GroupContextProviderProps {
fetchData: () => Promise<void>; fetchData: () => Promise<void>;
loading: boolean; loading: boolean;
setLoading: (value: boolean) => void; setLoading: (value: boolean) => void;
getError: boolean; getError?: AxiosError;
} }
export const GroupContext = createContext<GroupContextProviderProps>({ export const GroupContext = createContext<I_GroupContextProviderProps>({
currentType: "", currentType: "",
setCurrentType: () => {}, setCurrentType: () => {},
data: [], data: [],
@ -22,14 +23,14 @@ export const GroupContext = createContext<GroupContextProviderProps>({
fetchData: () => Promise.resolve(), fetchData: () => Promise.resolve(),
loading: false, loading: false,
setLoading: () => {}, setLoading: () => {},
getError: false, getError: undefined,
}); });
const GroupContextProvider = ({ children }: { children: ReactNode }) => { const GroupContextProvider = ({ children }: { children: ReactNode }) => {
const [currentType, setCurrentType] = useState(""); const [currentType, setCurrentType] = useState("");
const [data, setData] = useState<(I_Folder | I_Installation)[]>([]); const [data, setData] = useState<(I_Folder | I_Installation)[]>([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [getError, setGetError] = useState(false); const [getError, setGetError] = useState<AxiosError>();
const fetchData = useCallback(async () => { const fetchData = useCallback(async () => {
setLoading(true); setLoading(true);

View File

@ -3,7 +3,7 @@ import { createContext, ReactNode, useCallback, useState } from "react";
import axiosConfig from "../../config/axiosConfig"; import axiosConfig from "../../config/axiosConfig";
import { I_Installation } from "../../util/types"; import { I_Installation } from "../../util/types";
interface InstallationContextProviderProps { interface I_InstallationContextProviderProps {
data: I_Installation[]; data: I_Installation[];
setData: (value: I_Installation[]) => void; setData: (value: I_Installation[]) => void;
fetchData: () => Promise<void>; fetchData: () => Promise<void>;
@ -14,7 +14,7 @@ interface InstallationContextProviderProps {
} }
export const InstallationsContext = export const InstallationsContext =
createContext<InstallationContextProviderProps>({ createContext<I_InstallationContextProviderProps>({
data: [], data: [],
setData: () => {}, setData: () => {},
fetchData: () => Promise.resolve(), fetchData: () => Promise.resolve(),

View File

@ -1,16 +1,16 @@
import { createContext, ReactNode, useState } from "react"; import { createContext, ReactNode, useState } from "react";
import { TreeElement } from "../Installations/Log/CheckboxTree"; import { I_TreeElement } from "../Installations/Log/CheckboxTree";
import React from "react"; import React from "react";
interface LogContextProviderProps { interface I_LogContextProviderProps {
toggles: TreeElement[] | null; toggles: I_TreeElement[] | null;
setToggles: (value: TreeElement[]) => void; setToggles: (value: I_TreeElement[]) => void;
checkedToggles: string[]; checkedToggles: string[];
setChecked: (newValue: string) => void; setChecked: (newValue: string) => void;
removeChecked: (value: string) => void; removeChecked: (value: string) => void;
} }
export const LogContext = createContext<LogContextProviderProps>({ export const LogContext = createContext<I_LogContextProviderProps>({
toggles: [], toggles: [],
setToggles: () => {}, setToggles: () => {},
checkedToggles: [], checkedToggles: [],
@ -19,7 +19,7 @@ export const LogContext = createContext<LogContextProviderProps>({
}); });
const LogContextProvider = ({ children }: { children: ReactNode }) => { const LogContextProvider = ({ children }: { children: ReactNode }) => {
const [toggles, setToggles] = useState<TreeElement[] | null>(null); const [toggles, setToggles] = useState<I_TreeElement[] | null>(null);
const [checkedToggles, setCheckedToggles] = useState<string[]>([]); const [checkedToggles, setCheckedToggles] = useState<string[]>([]);
const setChecked = (newValue: string) => { const setChecked = (newValue: string) => {

View File

@ -1,21 +1,20 @@
import { createContext, ReactNode, useState } from "react"; import { createContext, ReactNode, useState } from "react";
import { I_User } from "../../util/user.util"; import { I_S3Credentials } from "../../util/types";
import { I_Installation, S3Credentials } from "../../util/types";
import { UnixTime } from "../../dataCache/time"; import { UnixTime } from "../../dataCache/time";
import { FetchResult } from "../../dataCache/dataCache"; import { FetchResult } from "../../dataCache/dataCache";
import { DataRecord } from "../../dataCache/data"; import { DataRecord } from "../../dataCache/data";
import { S3Access } from "../../dataCache/S3/S3Access"; import { S3Access } from "../../dataCache/S3/S3Access";
import { parseCsv } from "../../util/graph.util"; import { parseCsv } from "../../util/graph.util";
interface S3CredentialsContextProviderProps { interface I_S3CredentialsContextProviderProps {
s3Credentials?: S3Credentials; s3Credentials?: I_S3Credentials;
saveS3Credentials: (credentials: S3Credentials, id: string) => void; saveS3Credentials: (credentials: I_S3Credentials, id: string) => void;
fetchData: (timestamp: UnixTime) => Promise<FetchResult<DataRecord>>; fetchData: (timestamp: UnixTime) => Promise<FetchResult<DataRecord>>;
} }
export const S3CredentialsContext = export const S3CredentialsContext =
createContext<S3CredentialsContextProviderProps>({ createContext<I_S3CredentialsContextProviderProps>({
s3Credentials: {} as S3Credentials, s3Credentials: {} as I_S3Credentials,
saveS3Credentials: () => {}, saveS3Credentials: () => {},
fetchData: () => ({} as Promise<FetchResult<DataRecord>>), fetchData: () => ({} as Promise<FetchResult<DataRecord>>),
}); });
@ -25,9 +24,9 @@ const S3CredentialsContextProvider = ({
}: { }: {
children: ReactNode; children: ReactNode;
}) => { }) => {
const [s3Credentials, setS3Credentials] = useState<S3Credentials>(); const [s3Credentials, setS3Credentials] = useState<I_S3Credentials>();
const saveS3Credentials = (credentials: S3Credentials, id: string) => { const saveS3Credentials = (credentials: I_S3Credentials, id: string) => {
const s3Bucket = id + "-3e5b3069-214a-43ee-8d85-57d72000c19d"; const s3Bucket = id + "-3e5b3069-214a-43ee-8d85-57d72000c19d";
setS3Credentials({ s3Bucket, ...credentials }); setS3Credentials({ s3Bucket, ...credentials });
}; };

View File

@ -1,14 +1,14 @@
import { createContext, ReactNode, useState } from "react"; import { createContext, ReactNode, useState } from "react";
import { I_User } from "../../util/user.util"; import { I_User } from "../../util/user.util";
interface InstallationContextProviderProps { interface I_InstallationContextProviderProps {
currentUser?: I_User; currentUser?: I_User;
setCurrentUser: (value: I_User) => void; setCurrentUser: (value: I_User) => void;
saveCurrentUser: (user: I_User) => void; saveCurrentUser: (user: I_User) => void;
getCurrentUser: () => I_User; getCurrentUser: () => I_User;
} }
export const UserContext = createContext<InstallationContextProviderProps>({ export const UserContext = createContext<I_InstallationContextProviderProps>({
currentUser: {} as I_User, currentUser: {} as I_User,
setCurrentUser: () => {}, setCurrentUser: () => {},
saveCurrentUser: () => {}, saveCurrentUser: () => {},

View File

@ -8,14 +8,14 @@ import {
} from "react"; } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import axiosConfig from "../../config/axiosConfig"; import axiosConfig from "../../config/axiosConfig";
import { I_User, UserWithInheritedAccess } from "../../util/user.util"; import { I_User, I_UserWithInheritedAccess } from "../../util/user.util";
import { GroupContext } from "./GroupContextProvider"; import { GroupContext } from "./GroupContextProvider";
interface UsersContextProviderProps { interface I_UsersContextProviderProps {
directAccessUsers: I_User[]; directAccessUsers: I_User[];
setDirectAccessUsers: (value: I_User[]) => void; setDirectAccessUsers: (value: I_User[]) => void;
inheritedAccessUsers: UserWithInheritedAccess[]; inheritedAccessUsers: I_UserWithInheritedAccess[];
setInheritedAccessUsers: (value: UserWithInheritedAccess[]) => void; setInheritedAccessUsers: (value: I_UserWithInheritedAccess[]) => void;
availableUsers: I_User[]; availableUsers: I_User[];
setAvailableUsers: (value: I_User[]) => void; setAvailableUsers: (value: I_User[]) => void;
getAvailableUsersForResource: () => I_User[]; getAvailableUsersForResource: () => I_User[];
@ -24,7 +24,7 @@ interface UsersContextProviderProps {
fetchAvailableUsers: () => Promise<void>; fetchAvailableUsers: () => Promise<void>;
} }
export const UsersContext = createContext<UsersContextProviderProps>({ export const UsersContext = createContext<I_UsersContextProviderProps>({
directAccessUsers: [], directAccessUsers: [],
setDirectAccessUsers: () => {}, setDirectAccessUsers: () => {},
inheritedAccessUsers: [], inheritedAccessUsers: [],
@ -48,7 +48,7 @@ export const UsersContext = createContext<UsersContextProviderProps>({
const UsersContextProvider = ({ children }: { children: ReactNode }) => { const UsersContextProvider = ({ children }: { children: ReactNode }) => {
const [directAccessUsers, setDirectAccessUsers] = useState<I_User[]>([]); const [directAccessUsers, setDirectAccessUsers] = useState<I_User[]>([]);
const [inheritedAccessUsers, setInheritedAccessUsers] = useState< const [inheritedAccessUsers, setInheritedAccessUsers] = useState<
UserWithInheritedAccess[] I_UserWithInheritedAccess[]
>([]); >([]);
const [availableUsers, setAvailableUsers] = useState<I_User[]>([]); const [availableUsers, setAvailableUsers] = useState<I_User[]>([]);

View File

@ -10,7 +10,7 @@ import { Fragment, useContext, useEffect } from "react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { import {
filterDuplicateUsers, filterDuplicateUsers,
UserWithInheritedAccess, I_UserWithInheritedAccess,
} from "../../../util/user.util"; } from "../../../util/user.util";
import routes from "../../../routes.json"; import routes from "../../../routes.json";
import PersonIcon from "@mui/icons-material/Person"; import PersonIcon from "@mui/icons-material/Person";
@ -29,7 +29,7 @@ const UsersWithInheritedAccess = () => {
return ( return (
<> <>
{filterDuplicateUsers(inheritedAccessUsers).map( {filterDuplicateUsers(inheritedAccessUsers).map(
({ user, folderName }: UserWithInheritedAccess) => { ({ user, folderName }: I_UserWithInheritedAccess) => {
return ( return (
<Fragment key={user.id}> <Fragment key={user.id}>
<ListItem id={"inherited-access-user-list-item" + user.id}> <ListItem id={"inherited-access-user-list-item" + user.id}>

View File

@ -1,5 +1,4 @@
import { useState } from "react"; import { FormattedMessage } from "react-intl";
import { FormattedMessage, useIntl } from "react-intl";
import axiosConfig from "../../config/axiosConfig"; import axiosConfig from "../../config/axiosConfig";
import { I_Folder, I_Installation } from "../../util/types"; import { I_Folder, I_Installation } from "../../util/types";
import FolderForm from "./Detail/FolderForm"; import FolderForm from "./Detail/FolderForm";

View File

@ -5,13 +5,13 @@ import CloseIcon from "@mui/icons-material/Close";
import { ReactNode, useState } from "react"; import { ReactNode, useState } from "react";
import InnovenergyButton from "../Layout/InnovenergyButton"; import InnovenergyButton from "../Layout/InnovenergyButton";
interface AddNewDialogProps { interface I_AddNewDialogProps {
form: ReactNode; form: ReactNode;
message: ReactNode; message: ReactNode;
id: number; id: number;
} }
const AddNewDialog = (props: AddNewDialogProps) => { const AddNewDialog = (props: I_AddNewDialogProps) => {
const { form, id, message } = props; const { form, id, message } = props;
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const intl = useIntl(); const intl = useIntl();

View File

@ -53,7 +53,6 @@ const Folder = () => {
borderBottomLeftRadius: 4, borderBottomLeftRadius: 4,
borderBottomRightRadius: 4, borderBottomRightRadius: 4,
borderColor: theme.palette.text.disabled, borderColor: theme.palette.text.disabled,
marginTop: 0.05,
}} }}
> >
<FolderForm <FolderForm

View File

@ -9,11 +9,11 @@ import { GroupContext } from "../../Context/GroupContextProvider";
import InnovenergyButton from "../../Layout/InnovenergyButton"; import InnovenergyButton from "../../Layout/InnovenergyButton";
import MoveTree from "./MoveTree"; import MoveTree from "./MoveTree";
interface MoveDialogProps { interface I_MoveDialogProps {
values: I_Folder; values: I_Folder;
} }
const MoveDialog = (props: MoveDialogProps) => { const MoveDialog = (props: I_MoveDialogProps) => {
const { values } = props; const { values } = props;
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);

View File

@ -8,12 +8,12 @@ import { instanceOfFolder } from "../../../util/group.util";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import InnovenergyTreeItem from "../../Layout/InnovenergyTreeItem"; import InnovenergyTreeItem from "../../Layout/InnovenergyTreeItem";
interface MoveTreeProps { interface I_MoveTreeProps {
setSelectedParentId: (value: number) => void; setSelectedParentId: (value: number) => void;
parentId: number; parentId: number;
} }
const MoveTree = (props: MoveTreeProps) => { const MoveTree = (props: I_MoveTreeProps) => {
const { data } = useContext(GroupContext); const { data } = useContext(GroupContext);
const intl = useIntl(); const intl = useIntl();

View File

@ -22,6 +22,8 @@ const GroupTabs = () => {
const id = routeMatch?.params?.id; const id = routeMatch?.params?.id;
console.log("fuck", routeMatch?.pattern?.path, currentType);
if (id) { if (id) {
return ( return (
<Box sx={{ width: "100%" }}> <Box sx={{ width: "100%" }}>

View File

@ -1,19 +1,20 @@
import TreeView from "@mui/lab/TreeView"; import TreeView from "@mui/lab/TreeView";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ChevronRightIcon from "@mui/icons-material/ChevronRight"; import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import { ReactNode, useContext, useEffect, useState } from "react"; import React, { ReactNode, useContext, useEffect, useState } from "react";
import { I_Folder, I_Installation } from "../../util/types"; import { I_Folder, I_Installation } from "../../util/types";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import routes from "../../routes.json"; import routes from "../../routes.json";
import { GroupContext } from "../Context/GroupContextProvider"; import { GroupContext } from "../Context/GroupContextProvider";
import { instanceOfFolder } from "../../util/group.util"; import { instanceOfFolder } from "../../util/group.util";
import { Grid, CircularProgress, useTheme } from "@mui/material"; import { Grid, CircularProgress, useTheme, Alert } from "@mui/material";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import InnovenergyTreeItem from "../Layout/InnovenergyTreeItem"; import InnovenergyTreeItem from "../Layout/InnovenergyTreeItem";
import TypeIcon from "./TypeIcon"; import TypeIcon from "./TypeIcon";
const GroupTree = () => { const GroupTree = () => {
const { setCurrentType, fetchData, data, loading } = useContext(GroupContext); const { setCurrentType, fetchData, data, loading, getError } =
useContext(GroupContext);
const [openNodes, setOpenNodes] = useState<string[]>([]); const [openNodes, setOpenNodes] = useState<string[]>([]);
const [selected, setSelected] = useState<string>(""); const [selected, setSelected] = useState<string>("");
const intl = useIntl(); const intl = useIntl();
@ -56,7 +57,11 @@ const GroupTree = () => {
<TypeIcon type={element.type} /> {element.name} <TypeIcon type={element.type} /> {element.name}
</> </>
} }
onClick={() => setCurrentType(element.type)} onClick={() => {
console.log("fuck", element.type);
setCurrentType(element.type);
}}
sx={{ ".MuiTreeItem-label": { display: "flex" } }}
> >
{getNodes(element)} {getNodes(element)}
</InnovenergyTreeItem> </InnovenergyTreeItem>
@ -100,6 +105,8 @@ const GroupTree = () => {
{renderTree(data)} {renderTree(data)}
</TreeView> </TreeView>
); );
} else if (getError) {
return <Alert severity="error">{getError.message} </Alert>;
} }
return null; return null;
}; };

View File

@ -1,11 +1,11 @@
import FolderIcon from "@mui/icons-material/Folder"; import FolderIcon from "@mui/icons-material/Folder";
import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile"; import InsertDriveFileIcon from "@mui/icons-material/InsertDriveFile";
interface TypeIconProps { interface I_TypeIconProps {
type: string | undefined; type: string | undefined;
} }
const TypeIcon = (props: TypeIconProps) => { const TypeIcon = (props: I_TypeIconProps) => {
return ( return (
<> <>
{props.type === "Folder" ? ( {props.type === "Folder" ? (

View File

@ -1,12 +1,9 @@
import { Alert, Box, CircularProgress, useTheme } from "@mui/material"; import { Alert, Box, CircularProgress, useTheme } from "@mui/material";
import { AxiosError } from "axios"; import { AxiosError } from "axios";
import { useContext, useEffect, useState } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import axiosConfig from "../../../config/axiosConfig"; import axiosConfig from "../../../config/axiosConfig";
import { I_Folder, I_Installation } from "../../../util/types"; import { I_Folder, I_Installation } from "../../../util/types";
import InstallationForm from "./InstallationForm"; import InstallationForm from "./InstallationForm";
import { colors } from "../../../index";
import { S3CredentialsContext } from "../../Context/S3CredentialsContextProvider";
import MoveDialog from "../../Groups/Detail/MoveDialog"; import MoveDialog from "../../Groups/Detail/MoveDialog";
interface I_InstallationProps { interface I_InstallationProps {
@ -46,7 +43,7 @@ const Installation = (props: I_InstallationProps) => {
<InstallationForm <InstallationForm
values={values} values={values}
handleSubmit={handleSubmit} handleSubmit={handleSubmit}
additionalButtons={props.hasMoveButton ? [moveDialog] : []} additionalButtons={props.hasMoveButton ? [moveDialog] : undefined}
/> />
<Box> <Box>
{values.s3WriteKey && <div>{`Write key: ${values.s3WriteKey}`}</div>} {values.s3WriteKey && <div>{`Write key: ${values.s3WriteKey}`}</div>}

View File

@ -8,8 +8,9 @@ import InnovenergyButton from "../../Layout/InnovenergyButton";
import { I_InnovenergyTextfieldProps } from "../../Layout/InnovenergyTextfield"; import { I_InnovenergyTextfieldProps } from "../../Layout/InnovenergyTextfield";
import { UserContext } from "../../Context/UserContextProvider"; import { UserContext } from "../../Context/UserContextProvider";
import * as Yup from "yup"; import * as Yup from "yup";
import { AxiosResponse } from "axios"; import { AxiosError, AxiosResponse } from "axios";
import InnovenergyPropertyGrid from "../../Layout/InnovenergyPropertyGrid"; import InnovenergyPropertyGrid from "../../Layout/InnovenergyPropertyGrid";
import { GroupContext } from "../../Context/GroupContextProvider";
interface I_InstallationFormProps { interface I_InstallationFormProps {
values: I_Installation; values: I_Installation;
@ -23,8 +24,11 @@ interface I_InstallationFormProps {
const InstallationForm = (props: I_InstallationFormProps) => { const InstallationForm = (props: I_InstallationFormProps) => {
const { values, additionalButtons, handleSubmit } = props; const { values, additionalButtons, handleSubmit } = props;
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [error, setError] = useState<AxiosError>();
const { fetchData: fetchInstallations } = useContext(InstallationsContext);
const { fetchData: fetchGroups } = useContext(GroupContext);
const { fetchData } = useContext(InstallationsContext);
const { getCurrentUser } = useContext(UserContext); const { getCurrentUser } = useContext(UserContext);
const readOnly = !getCurrentUser().hasWriteAccess; const readOnly = !getCurrentUser().hasWriteAccess;
@ -62,9 +66,16 @@ const InstallationForm = (props: I_InstallationFormProps) => {
onSubmit: (formikValues) => { onSubmit: (formikValues) => {
handleSubmit(values, formikValues) handleSubmit(values, formikValues)
.then(() => { .then(() => {
fetchData(); setOpen(true);
console.log(additionalButtons, "addbuttons");
additionalButtons && additionalButtons.length > 0
? fetchGroups()
: fetchInstallations();
}) })
.catch((err) => {}); .catch((err) => {
setError(err);
setOpen(true);
});
}, },
validationSchema, validationSchema,
}); });
@ -171,10 +182,14 @@ const InstallationForm = (props: I_InstallationFormProps) => {
onClose={handleClose} onClose={handleClose}
> >
<Alert onClose={handleClose} severity="success" sx={{ width: "100%" }}> <Alert onClose={handleClose} severity="success" sx={{ width: "100%" }}>
{error ? (
error.message
) : (
<FormattedMessage <FormattedMessage
id="updatedSuccessfully" id="updatedSuccessfully"
defaultMessage="Updated successfully" defaultMessage="Updated successfully"
/> />
)}
</Alert> </Alert>
</Snackbar> </Snackbar>
</form> </form>

View File

@ -1,4 +1,4 @@
import { Grid, colors } from "@mui/material"; import { Grid } from "@mui/material";
import { Routes, Route } from "react-router"; import { Routes, Route } from "react-router";
import LiveView from "./LiveView/LiveView"; import LiveView from "./LiveView/LiveView";
import InstallationTabs from "./InstallationTabs"; import InstallationTabs from "./InstallationTabs";

View File

@ -1,6 +1,5 @@
import TopologyView from "./TopologyView"; import TopologyView from "./TopologyView";
import { Box, useTheme } from "@mui/material"; import { Box, useTheme } from "@mui/material";
import { colors } from "../../../index";
const LiveView = () => { const LiveView = () => {
const theme = useTheme(); const theme = useTheme();

View File

@ -1,14 +1,14 @@
import { Box } from "@mui/material"; import { Box } from "@mui/material";
import { getBoxColor } from "../../../util/graph.util"; import { getBoxColor } from "../../../util/graph.util";
export interface BoxDataValue { export interface I_BoxDataValue {
unit: string; unit: string;
value: string | number; value: string | number;
} }
export type BoxData = { export type BoxData = {
label: string; label: string;
values: BoxDataValue[]; values: I_BoxDataValue[];
}; };
export type TopologyBoxProps = { export type TopologyBoxProps = {

View File

@ -1,4 +1,4 @@
import { Alert, Box, useTheme } from "@mui/material"; import { Alert, Box } from "@mui/material";
import TopologyColumn from "./TopologyColumn"; import TopologyColumn from "./TopologyColumn";
import { TimeSpan, UnixTime } from "../../../dataCache/time"; import { TimeSpan, UnixTime } from "../../../dataCache/time";
import { import {
@ -224,7 +224,6 @@ const TopologyView = () => {
/> />
</Alert> </Alert>
); );
return <div>TopologyView</div>;
}; };
export default TopologyView; export default TopologyView;

View File

@ -9,10 +9,10 @@ import routes from "../../../routes.json";
import React from "react"; import React from "react";
import InnovenergyTreeItem from "../../Layout/InnovenergyTreeItem"; import InnovenergyTreeItem from "../../Layout/InnovenergyTreeItem";
export interface TreeElement { export interface I_TreeElement {
id: string; id: string;
name: string; name: string;
children: TreeElement[]; children: I_TreeElement[];
checked?: boolean; checked?: boolean;
} }
@ -23,13 +23,13 @@ const CheckboxTree = () => {
routes.installations + routes.list + routes.log + ":id", routes.installations + routes.list + routes.log + ":id",
]); ]);
const getNodes = (element: TreeElement): null | ReactNode => { const getNodes = (element: I_TreeElement): null | ReactNode => {
return element.children.length > 0 ? renderTree(element.children) : null; return element.children.length > 0 ? renderTree(element.children) : null;
}; };
const handleClick = ( const handleClick = (
event: React.MouseEvent<HTMLButtonElement, MouseEvent>, event: React.MouseEvent<HTMLButtonElement, MouseEvent>,
element: TreeElement, element: I_TreeElement,
checked?: string checked?: string
) => { ) => {
if (checked) { if (checked) {
@ -46,7 +46,7 @@ const CheckboxTree = () => {
event.stopPropagation(); event.stopPropagation();
}; };
const renderTree = (data: TreeElement[]): ReactNode => { const renderTree = (data: I_TreeElement[]): ReactNode => {
return data.map((element) => { return data.map((element) => {
const checked = checkedToggles.find((toggle) => element.id === toggle); const checked = checkedToggles.find((toggle) => element.id === toggle);
const splitName = element.name.split("/"); const splitName = element.name.split("/");

View File

@ -9,13 +9,13 @@ import { useTheme } from "@mui/material";
import { colors } from "../../../../index"; import { colors } from "../../../../index";
import ShortcutButton from "./ShortcutButton"; import ShortcutButton from "./ShortcutButton";
interface DateRangePickerProps { interface I_DateRangePickerProps {
setRange: (value: Date[]) => void; setRange: (value: Date[]) => void;
range: Date[]; range: Date[];
getCacheSeries: (xaxisRange0: Date, xaxisRange1: Date) => void; getCacheSeries: (xaxisRange0: Date, xaxisRange1: Date) => void;
} }
const DateRangePicker = (props: DateRangePickerProps) => { const DateRangePicker = (props: I_DateRangePickerProps) => {
const { setRange, range, getCacheSeries } = props; const { setRange, range, getCacheSeries } = props;
const theme = useTheme(); const theme = useTheme();

View File

@ -2,14 +2,14 @@ import { UnixTime, TimeSpan } from "../../../../dataCache/time";
import { createTimes } from "../../../../util/graph.util"; import { createTimes } from "../../../../util/graph.util";
import InnovenergyButton from "../../../Layout/InnovenergyButton"; import InnovenergyButton from "../../../Layout/InnovenergyButton";
interface ShortcutButtonProps { interface I_ShortcutButtonProps {
setRange: (value: Date[]) => void; setRange: (value: Date[]) => void;
getCacheSeries: (xaxisRange0: Date, xaxisRange1: Date) => void; getCacheSeries: (xaxisRange0: Date, xaxisRange1: Date) => void;
dayRange: number; dayRange: number;
children?: React.ReactNode; children?: React.ReactNode;
} }
const ShortcutButton = (props: ShortcutButtonProps) => { const ShortcutButton = (props: I_ShortcutButtonProps) => {
return ( return (
<InnovenergyButton <InnovenergyButton
onClick={() => { onClick={() => {

View File

@ -1,7 +1,7 @@
import Plot from "react-plotly.js"; import Plot from "react-plotly.js";
import { RecordSeries } from "../../../dataCache/data"; import { RecordSeries } from "../../../dataCache/data";
import { import {
GraphData, I_GraphData,
createTimes, createTimes,
getTreeElements, getTreeElements,
isNumeric, isNumeric,
@ -11,15 +11,15 @@ import {
import { TimeRange, TimeSpan, UnixTime } from "../../../dataCache/time"; import { TimeRange, TimeSpan, UnixTime } from "../../../dataCache/time";
import { useCallback, useContext, useEffect, useMemo, useState } from "react"; import { useCallback, useContext, useEffect, useMemo, useState } from "react";
import { BehaviorSubject, startWith, throttleTime, withLatestFrom } from "rxjs"; import { BehaviorSubject, startWith, throttleTime, withLatestFrom } from "rxjs";
import DataCache, { FetchResult } from "../../../dataCache/dataCache"; import DataCache from "../../../dataCache/dataCache";
import { LogContext } from "../../Context/LogContextProvider"; import { LogContext } from "../../Context/LogContextProvider";
import { isDefined } from "../../../dataCache/utils/maybe"; import { isDefined } from "../../../dataCache/utils/maybe";
import { Data, Icons, Layout, PlotRelayoutEvent } from "plotly.js"; import { Data, Layout, PlotRelayoutEvent } from "plotly.js";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs"; import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
import DateRangePicker from "./DatePicker/DateRangePicker"; import DateRangePicker from "./DatePicker/DateRangePicker";
import { LocalizationProvider } from "@mui/x-date-pickers"; import { LocalizationProvider } from "@mui/x-date-pickers";
import { Alert, useTheme } from "@mui/material"; import { Alert } from "@mui/material";
import { S3CredentialsContext } from "../../Context/S3CredentialsContextProvider"; import { S3CredentialsContext } from "../../Context/S3CredentialsContextProvider";
const NUMBER_OF_NODES = 100; const NUMBER_OF_NODES = 100;
@ -66,7 +66,7 @@ const ScalarGraph = () => {
return () => subscription.unsubscribe(); return () => subscription.unsubscribe();
}, [toggles]); }, [toggles]);
const transformToGraphData = (input: RecordSeries): GraphData => { const transformToGraphData = (input: RecordSeries): I_GraphData => {
const transformedObject: any = {}; const transformedObject: any = {};
input.forEach((item) => { input.forEach((item) => {
@ -101,7 +101,7 @@ const ScalarGraph = () => {
y: [], y: [],
}, },
}), }),
{} as GraphData {} as I_GraphData
); );
}; };

View File

@ -1,4 +1,4 @@
import { Button, SxProps, Theme, colors, useTheme } from "@mui/material"; import { Button, SxProps, Theme, useTheme } from "@mui/material";
import { ReactNode } from "react"; import { ReactNode } from "react";
interface I_InnovenergyButtonProps { interface I_InnovenergyButtonProps {

View File

@ -1,12 +1,12 @@
import { List, useTheme } from "@mui/material"; import { List, useTheme } from "@mui/material";
import { ReactNode } from "react"; import { ReactNode } from "react";
interface InnovenergyListProps { interface I_InnovenergyListProps {
id: string; id: string;
children: ReactNode; children: ReactNode;
} }
const InnovenergyList = (props: InnovenergyListProps) => { const InnovenergyList = (props: I_InnovenergyListProps) => {
const theme = useTheme(); const theme = useTheme();
return ( return (
<List <List

View File

@ -2,12 +2,12 @@ import { InputLabel, TextField } from "@mui/material";
import { colors } from "../../index"; import { colors } from "../../index";
import { I_InnovenergyTextfieldProps } from "./InnovenergyTextfield"; import { I_InnovenergyTextfieldProps } from "./InnovenergyTextfield";
interface InnovenergyPropertyGridProps { interface I_InnovenergyPropertyGridProps {
rows: I_InnovenergyTextfieldProps[]; rows: I_InnovenergyTextfieldProps[];
} }
export const InnovenergyPropertyGrid = ( export const InnovenergyPropertyGrid = (
props: InnovenergyPropertyGridProps props: I_InnovenergyPropertyGridProps
) => { ) => {
return ( return (
<div style={{ display: "flex", flexDirection: "row" }}> <div style={{ display: "flex", flexDirection: "row" }}>

View File

@ -1,13 +1,13 @@
import { Alert, Snackbar } from "@mui/material"; import { Alert, Snackbar } from "@mui/material";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
interface InnovenergySnackbarProps { interface I_InnovenergySnackbarProps {
open: boolean; open: boolean;
setOpen: (value: boolean) => void; setOpen: (value: boolean) => void;
error?: any; error?: any;
} }
const InnovenergySnackbar = (props: InnovenergySnackbarProps) => { const InnovenergySnackbar = (props: I_InnovenergySnackbarProps) => {
const { open, setOpen, error } = props; const { open, setOpen, error } = props;
const handleClose = () => { const handleClose = () => {

View File

@ -1,15 +1,15 @@
import { SxProps, Tabs, useTheme } from "@mui/material"; import { Tabs, useTheme } from "@mui/material";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { colors } from "index"; import { colors } from "index";
interface AntTabsProps { interface I_AntTabsProps {
id: string; id: string;
value?: string; value?: string;
sx?: any; sx?: any;
children: ReactNode; children: ReactNode;
} }
const InnovenergyTabs = (props: AntTabsProps) => { const InnovenergyTabs = (props: I_AntTabsProps) => {
const theme = useTheme(); const theme = useTheme();
return ( return (
<Tabs <Tabs

View File

@ -9,7 +9,7 @@ const InnovenergyTreeItem = (props: TreeItemProps) => {
id={props.id} id={props.id}
nodeId={props.nodeId} nodeId={props.nodeId}
label={props.label} label={props.label}
onClick={() => props.onClick} onClick={props.onClick}
sx={{ sx={{
".MuiTreeItem-content": { ".MuiTreeItem-content": {
py: "10px", py: "10px",
@ -30,6 +30,7 @@ const InnovenergyTreeItem = (props: TreeItemProps) => {
}, },
borderRadius: "4px", borderRadius: "4px",
bgcolor: colors.greyDark, bgcolor: colors.greyDark,
...props.sx,
}} }}
> >
{props.children} {props.children}

View File

@ -1,12 +1,12 @@
import { MenuItem, Select } from "@mui/material"; import { MenuItem, Select } from "@mui/material";
import { FormattedMessage } from "react-intl"; import { FormattedMessage } from "react-intl";
interface LanguageSelectProps { interface I_LanguageSelectProps {
language: string; language: string;
setLanguage: (language: string) => void; setLanguage: (language: string) => void;
} }
const LanguageSelect = (props: LanguageSelectProps) => { const LanguageSelect = (props: I_LanguageSelectProps) => {
return ( return (
<Select <Select
color="secondary" color="secondary"

View File

@ -4,11 +4,11 @@ import axiosConfig from "../../config/axiosConfig";
import InnovenergyButton from "./InnovenergyButton"; import InnovenergyButton from "./InnovenergyButton";
import { useTheme } from "@mui/material"; import { useTheme } from "@mui/material";
interface LogoutButtonProps { interface I_LogoutButtonProps {
removeToken: () => void; removeToken: () => void;
} }
const LogoutButton = (props: LogoutButtonProps) => { const LogoutButton = (props: I_LogoutButtonProps) => {
const navigate = useNavigate(); const navigate = useNavigate();
const theme = useTheme(); const theme = useTheme();

View File

@ -1,4 +1,4 @@
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage } from "react-intl";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import useRouteMatch from "../../hooks/useRouteMatch"; import useRouteMatch from "../../hooks/useRouteMatch";
import routes from "../../routes.json"; import routes from "../../routes.json";

View File

@ -2,7 +2,6 @@ import {
OutlinedInputProps, OutlinedInputProps,
TextField, TextField,
TextFieldProps, TextFieldProps,
alpha,
styled, styled,
useTheme, useTheme,
} from "@mui/material"; } from "@mui/material";
@ -10,7 +9,7 @@ import { colors } from "index";
import { FC, useState } from "react"; import { FC, useState } from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
interface SearchSidebarProps { interface I_SearchSidebarProps {
listComponent: FC<{ searchQuery: string }>; listComponent: FC<{ searchQuery: string }>;
id: string; id: string;
height?: string; height?: string;
@ -45,11 +44,10 @@ const SearchInputTextfield = styled((props: TextFieldProps) => (
}, },
})); }));
const SearchSidebar = (props: SearchSidebarProps) => { const SearchSidebar = (props: I_SearchSidebarProps) => {
const { listComponent: ListComponent, id, height } = props; const { listComponent: ListComponent, id, height } = props;
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
const intl = useIntl(); const intl = useIntl();
const theme = useTheme();
return ( return (
<div style={{ height: height ?? "750px", overflow: "hidden" }}> <div style={{ height: height ?? "750px", overflow: "hidden" }}>

View File

@ -1,10 +1,4 @@
import { import { Dialog, DialogTitle, IconButton, DialogContent } from "@mui/material";
Dialog,
DialogTitle,
IconButton,
DialogContent,
colors,
} from "@mui/material";
import { useState } from "react"; import { useState } from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import axiosConfig from "../../config/axiosConfig"; import axiosConfig from "../../config/axiosConfig";

View File

@ -1,10 +1,4 @@
import { import { Box, CircularProgress, Alert, useTheme } from "@mui/material";
Box,
CircularProgress,
Alert,
collapseClasses,
useTheme,
} from "@mui/material";
import { AxiosError } from "axios"; import { AxiosError } from "axios";
import { useState, useEffect } from "react"; import { useState, useEffect } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";

View File

@ -28,11 +28,11 @@ const filterData = (searchQuery: string, data: I_User[] | undefined) => {
return data; return data;
}; };
interface UserListProps { interface I_UserListProps {
searchQuery: string; searchQuery: string;
} }
const UserList = (props: UserListProps) => { const UserList = (props: I_UserListProps) => {
const { availableUsers } = useContext(UsersContext); const { availableUsers } = useContext(UsersContext);
const filteredData = filterData(props.searchQuery, availableUsers); const filteredData = filterData(props.searchQuery, availableUsers);

View File

@ -1,14 +1,14 @@
import { Maybe } from "yup"; import { Maybe } from "yup";
import { Timestamped } from "./types"; import { Timestamped } from "./types";
import { isDefined } from "./utils/maybe"; import { isDefined } from "./utils/maybe";
import { CsvEntry } from "../util/graph.util"; import { I_CsvEntry } from "../util/graph.util";
export type DataRecord = Record<string, CsvEntry>; export type DataRecord = Record<string, I_CsvEntry>;
export type DataPoint = Timestamped<Maybe<DataRecord>>; export type DataPoint = Timestamped<Maybe<DataRecord>>;
export type RecordSeries = Array<DataPoint>; export type RecordSeries = Array<DataPoint>;
export type PointSeries = Array<Timestamped<Maybe<CsvEntry>>>; export type PointSeries = Array<Timestamped<Maybe<I_CsvEntry>>>;
export type DataSeries = Array<Maybe<CsvEntry>>; export type DataSeries = Array<Maybe<I_CsvEntry>>;
export function getPoints( export function getPoints(
recordSeries: RecordSeries, recordSeries: RecordSeries,

View File

@ -7,7 +7,7 @@ import { SkipListNode } from "./skipList/skipListNode";
import { RecordSeries } from "./data"; import { RecordSeries } from "./data";
import { isUndefined, Maybe } from "./utils/maybe"; import { isUndefined, Maybe } from "./utils/maybe";
import { isNumber } from "./utils/runtimeTypeChecking"; import { isNumber } from "./utils/runtimeTypeChecking";
import { CsvEntry } from "../util/graph.util"; import { I_CsvEntry } from "../util/graph.util";
export const FetchResult = { export const FetchResult = {
notAvailable: "N/A", notAvailable: "N/A",
@ -31,7 +31,7 @@ function reverseBits(x: number): number {
return x >>> 0; return x >>> 0;
} }
export default class DataCache<T extends Record<string, CsvEntry>> { export default class DataCache<T extends Record<string, I_CsvEntry>> {
private readonly cache: SkipList<Maybe<T>> = new SkipList<Maybe<T>>(); private readonly cache: SkipList<Maybe<T>> = new SkipList<Maybe<T>>();
private readonly resolution: TimeSpan; private readonly resolution: TimeSpan;
@ -104,7 +104,7 @@ export default class DataCache<T extends Record<string, CsvEntry>> {
const n = after.index - t; const n = after.index - t;
const pn = p + n; const pn = p + n;
let interpolated: Record<string, CsvEntry> = {}; let interpolated: Record<string, I_CsvEntry> = {};
//What about string nodes? like Alarms //What about string nodes? like Alarms
for (const k of Object.keys(dataBefore)) { for (const k of Object.keys(dataBefore)) {

View File

@ -0,0 +1,17 @@
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
body {
background-color: #f3f4f7;
}

View File

@ -1,6 +1,7 @@
import React from "react"; import React from "react";
import ReactDOM from "react-dom/client"; import ReactDOM from "react-dom/client";
import App from "./App"; import App from "./App";
import "./index.css";
import reportWebVitals from "./reportWebVitals"; import reportWebVitals from "./reportWebVitals";
import { createTheme, ThemeProvider } from "@mui/material"; import { createTheme, ThemeProvider } from "@mui/material";
import UserContextProvider from "./components/Context/UserContextProvider"; import UserContextProvider from "./components/Context/UserContextProvider";

View File

@ -1,14 +1,12 @@
import { t } from "testcafe";
import {Selector, t} from 'testcafe';
export async function login(name, pw) { export async function login(name, pw) {
await t await t
.typeText('#username-textfield', name) .typeText("#username-textfield", name)
.typeText('#password-textfield', pw) .typeText("#password-textfield", pw)
.click('.MuiButtonBase-root') //todo id .click(".MuiButtonBase-root"); //todo id
} }
export async function logout() { export async function logout() {
await t await t.click(".MuiButtonBase-root");
.click('.MuiButtonBase-root');
} }

View File

@ -1,14 +1,14 @@
import { Datum, TypedArray } from "plotly.js"; import { Datum, TypedArray } from "plotly.js";
import { TreeElement } from "../components/Installations/Log/CheckboxTree"; import { I_TreeElement } from "../components/Installations/Log/CheckboxTree";
import { TimeRange, UnixTime } from "../dataCache/time"; import { TimeRange, UnixTime } from "../dataCache/time";
import { DataPoint, DataRecord } from "../dataCache/data"; import { DataPoint, DataRecord } from "../dataCache/data";
import { isDefined } from "../dataCache/utils/maybe"; import { isDefined } from "../dataCache/utils/maybe";
import { import {
BoxData, BoxData,
BoxDataValue, I_BoxDataValue,
} from "../components/Installations/LiveView/TopologyBox"; } from "../components/Installations/LiveView/TopologyBox";
export interface GraphCoordinates { export interface I_GraphCoordinates {
x: Datum[] | Datum[][] | TypedArray; x: Datum[] | Datum[][] | TypedArray;
y: Datum[] | Datum[][] | TypedArray; y: Datum[] | Datum[][] | TypedArray;
xaxis?: string; xaxis?: string;
@ -32,8 +32,8 @@ export const createTimes = (
return roundedRange.sample(oneSpan); return roundedRange.sample(oneSpan);
}; };
export interface GraphData { export interface I_GraphData {
[path: string]: GraphCoordinates; [path: string]: I_GraphCoordinates;
} }
// connections must have the word Connection in the prop name, so the topology works correctly // connections must have the word Connection in the prop name, so the topology works correctly
@ -141,7 +141,7 @@ export const extractTopologyValues = (
const timeSeriesValue = timeSeriesData.value; const timeSeriesValue = timeSeriesData.value;
if (isDefined(timeSeriesValue)) { if (isDefined(timeSeriesValue)) {
return Object.keys(topologyPaths).reduce((acc, topologyKey) => { return Object.keys(topologyPaths).reduce((acc, topologyKey) => {
let topologyValues: BoxDataValue[]; let topologyValues: I_BoxDataValue[];
const values = topologyPaths[topologyKey as keyof TopologyValues].map( const values = topologyPaths[topologyKey as keyof TopologyValues].map(
(topologyPath) => timeSeriesValue[topologyPath] (topologyPath) => timeSeriesValue[topologyPath]
); );
@ -196,12 +196,12 @@ export const getHighestConnectionValue = (values: TopologyValues) =>
export const getAmount = ( export const getAmount = (
highestConnectionValue: number, highestConnectionValue: number,
values: BoxDataValue[] values: I_BoxDataValue[]
) => { ) => {
return Math.abs(values[0].value as number) / highestConnectionValue; return Math.abs(values[0].value as number) / highestConnectionValue;
}; };
export interface CsvEntry { export interface I_CsvEntry {
value: string | number; value: string | number;
unit: string; unit: string;
} }
@ -225,9 +225,9 @@ export const parseCsv = (text: string): DataRecord => {
}; };
export const insertTreeElements = ( export const insertTreeElements = (
children: TreeElement[] = [], children: I_TreeElement[] = [],
[head, ...tail]: string[] [head, ...tail]: string[]
): TreeElement[] => { ): I_TreeElement[] => {
let child = children.find((child) => child.name === head); let child = children.find((child) => child.name === head);
if (!child) { if (!child) {
@ -249,7 +249,7 @@ export const isText = (data: any): data is string => {
return typeof data === "string"; return typeof data === "string";
}; };
export const flattenBarGraphData = (arr: any): GraphCoordinates[] => { export const flattenBarGraphData = (arr: any): I_GraphCoordinates[] => {
return arr.reduce((flat: any, toFlatten: any) => { return arr.reduce((flat: any, toFlatten: any) => {
return flat.concat( return flat.concat(
Array.isArray(toFlatten) ? flattenBarGraphData(toFlatten) : toFlatten Array.isArray(toFlatten) ? flattenBarGraphData(toFlatten) : toFlatten
@ -277,7 +277,7 @@ export const isNumeric = (value: any) => {
return !isNaN(value) && !isNaN(parseFloat(value)); return !isNaN(value) && !isNaN(parseFloat(value));
}; };
export const transformToBarGraphData = (data: GraphCoordinates) => { export const transformToBarGraphData = (data: I_GraphCoordinates) => {
let names: string[] = []; let names: string[] = [];
const barGraphData = data.y.map((text, i) => { const barGraphData = data.y.map((text, i) => {
if (isText(text)) { if (isText(text)) {
@ -313,6 +313,6 @@ export const getTreeElements = (toggleValues: DataRecord) => {
) )
.reduce( .reduce(
(children, path) => insertTreeElements(children, path), (children, path) => insertTreeElements(children, path),
[] as TreeElement[] [] as I_TreeElement[]
); );
}; };

View File

@ -1,5 +1,4 @@
// TODO add if required or not export interface I_S3Credentials {
export interface S3Credentials {
s3Region: string; s3Region: string;
s3Provider: string; s3Provider: string;
s3Key: string; s3Key: string;
@ -7,7 +6,7 @@ export interface S3Credentials {
s3Bucket?: string; s3Bucket?: string;
} }
export interface I_Installation extends S3Credentials { export interface I_Installation extends I_S3Credentials {
type: string; type: string;
title?: string; title?: string;
status?: number; status?: number;
@ -35,37 +34,3 @@ export interface I_Folder {
type: string; type: string;
children?: (I_Installation | I_Folder)[]; children?: (I_Installation | I_Folder)[];
} }
interface I_Ac {
Current: number;
Voltage: number;
Phi?: number;
}
interface I_Dc {
Current: number;
Voltage: number;
}
export interface I_Device {
Name: string;
Type: string;
Ac?: I_Ac[];
Dc?: I_Dc;
Dc48?: I_Dc;
Frequency?: number;
Alarms?: any[];
Warnings?: any[];
MainState?: string;
"DC Power"?: number;
Soc?: number;
HeaterOn?: boolean;
EocReached?: boolean;
BatteryCold?: boolean;
Temperature?: number;
}
export interface I_GraphData {
TimeStamp: string;
Devices: I_Device[];
}

View File

@ -12,7 +12,7 @@ export interface I_User {
mustResetPassword: boolean; mustResetPassword: boolean;
} }
export interface UserWithInheritedAccess { export interface I_UserWithInheritedAccess {
folderId: number; folderId: number;
folderName: string; folderName: string;
user: I_User; user: I_User;
@ -20,7 +20,7 @@ export interface UserWithInheritedAccess {
export const filterDuplicateUsers = (data: any[]) => { export const filterDuplicateUsers = (data: any[]) => {
return data.reduce( return data.reduce(
(prev: UserWithInheritedAccess[], curr: UserWithInheritedAccess) => { (prev: I_UserWithInheritedAccess[], curr: I_UserWithInheritedAccess) => {
const foundUser = prev.find(({ user }) => user.id === curr.user.id); const foundUser = prev.find(({ user }) => user.id === curr.user.id);
if (foundUser) { if (foundUser) {
const prevIds = foundUser.user.folderIds const prevIds = foundUser.user.folderIds