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}
pt={3}
borderTop="2px solid"
borderColor={colors.darkGrey}
borderColor={colors.borderColor}
flex="1 0 auto"
>
<Container maxWidth="xl">

View File

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

View File

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

View File

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

View File

@ -1,21 +1,20 @@
import { createContext, ReactNode, useState } from "react";
import { I_User } from "../../util/user.util";
import { I_Installation, S3Credentials } from "../../util/types";
import { I_S3Credentials } from "../../util/types";
import { UnixTime } from "../../dataCache/time";
import { FetchResult } from "../../dataCache/dataCache";
import { DataRecord } from "../../dataCache/data";
import { S3Access } from "../../dataCache/S3/S3Access";
import { parseCsv } from "../../util/graph.util";
interface S3CredentialsContextProviderProps {
s3Credentials?: S3Credentials;
saveS3Credentials: (credentials: S3Credentials, id: string) => void;
interface I_S3CredentialsContextProviderProps {
s3Credentials?: I_S3Credentials;
saveS3Credentials: (credentials: I_S3Credentials, id: string) => void;
fetchData: (timestamp: UnixTime) => Promise<FetchResult<DataRecord>>;
}
export const S3CredentialsContext =
createContext<S3CredentialsContextProviderProps>({
s3Credentials: {} as S3Credentials,
createContext<I_S3CredentialsContextProviderProps>({
s3Credentials: {} as I_S3Credentials,
saveS3Credentials: () => {},
fetchData: () => ({} as Promise<FetchResult<DataRecord>>),
});
@ -25,9 +24,9 @@ const S3CredentialsContextProvider = ({
}: {
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";
setS3Credentials({ s3Bucket, ...credentials });
};

View File

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

View File

@ -8,14 +8,14 @@ import {
} from "react";
import { useParams } from "react-router-dom";
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";
interface UsersContextProviderProps {
interface I_UsersContextProviderProps {
directAccessUsers: I_User[];
setDirectAccessUsers: (value: I_User[]) => void;
inheritedAccessUsers: UserWithInheritedAccess[];
setInheritedAccessUsers: (value: UserWithInheritedAccess[]) => void;
inheritedAccessUsers: I_UserWithInheritedAccess[];
setInheritedAccessUsers: (value: I_UserWithInheritedAccess[]) => void;
availableUsers: I_User[];
setAvailableUsers: (value: I_User[]) => void;
getAvailableUsersForResource: () => I_User[];
@ -24,7 +24,7 @@ interface UsersContextProviderProps {
fetchAvailableUsers: () => Promise<void>;
}
export const UsersContext = createContext<UsersContextProviderProps>({
export const UsersContext = createContext<I_UsersContextProviderProps>({
directAccessUsers: [],
setDirectAccessUsers: () => {},
inheritedAccessUsers: [],
@ -48,7 +48,7 @@ export const UsersContext = createContext<UsersContextProviderProps>({
const UsersContextProvider = ({ children }: { children: ReactNode }) => {
const [directAccessUsers, setDirectAccessUsers] = useState<I_User[]>([]);
const [inheritedAccessUsers, setInheritedAccessUsers] = useState<
UserWithInheritedAccess[]
I_UserWithInheritedAccess[]
>([]);
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 {
filterDuplicateUsers,
UserWithInheritedAccess,
I_UserWithInheritedAccess,
} from "../../../util/user.util";
import routes from "../../../routes.json";
import PersonIcon from "@mui/icons-material/Person";
@ -29,7 +29,7 @@ const UsersWithInheritedAccess = () => {
return (
<>
{filterDuplicateUsers(inheritedAccessUsers).map(
({ user, folderName }: UserWithInheritedAccess) => {
({ user, folderName }: I_UserWithInheritedAccess) => {
return (
<Fragment key={user.id}>
<ListItem id={"inherited-access-user-list-item" + user.id}>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,19 +1,20 @@
import TreeView from "@mui/lab/TreeView";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
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 { Link } from "react-router-dom";
import routes from "../../routes.json";
import { GroupContext } from "../Context/GroupContextProvider";
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 InnovenergyTreeItem from "../Layout/InnovenergyTreeItem";
import TypeIcon from "./TypeIcon";
const GroupTree = () => {
const { setCurrentType, fetchData, data, loading } = useContext(GroupContext);
const { setCurrentType, fetchData, data, loading, getError } =
useContext(GroupContext);
const [openNodes, setOpenNodes] = useState<string[]>([]);
const [selected, setSelected] = useState<string>("");
const intl = useIntl();
@ -56,7 +57,11 @@ const GroupTree = () => {
<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)}
</InnovenergyTreeItem>
@ -100,6 +105,8 @@ const GroupTree = () => {
{renderTree(data)}
</TreeView>
);
} else if (getError) {
return <Alert severity="error">{getError.message} </Alert>;
}
return null;
};

View File

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

View File

@ -1,12 +1,9 @@
import { Alert, Box, CircularProgress, useTheme } from "@mui/material";
import { AxiosError } from "axios";
import { useContext, useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import axiosConfig from "../../../config/axiosConfig";
import { I_Folder, I_Installation } from "../../../util/types";
import InstallationForm from "./InstallationForm";
import { colors } from "../../../index";
import { S3CredentialsContext } from "../../Context/S3CredentialsContextProvider";
import MoveDialog from "../../Groups/Detail/MoveDialog";
interface I_InstallationProps {
@ -46,7 +43,7 @@ const Installation = (props: I_InstallationProps) => {
<InstallationForm
values={values}
handleSubmit={handleSubmit}
additionalButtons={props.hasMoveButton ? [moveDialog] : []}
additionalButtons={props.hasMoveButton ? [moveDialog] : undefined}
/>
<Box>
{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 { UserContext } from "../../Context/UserContextProvider";
import * as Yup from "yup";
import { AxiosResponse } from "axios";
import { AxiosError, AxiosResponse } from "axios";
import InnovenergyPropertyGrid from "../../Layout/InnovenergyPropertyGrid";
import { GroupContext } from "../../Context/GroupContextProvider";
interface I_InstallationFormProps {
values: I_Installation;
@ -23,8 +24,11 @@ interface I_InstallationFormProps {
const InstallationForm = (props: I_InstallationFormProps) => {
const { values, additionalButtons, handleSubmit } = props;
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 readOnly = !getCurrentUser().hasWriteAccess;
@ -62,9 +66,16 @@ const InstallationForm = (props: I_InstallationFormProps) => {
onSubmit: (formikValues) => {
handleSubmit(values, formikValues)
.then(() => {
fetchData();
setOpen(true);
console.log(additionalButtons, "addbuttons");
additionalButtons && additionalButtons.length > 0
? fetchGroups()
: fetchInstallations();
})
.catch((err) => {});
.catch((err) => {
setError(err);
setOpen(true);
});
},
validationSchema,
});
@ -171,10 +182,14 @@ const InstallationForm = (props: I_InstallationFormProps) => {
onClose={handleClose}
>
<Alert onClose={handleClose} severity="success" sx={{ width: "100%" }}>
<FormattedMessage
id="updatedSuccessfully"
defaultMessage="Updated successfully"
/>
{error ? (
error.message
) : (
<FormattedMessage
id="updatedSuccessfully"
defaultMessage="Updated successfully"
/>
)}
</Alert>
</Snackbar>
</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 LiveView from "./LiveView/LiveView";
import InstallationTabs from "./InstallationTabs";

View File

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

View File

@ -1,14 +1,14 @@
import { Box } from "@mui/material";
import { getBoxColor } from "../../../util/graph.util";
export interface BoxDataValue {
export interface I_BoxDataValue {
unit: string;
value: string | number;
}
export type BoxData = {
label: string;
values: BoxDataValue[];
values: I_BoxDataValue[];
};
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 { TimeSpan, UnixTime } from "../../../dataCache/time";
import {
@ -224,7 +224,6 @@ const TopologyView = () => {
/>
</Alert>
);
return <div>TopologyView</div>;
};
export default TopologyView;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,13 +1,13 @@
import { Alert, Snackbar } from "@mui/material";
import { FormattedMessage } from "react-intl";
interface InnovenergySnackbarProps {
interface I_InnovenergySnackbarProps {
open: boolean;
setOpen: (value: boolean) => void;
error?: any;
}
const InnovenergySnackbar = (props: InnovenergySnackbarProps) => {
const InnovenergySnackbar = (props: I_InnovenergySnackbarProps) => {
const { open, setOpen, error } = props;
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 { colors } from "index";
interface AntTabsProps {
interface I_AntTabsProps {
id: string;
value?: string;
sx?: any;
children: ReactNode;
}
const InnovenergyTabs = (props: AntTabsProps) => {
const InnovenergyTabs = (props: I_AntTabsProps) => {
const theme = useTheme();
return (
<Tabs

View File

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

View File

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

View File

@ -4,11 +4,11 @@ import axiosConfig from "../../config/axiosConfig";
import InnovenergyButton from "./InnovenergyButton";
import { useTheme } from "@mui/material";
interface LogoutButtonProps {
interface I_LogoutButtonProps {
removeToken: () => void;
}
const LogoutButton = (props: LogoutButtonProps) => {
const LogoutButton = (props: I_LogoutButtonProps) => {
const navigate = useNavigate();
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 useRouteMatch from "../../hooks/useRouteMatch";
import routes from "../../routes.json";

View File

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

View File

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

View File

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

View File

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

View File

@ -1,14 +1,14 @@
import { Maybe } from "yup";
import { Timestamped } from "./types";
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 RecordSeries = Array<DataPoint>;
export type PointSeries = Array<Timestamped<Maybe<CsvEntry>>>;
export type DataSeries = Array<Maybe<CsvEntry>>;
export type PointSeries = Array<Timestamped<Maybe<I_CsvEntry>>>;
export type DataSeries = Array<Maybe<I_CsvEntry>>;
export function getPoints(
recordSeries: RecordSeries,

View File

@ -7,7 +7,7 @@ import { SkipListNode } from "./skipList/skipListNode";
import { RecordSeries } from "./data";
import { isUndefined, Maybe } from "./utils/maybe";
import { isNumber } from "./utils/runtimeTypeChecking";
import { CsvEntry } from "../util/graph.util";
import { I_CsvEntry } from "../util/graph.util";
export const FetchResult = {
notAvailable: "N/A",
@ -31,7 +31,7 @@ function reverseBits(x: number): number {
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 resolution: TimeSpan;
@ -104,7 +104,7 @@ export default class DataCache<T extends Record<string, CsvEntry>> {
const n = after.index - t;
const pn = p + n;
let interpolated: Record<string, CsvEntry> = {};
let interpolated: Record<string, I_CsvEntry> = {};
//What about string nodes? like Alarms
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 ReactDOM from "react-dom/client";
import App from "./App";
import "./index.css";
import reportWebVitals from "./reportWebVitals";
import { createTheme, ThemeProvider } from "@mui/material";
import UserContextProvider from "./components/Context/UserContextProvider";

View File

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

View File

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

View File

@ -1,5 +1,4 @@
// TODO add if required or not
export interface S3Credentials {
export interface I_S3Credentials {
s3Region: string;
s3Provider: string;
s3Key: string;
@ -7,7 +6,7 @@ export interface S3Credentials {
s3Bucket?: string;
}
export interface I_Installation extends S3Credentials {
export interface I_Installation extends I_S3Credentials {
type: string;
title?: string;
status?: number;
@ -35,37 +34,3 @@ export interface I_Folder {
type: string;
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;
}
export interface UserWithInheritedAccess {
export interface I_UserWithInheritedAccess {
folderId: number;
folderName: string;
user: I_User;
@ -20,7 +20,7 @@ export interface UserWithInheritedAccess {
export const filterDuplicateUsers = (data: any[]) => {
return data.reduce(
(prev: UserWithInheritedAccess[], curr: UserWithInheritedAccess) => {
(prev: I_UserWithInheritedAccess[], curr: I_UserWithInheritedAccess) => {
const foundUser = prev.find(({ user }) => user.id === curr.user.id);
if (foundUser) {
const prevIds = foundUser.user.folderIds