change style for multiple pages, change how s3 credentials are create
This commit is contained in:
parent
72ced4be3e
commit
3e099a68cb
|
@ -1,20 +1,20 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8"/>
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000"/>
|
||||||
<meta
|
<meta
|
||||||
name="description"
|
name="description"
|
||||||
content="Web site created using create-react-app"
|
content="Web site created using create-react-app"
|
||||||
/>
|
/>
|
||||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
|
||||||
<!--
|
<!--
|
||||||
manifest.json provides metadata used when your web app is installed on a
|
manifest.json provides metadata used when your web app is installed on a
|
||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
-->
|
-->
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
|
||||||
<!--
|
<!--
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
Notice the use of %PUBLIC_URL% in the tags above.
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
|
@ -25,11 +25,11 @@
|
||||||
Learn how to configure a non-root public URL by running `npm run build`.
|
Learn how to configure a non-root public URL by running `npm run build`.
|
||||||
-->
|
-->
|
||||||
<title>Innovenergy</title>
|
<title>Innovenergy</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||||
<div id="root"></div>
|
<div id="root" style="height: 100vh; display: flex; flex-direction: column;"></div>
|
||||||
<!--
|
<!--
|
||||||
This HTML file is a template.
|
This HTML file is a template.
|
||||||
If you open it directly in the browser, you will see an empty page.
|
If you open it directly in the browser, you will see an empty page.
|
||||||
|
|
||||||
|
@ -38,6 +38,6 @@
|
||||||
|
|
||||||
To begin the development, run `npm start` or `yarn start`.
|
To begin the development, run `npm start` or `yarn start`.
|
||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
-->
|
-->
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -2,7 +2,7 @@ import useToken from "./hooks/useToken";
|
||||||
import Login from "./Login";
|
import Login from "./Login";
|
||||||
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
|
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
|
||||||
|
|
||||||
import { Container, Grid, colors } from "@mui/material";
|
import { Container, Grid, colors, Box } from "@mui/material";
|
||||||
import routes from "./routes.json";
|
import routes from "./routes.json";
|
||||||
import { IntlProvider, MessageFormatElement } from "react-intl";
|
import { IntlProvider, MessageFormatElement } from "react-intl";
|
||||||
import { useContext, useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
|
@ -12,11 +12,11 @@ import fr from "./lang/fr.json";
|
||||||
import LanguageSelect from "./components/Layout/LanguageSelect";
|
import LanguageSelect from "./components/Layout/LanguageSelect";
|
||||||
import LogoutButton from "./components/Layout/LogoutButton";
|
import LogoutButton from "./components/Layout/LogoutButton";
|
||||||
import Users from "./components/Users/Users";
|
import Users from "./components/Users/Users";
|
||||||
import NavigationButtons from "./components/Layout/NavigationButtons";
|
import NavigationTabs from "./components/Layout/NavigationTabs";
|
||||||
import InstallationPage from "./components/Installations/InstallationPage";
|
import InstallationPage from "./components/Installations/InstallationPage";
|
||||||
import { UserContext } from "./components/Context/UserContextProvider";
|
import { UserContext } from "./components/Context/UserContextProvider";
|
||||||
import ResetPassword from "./ResetPassword";
|
import ResetPassword from "./ResetPassword";
|
||||||
import innovenergyLogo from "./resources/test.gif";
|
import innovenergyLogo from "./resources/innoveng_logo_on_orange.png";
|
||||||
|
|
||||||
const App = () => {
|
const App = () => {
|
||||||
const { token, setToken, removeToken } = useToken();
|
const { token, setToken, removeToken } = useToken();
|
||||||
|
@ -48,9 +48,9 @@ const App = () => {
|
||||||
locale={language}
|
locale={language}
|
||||||
defaultLocale="EN"
|
defaultLocale="EN"
|
||||||
>
|
>
|
||||||
<Container maxWidth="xl" sx={{ marginTop: 2, height: "100vh" }}>
|
<Container maxWidth="xl" sx={{ pt: 2 }}>
|
||||||
<Grid container maxHeight="20vh">
|
<Grid container>
|
||||||
<Grid item xs={3} container justifyContent="flex-start">
|
<Grid item xs={3} container justifyContent="flex-start" mb={2}>
|
||||||
<img src={innovenergyLogo} alt="innovenergy logo" height="100" />
|
<img src={innovenergyLogo} alt="innovenergy logo" height="100" />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid
|
<Grid
|
||||||
|
@ -64,11 +64,22 @@ const App = () => {
|
||||||
<LogoutButton removeToken={removeToken} />
|
<LogoutButton removeToken={removeToken} />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid container spacing={2} mt={2}>
|
</Container>
|
||||||
<Grid item xs={3} container justifyContent="flex-start">
|
<Container maxWidth="xl" sx={{ pt: 2 }}>
|
||||||
<NavigationButtons />
|
<Grid spacing={2} width="100%">
|
||||||
|
<Grid item xs={3}>
|
||||||
|
<NavigationTabs />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Container>
|
||||||
|
<Box
|
||||||
|
bgcolor="#eaecf1"
|
||||||
|
pt={3}
|
||||||
|
borderTop="2px solid"
|
||||||
|
borderColor=" #a8b0be"
|
||||||
|
flex="1 0 auto"
|
||||||
|
>
|
||||||
|
<Container maxWidth="xl">
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
path="*"
|
path="*"
|
||||||
|
@ -83,6 +94,7 @@ const App = () => {
|
||||||
<Route path={routes.users + "*"} element={<Users />} />
|
<Route path={routes.users + "*"} element={<Users />} />
|
||||||
</Routes>
|
</Routes>
|
||||||
</Container>
|
</Container>
|
||||||
|
</Box>
|
||||||
</IntlProvider>
|
</IntlProvider>
|
||||||
</BrowserRouter>
|
</BrowserRouter>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,29 +1,89 @@
|
||||||
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";
|
||||||
|
import { I_Installation, 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 InstallationContextProviderProps {
|
interface S3CredentialsContextProviderProps {
|
||||||
s3Credentials?: I_User;
|
s3Credentials?: S3Credentials;
|
||||||
setS3Credentials: (value: I_User) => void;
|
saveS3Credentials: (credentials: S3Credentials, id: string) => void;
|
||||||
|
fetchData: (timestamp: UnixTime) => Promise<FetchResult<DataRecord>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const UserContext = createContext<InstallationContextProviderProps>({
|
export const S3CredentialsContext =
|
||||||
s3Credentials: {} as I_User,
|
createContext<S3CredentialsContextProviderProps>({
|
||||||
setS3Credentials: () => {},
|
s3Credentials: {} as S3Credentials,
|
||||||
});
|
saveS3Credentials: () => {},
|
||||||
|
fetchData: () => ({} as Promise<FetchResult<DataRecord>>),
|
||||||
|
});
|
||||||
|
|
||||||
const UserContextProvider = ({ children }: { children: ReactNode }) => {
|
const S3CredentialsContextProvider = ({
|
||||||
const [s3Credentials, setS3Credentials] = useState<I_User>();
|
children,
|
||||||
|
}: {
|
||||||
|
children: ReactNode;
|
||||||
|
}) => {
|
||||||
|
const [s3Credentials, setS3Credentials] = useState<S3Credentials>();
|
||||||
|
|
||||||
|
console.log("creds", s3Credentials);
|
||||||
|
const saveS3Credentials = (credentials: S3Credentials, id: string) => {
|
||||||
|
//const s3Bucket = id + "-3e5b3069-214a-43ee-8d85-57d72000c19d";
|
||||||
|
/* const s3Bucket = "saliomameiringen";
|
||||||
|
|
||||||
|
setS3Credentials({ s3Bucket, ...credentials });*/
|
||||||
|
setS3Credentials({
|
||||||
|
s3Region: "sos-ch-dk-2",
|
||||||
|
s3Provider: "exo.io",
|
||||||
|
s3Key: "EXO15c0bf710e158e9b83270f0a",
|
||||||
|
s3Secret: "Dd5jYSiZtt_Zt5Ba5mDmaiLCdASUaKLfduSKY-SU-lg",
|
||||||
|
s3Bucket: "saliomameiringen",
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchData = (timestamp: UnixTime): Promise<FetchResult<DataRecord>> => {
|
||||||
|
const s3Path = `${timestamp.ticks}.csv`;
|
||||||
|
if (s3Credentials && s3Credentials.s3Bucket) {
|
||||||
|
const s3Access = new S3Access(
|
||||||
|
s3Credentials.s3Bucket,
|
||||||
|
s3Credentials.s3Region,
|
||||||
|
s3Credentials.s3Provider,
|
||||||
|
s3Credentials.s3Key,
|
||||||
|
s3Credentials.s3Secret
|
||||||
|
);
|
||||||
|
return s3Access
|
||||||
|
.get(s3Path)
|
||||||
|
.then(async (r) => {
|
||||||
|
if (r.status === 404) {
|
||||||
|
return Promise.resolve(FetchResult.notAvailable);
|
||||||
|
} else if (r.status === 200) {
|
||||||
|
const text = await r.text();
|
||||||
|
return parseCsv(text);
|
||||||
|
} else {
|
||||||
|
console.error("unexpected status code");
|
||||||
|
return Promise.resolve(FetchResult.notAvailable);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.log("catch", e);
|
||||||
|
return Promise.resolve(FetchResult.tryLater);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Promise.resolve(FetchResult.tryLater);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UserContext.Provider
|
<S3CredentialsContext.Provider
|
||||||
value={{
|
value={{
|
||||||
s3Credentials: s3Credentials,
|
s3Credentials,
|
||||||
setS3Credentials: setS3Credentials,
|
saveS3Credentials,
|
||||||
|
fetchData,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</UserContext.Provider>
|
</S3CredentialsContext.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UserContextProvider;
|
export default S3CredentialsContextProvider;
|
||||||
|
|
|
@ -7,8 +7,27 @@ import GroupContextProvider from "../Context/GroupContextProvider";
|
||||||
import GroupTree from "./Tree/GroupTree";
|
import GroupTree from "./Tree/GroupTree";
|
||||||
import AccessManagement from "./AccessManagement/AccessManagement";
|
import AccessManagement from "./AccessManagement/AccessManagement";
|
||||||
import Installation from "../Installations/Installation";
|
import Installation from "../Installations/Installation";
|
||||||
|
import useRouteMatch from "../../hooks/useRouteMatch";
|
||||||
|
import useInstallation from "../../hooks/useInstallation";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
const Groups = () => {
|
const Groups = () => {
|
||||||
|
const routeMatch = useRouteMatch([
|
||||||
|
routes.installations + routes.tree + ":view/:id",
|
||||||
|
]);
|
||||||
|
const {
|
||||||
|
data: currentInstallation,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
getInstallation,
|
||||||
|
} = useInstallation();
|
||||||
|
|
||||||
|
const id = routeMatch?.params?.id;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// TODO remove if
|
||||||
|
getInstallation(id);
|
||||||
|
}, [id]);
|
||||||
return (
|
return (
|
||||||
<GroupContextProvider>
|
<GroupContextProvider>
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
|
@ -25,7 +44,14 @@ const Groups = () => {
|
||||||
/>
|
/>
|
||||||
<Route
|
<Route
|
||||||
path={routes.installation + ":id"}
|
path={routes.installation + ":id"}
|
||||||
element={<Installation hasMoveButton />}
|
element={
|
||||||
|
<Installation
|
||||||
|
hasMoveButton
|
||||||
|
error={error}
|
||||||
|
values={currentInstallation}
|
||||||
|
loading={loading}
|
||||||
|
/>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
|
@ -11,6 +11,7 @@ import { instanceOfFolder } from "../../../util/group.util";
|
||||||
import { Grid, CircularProgress, useTheme } from "@mui/material";
|
import { Grid, CircularProgress, useTheme } from "@mui/material";
|
||||||
import { useIntl } from "react-intl";
|
import { useIntl } from "react-intl";
|
||||||
import { colors } from "../../..";
|
import { colors } from "../../..";
|
||||||
|
import { color } from "chart.js/helpers";
|
||||||
|
|
||||||
const GroupTree = () => {
|
const GroupTree = () => {
|
||||||
const { setCurrentType, fetchData, data, loading } = useContext(GroupContext);
|
const { setCurrentType, fetchData, data, loading } = useContext(GroupContext);
|
||||||
|
@ -54,7 +55,14 @@ const GroupTree = () => {
|
||||||
label={element.name}
|
label={element.name}
|
||||||
onClick={() => setCurrentType(element.type)}
|
onClick={() => setCurrentType(element.type)}
|
||||||
sx={{
|
sx={{
|
||||||
".MuiTreeItem-content": { paddingY: "5px" },
|
".MuiTreeItem-content": { py: "10px" },
|
||||||
|
".Mui-selected": {
|
||||||
|
backgroundColor: theme.palette.secondary.main,
|
||||||
|
},
|
||||||
|
".Mui-selected:hover": {
|
||||||
|
backgroundColor: theme.palette.secondary.main,
|
||||||
|
},
|
||||||
|
".Mui-focused": { backgroundColor: theme.palette.secondary.main },
|
||||||
bgcolor: colors.greyDark,
|
bgcolor: colors.greyDark,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
}}
|
}}
|
||||||
|
@ -68,7 +76,7 @@ const GroupTree = () => {
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<Grid container justifyContent="center" width="100%">
|
<Grid container justifyContent="center" width="100%">
|
||||||
<CircularProgress sx={{color: theme.palette.secondary.main}} />
|
<CircularProgress sx={{ color: theme.palette.secondary.main }} />
|
||||||
</Grid>
|
</Grid>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,24 @@
|
||||||
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 { useEffect, useState } from "react";
|
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_Installation } from "../../util/types";
|
import { I_Installation } from "../../util/types";
|
||||||
import InstallationForm from "./InstallationForm";
|
import InstallationForm from "./InstallationForm";
|
||||||
import { colors } from "../..";
|
import { colors } from "../..";
|
||||||
|
import { S3CredentialsContext } from "../Context/S3CredentialsContextProvider";
|
||||||
|
|
||||||
interface I_InstallationProps {
|
interface I_InstallationProps {
|
||||||
|
loading?: boolean;
|
||||||
|
values?: I_Installation;
|
||||||
|
error?: AxiosError;
|
||||||
hasMoveButton?: boolean;
|
hasMoveButton?: boolean;
|
||||||
}
|
}
|
||||||
const Installation = (props: I_InstallationProps) => {
|
|
||||||
const { id } = useParams();
|
|
||||||
const [values, setValues] = useState<I_Installation>();
|
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [error, setError] = useState<AxiosError>();
|
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
useEffect(() => {
|
const Installation = (props: I_InstallationProps) => {
|
||||||
setLoading(true);
|
const { hasMoveButton, values, loading, error } = props;
|
||||||
axiosConfig
|
const { id } = useParams();
|
||||||
.get("/GetInstallationById?id=" + id)
|
const theme = useTheme();
|
||||||
.then((res) => {
|
|
||||||
setValues(res.data);
|
|
||||||
setLoading(false);
|
|
||||||
})
|
|
||||||
.catch((err: AxiosError) => {
|
|
||||||
setError(err);
|
|
||||||
setLoading(false);
|
|
||||||
});
|
|
||||||
}, [id]);
|
|
||||||
|
|
||||||
if (values && values.id && values.id.toString() === id) {
|
if (values && values.id && values.id.toString() === id) {
|
||||||
return (
|
return (
|
||||||
|
@ -51,7 +40,7 @@ const Installation = (props: I_InstallationProps) => {
|
||||||
<InstallationForm
|
<InstallationForm
|
||||||
values={values}
|
values={values}
|
||||||
id={id}
|
id={id}
|
||||||
hasMoveButton={props.hasMoveButton}
|
hasMoveButton={hasMoveButton}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
|
@ -60,7 +49,7 @@ const Installation = (props: I_InstallationProps) => {
|
||||||
<Box
|
<Box
|
||||||
sx={{ width: 1 / 2, justifyContent: "center", display: "flex", mt: 10 }}
|
sx={{ width: 1 / 2, justifyContent: "center", display: "flex", mt: 10 }}
|
||||||
>
|
>
|
||||||
<CircularProgress sx={{ m: 2 ,color: theme.palette.secondary.main}}/>
|
<CircularProgress sx={{ m: 2, color: theme.palette.secondary.main }} />
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
} else if (error) {
|
} else if (error) {
|
||||||
|
|
|
@ -70,13 +70,12 @@ const InstallationList = (props: InstallationListProps) => {
|
||||||
<List
|
<List
|
||||||
sx={{
|
sx={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
bgcolor: "background.paper",
|
|
||||||
position: "relative",
|
position: "relative",
|
||||||
overflow: "auto",
|
overflow: "auto",
|
||||||
py: 0,
|
py: 0,
|
||||||
mt: 1,
|
mt: 1,
|
||||||
borderRadius: 1.5,
|
borderRadius: 1.5,
|
||||||
height:
|
maxHeight:
|
||||||
routeMatch?.pattern.path ===
|
routeMatch?.pattern.path ===
|
||||||
routes.installations + routes.list + routes.log + ":id"
|
routes.installations + routes.list + routes.log + ":id"
|
||||||
? "130px"
|
? "130px"
|
||||||
|
@ -93,7 +92,7 @@ const InstallationList = (props: InstallationListProps) => {
|
||||||
to={
|
to={
|
||||||
getPathWithoutId(routeMatch?.pattern?.path) + installation.id
|
getPathWithoutId(routeMatch?.pattern?.path) + installation.id
|
||||||
}
|
}
|
||||||
style={{ textDecoration: "none", color: colors.blueBlack }}
|
style={{ textDecoration: "none", color: colors.black }}
|
||||||
>
|
>
|
||||||
<ListItemButton
|
<ListItemButton
|
||||||
id={"installation-list-button-" + installation.id}
|
id={"installation-list-button-" + installation.id}
|
||||||
|
|
|
@ -4,18 +4,26 @@ import ModeButtons from "../Layout/ModeButtons";
|
||||||
import Installations from "./Installations";
|
import Installations from "./Installations";
|
||||||
import routes from "../../routes.json";
|
import routes from "../../routes.json";
|
||||||
import { Grid } from "@mui/material";
|
import { Grid } from "@mui/material";
|
||||||
|
import S3CredentialsContextProvider from "../Context/S3CredentialsContextProvider";
|
||||||
|
|
||||||
const InstallationPage = () => {
|
const InstallationPage = () => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Grid container spacing={2} marginTop={1}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={3}>
|
<Grid item xs={3}>
|
||||||
<ModeButtons />
|
<ModeButtons />
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path={routes.tree + "*"} element={<Groups />} />
|
<Route path={routes.tree + "*"} element={<Groups />} />
|
||||||
<Route path={routes.list + "*"} element={<Installations />} />
|
<Route
|
||||||
|
path={routes.list + "*"}
|
||||||
|
element={
|
||||||
|
<S3CredentialsContextProvider>
|
||||||
|
<Installations />
|
||||||
|
</S3CredentialsContextProvider>
|
||||||
|
}
|
||||||
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -25,7 +25,6 @@ const InstallationTabs = () => {
|
||||||
if (id) {
|
if (id) {
|
||||||
return (
|
return (
|
||||||
<Box sx={{ width: "100%" }}>
|
<Box sx={{ width: "100%" }}>
|
||||||
<Box sx={{}}>
|
|
||||||
<InnovenergyTabs
|
<InnovenergyTabs
|
||||||
id="installation-tabs"
|
id="installation-tabs"
|
||||||
value={routeMatch?.pattern?.path ?? routes.installation + ":id"}
|
value={routeMatch?.pattern?.path ?? routes.installation + ":id"}
|
||||||
|
@ -53,23 +52,21 @@ const InstallationTabs = () => {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<InnovenergyTab
|
<InnovenergyTab
|
||||||
|
id={"installation-tab-liveView"}
|
||||||
sx={{
|
sx={{
|
||||||
"&.Mui-selected": {
|
"&.Mui-selected": {
|
||||||
color: colors.black,
|
color: colors.black,
|
||||||
backgroundColor: "white",
|
backgroundColor: theme.palette.primary.dark,
|
||||||
borderColor: theme.palette.text.disabled,
|
borderColor: theme.palette.text.disabled,
|
||||||
borderBottom: 0,
|
borderBottom: 0,
|
||||||
mb: -1 / 8,
|
mb: -1 / 8,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
id={"installation-tab-liveView"}
|
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
id: "liveView",
|
id: "liveView",
|
||||||
defaultMessage: "Live view",
|
defaultMessage: "Live view",
|
||||||
})}
|
})}
|
||||||
value={
|
value={routes.installations + routes.list + routes.liveView + ":id"}
|
||||||
routes.installations + routes.list + routes.liveView + ":id"
|
|
||||||
}
|
|
||||||
component={Link}
|
component={Link}
|
||||||
to={routes.liveView + id}
|
to={routes.liveView + id}
|
||||||
/>
|
/>
|
||||||
|
@ -77,7 +74,7 @@ const InstallationTabs = () => {
|
||||||
sx={{
|
sx={{
|
||||||
"&.Mui-selected": {
|
"&.Mui-selected": {
|
||||||
color: colors.black,
|
color: colors.black,
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: theme.palette.primary.dark,
|
||||||
borderColor: theme.palette.text.disabled,
|
borderColor: theme.palette.text.disabled,
|
||||||
borderBottom: 0,
|
borderBottom: 0,
|
||||||
mb: -1 / 8,
|
mb: -1 / 8,
|
||||||
|
@ -94,7 +91,6 @@ const InstallationTabs = () => {
|
||||||
/>
|
/>
|
||||||
</InnovenergyTabs>
|
</InnovenergyTabs>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -13,20 +13,47 @@ import LogContextProvider from "../Context/LogContextProvider";
|
||||||
import useRouteMatch from "../../hooks/useRouteMatch";
|
import useRouteMatch from "../../hooks/useRouteMatch";
|
||||||
import { Background } from "reactflow";
|
import { Background } from "reactflow";
|
||||||
import { red } from "@mui/material/colors";
|
import { red } from "@mui/material/colors";
|
||||||
|
import S3CredentialsContextProvider, {
|
||||||
|
S3CredentialsContext,
|
||||||
|
} from "../Context/S3CredentialsContextProvider";
|
||||||
|
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";
|
||||||
|
import { useParams } from "react-router-dom";
|
||||||
|
import { useContext, useEffect, useState } from "react";
|
||||||
|
import axiosConfig from "../../config/axiosConfig";
|
||||||
|
import { I_Installation } from "../../util/types";
|
||||||
|
import { AxiosError } from "axios/index";
|
||||||
|
import useInstallation from "../../hooks/useInstallation";
|
||||||
|
|
||||||
const Installations = () => {
|
const Installations = () => {
|
||||||
const routeMatch = useRouteMatch([
|
const routeMatch = useRouteMatch([
|
||||||
routes.installations + routes.list + routes.log + ":id",
|
routes.installations + routes.list + ":view/:id",
|
||||||
]);
|
]);
|
||||||
|
const {
|
||||||
|
data: currentInstallation,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
getInstallation,
|
||||||
|
} = useInstallation();
|
||||||
|
const id = routeMatch?.params?.id;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// TODO remove if
|
||||||
|
getInstallation(id);
|
||||||
|
}, [id]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InstallationsContextProvider>
|
<InstallationsContextProvider>
|
||||||
<LogContextProvider>
|
<LogContextProvider>
|
||||||
<Grid container spacing={2} height="100%">
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={3}>
|
<Grid item xs={3}>
|
||||||
<SearchSidebar
|
<SearchSidebar
|
||||||
id="installations-search-sidebar"
|
id="installations-search-sidebar"
|
||||||
listComponent={InstallationList}
|
listComponent={InstallationList}
|
||||||
height={routeMatch ? "200px" : undefined}
|
height={routeMatch?.params?.view === "log" ? "200px" : undefined}
|
||||||
/>
|
/>
|
||||||
<CheckboxTree />
|
<CheckboxTree />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
@ -35,7 +62,13 @@ const Installations = () => {
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route
|
<Route
|
||||||
path={routes.installation + ":id"}
|
path={routes.installation + ":id"}
|
||||||
element={<Installation />}
|
element={
|
||||||
|
<Installation
|
||||||
|
loading={loading}
|
||||||
|
values={currentInstallation}
|
||||||
|
error={error}
|
||||||
|
/>
|
||||||
|
}
|
||||||
index
|
index
|
||||||
/>
|
/>
|
||||||
<Route path={routes.liveView + ":id"} element={<LiveView />} />
|
<Route path={routes.liveView + ":id"} element={<LiveView />} />
|
||||||
|
|
|
@ -1,7 +1,28 @@
|
||||||
import TopologyView from "./Log/TopologyView";
|
import TopologyView from "./Log/TopologyView";
|
||||||
|
import { Box, useTheme } from "@mui/material";
|
||||||
|
import { colors } from "../../index";
|
||||||
|
|
||||||
const LiveView = () => {
|
const LiveView = () => {
|
||||||
return <TopologyView />;
|
const theme = useTheme();
|
||||||
|
return (
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
py: 3,
|
||||||
|
bgcolor: colors.greyDark,
|
||||||
|
px: 1,
|
||||||
|
borderLeft: 2,
|
||||||
|
borderRight: 2,
|
||||||
|
borderBottom: 2,
|
||||||
|
borderTopLeftRadius: 0,
|
||||||
|
WebkitBorderTopRightRadius: 0,
|
||||||
|
borderBottomLeftRadius: 4,
|
||||||
|
borderBottomRightRadius: 4,
|
||||||
|
borderColor: theme.palette.text.disabled,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<TopologyView />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LiveView;
|
export default LiveView;
|
||||||
|
|
|
@ -49,7 +49,6 @@ const CheckboxTree = () => {
|
||||||
) => {
|
) => {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
};
|
};
|
||||||
const theme = useTheme();
|
|
||||||
const renderTree = (data: TreeElement[]): ReactNode => {
|
const renderTree = (data: 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);
|
||||||
|
@ -66,19 +65,20 @@ const CheckboxTree = () => {
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={!!checked}
|
checked={!!checked}
|
||||||
onClick={(e) => handleClick(e, element, checked)}
|
onClick={(e) => handleClick(e, element, checked)}
|
||||||
style={{
|
|
||||||
color: theme.palette.text.primary,
|
|
||||||
}}
|
|
||||||
sx={{
|
sx={{
|
||||||
paddingY: 0,
|
paddingY: 0,
|
||||||
}}
|
}}
|
||||||
|
color="secondary"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{splitName[splitName.length - 1]}
|
{splitName[splitName.length - 1]}
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
sx={{
|
sx={{
|
||||||
".MuiTreeItem-content": { paddingY: "5px" },
|
"& .MuiTreeItem-content": {
|
||||||
|
paddingY: "5px",
|
||||||
|
minHeight: "52px",
|
||||||
|
},
|
||||||
bgcolor: colors.greyDark,
|
bgcolor: colors.greyDark,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -14,6 +14,7 @@ interface DateRangePickerProps {
|
||||||
range: Date[];
|
range: Date[];
|
||||||
getCacheSeries: (xaxisRange0: Date, xaxisRange1: Date) => void;
|
getCacheSeries: (xaxisRange0: Date, xaxisRange1: Date) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const DateRangePicker = (props: DateRangePickerProps) => {
|
const DateRangePicker = (props: DateRangePickerProps) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { setRange, range, getCacheSeries } = props;
|
const { setRange, range, getCacheSeries } = props;
|
||||||
|
@ -42,10 +43,6 @@ const DateRangePicker = (props: DateRangePickerProps) => {
|
||||||
label="From date"
|
label="From date"
|
||||||
value={dayjs(range[0])}
|
value={dayjs(range[0])}
|
||||||
sx={{
|
sx={{
|
||||||
".MuiInputLabel-root": {
|
|
||||||
color: colors.blueBlack,
|
|
||||||
},
|
|
||||||
|
|
||||||
".Mui-disabled": {
|
".Mui-disabled": {
|
||||||
color: "red",
|
color: "red",
|
||||||
},
|
},
|
||||||
|
@ -69,13 +66,12 @@ const DateRangePicker = (props: DateRangePickerProps) => {
|
||||||
".MuiInputLabel-root": {
|
".MuiInputLabel-root": {
|
||||||
color: colors.blueBlack,
|
color: colors.blueBlack,
|
||||||
},
|
},
|
||||||
|
|
||||||
".Mui-disabled": {
|
".Mui-disabled": {
|
||||||
color: "red",
|
color: "red",
|
||||||
},
|
},
|
||||||
".Mui-focused fieldset.MuiOutlinedInput-notchedOutline": {
|
".Mui-focused fieldset.MuiOutlinedInput-notchedOutline": {
|
||||||
borderColor: theme.palette.secondary.main, },
|
borderColor: theme.palette.secondary.main,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
onChange={(newValue) => {
|
onChange={(newValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
|
|
|
@ -1,11 +1,28 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import ScalarGraph from "./ScalarGraph";
|
import ScalarGraph from "./ScalarGraph";
|
||||||
|
import { colors } from "../../../index";
|
||||||
|
import { Box, useTheme } from "@mui/material";
|
||||||
|
|
||||||
const Log = () => {
|
const Log = () => {
|
||||||
|
const theme = useTheme();
|
||||||
return (
|
return (
|
||||||
<>
|
<Box
|
||||||
|
sx={{
|
||||||
|
py: 3,
|
||||||
|
bgcolor: colors.greyDark,
|
||||||
|
px: 1,
|
||||||
|
borderLeft: 2,
|
||||||
|
borderRight: 2,
|
||||||
|
borderBottom: 2,
|
||||||
|
borderTopLeftRadius: 0,
|
||||||
|
WebkitBorderTopRightRadius: 0,
|
||||||
|
borderBottomLeftRadius: 4,
|
||||||
|
borderBottomRightRadius: 4,
|
||||||
|
borderColor: theme.palette.text.disabled,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<ScalarGraph />
|
<ScalarGraph />
|
||||||
</>
|
</Box>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -22,40 +22,10 @@ import { FormattedMessage } from "react-intl";
|
||||||
import DateRangePicker from "./DateRangePicker";
|
import DateRangePicker from "./DateRangePicker";
|
||||||
import { LocalizationProvider } from "@mui/x-date-pickers";
|
import { LocalizationProvider } from "@mui/x-date-pickers";
|
||||||
import { Alert, useTheme } from "@mui/material";
|
import { Alert, useTheme } from "@mui/material";
|
||||||
|
import { S3CredentialsContext } from "../../Context/S3CredentialsContextProvider";
|
||||||
|
|
||||||
const NUMBER_OF_NODES = 100;
|
const NUMBER_OF_NODES = 100;
|
||||||
|
|
||||||
const s3Access = new S3Access(
|
|
||||||
"saliomameiringen",
|
|
||||||
"sos-ch-dk-2",
|
|
||||||
"exo.io",
|
|
||||||
"EXO464a9ff62fdfa407aa742855", // key
|
|
||||||
"f2KtCWN4EHFqtvH2kotdyI0w5SjjdHVPAADdcD3ik8g" // secret
|
|
||||||
);
|
|
||||||
|
|
||||||
export const fetchData = (
|
|
||||||
timestamp: UnixTime
|
|
||||||
): Promise<FetchResult<DataRecord>> => {
|
|
||||||
const s3Path = `${timestamp.ticks}.csv`;
|
|
||||||
return s3Access
|
|
||||||
.get(s3Path)
|
|
||||||
.then(async (r) => {
|
|
||||||
if (r.status === 404) {
|
|
||||||
return Promise.resolve(FetchResult.notAvailable);
|
|
||||||
} else if (r.status === 200) {
|
|
||||||
const text = await r.text();
|
|
||||||
console.log("parsecsv", text, parseCsv(text));
|
|
||||||
return parseCsv(text);
|
|
||||||
} else {
|
|
||||||
console.error("unexpected status code");
|
|
||||||
return Promise.resolve(FetchResult.notAvailable);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch((e) => {
|
|
||||||
return Promise.resolve(FetchResult.tryLater);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const ScalarGraph = () => {
|
const ScalarGraph = () => {
|
||||||
const timeRange = createTimes(
|
const timeRange = createTimes(
|
||||||
UnixTime.now() /* .fromTicks(1682085650) */
|
UnixTime.now() /* .fromTicks(1682085650) */
|
||||||
|
@ -70,6 +40,7 @@ const ScalarGraph = () => {
|
||||||
const [plotTitles, setPlotTitles] = useState<string[]>([]);
|
const [plotTitles, setPlotTitles] = useState<string[]>([]);
|
||||||
|
|
||||||
const { toggles, setToggles, checkedToggles } = useContext(LogContext);
|
const { toggles, setToggles, checkedToggles } = useContext(LogContext);
|
||||||
|
const { fetchData } = useContext(S3CredentialsContext);
|
||||||
|
|
||||||
const times$ = useMemo(() => new BehaviorSubject(timeRange), []);
|
const times$ = useMemo(() => new BehaviorSubject(timeRange), []);
|
||||||
|
|
||||||
|
@ -93,10 +64,9 @@ const ScalarGraph = () => {
|
||||||
return () => subscription.unsubscribe();
|
return () => subscription.unsubscribe();
|
||||||
}, [toggles]);
|
}, [toggles]);
|
||||||
|
|
||||||
const cache = useMemo(
|
const cache = useMemo(() => {
|
||||||
() => new DataCache(fetchData, TimeSpan.fromSeconds(2)),
|
return new DataCache(fetchData, TimeSpan.fromSeconds(2));
|
||||||
[]
|
}, []);
|
||||||
);
|
|
||||||
|
|
||||||
const transformToGraphData = (input: RecordSeries): GraphData => {
|
const transformToGraphData = (input: RecordSeries): GraphData => {
|
||||||
const transformedObject: any = {};
|
const transformedObject: any = {};
|
||||||
|
|
|
@ -20,7 +20,7 @@ const isInt = (value: number) => {
|
||||||
return value % 1 === 0;
|
return value % 1 === 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const BOX_SIZE = 85;
|
export const BOX_SIZE = 75;
|
||||||
const TopologyBox = (props: TopologyBoxProps) => {
|
const TopologyBox = (props: TopologyBoxProps) => {
|
||||||
const { titleColor, boxColor } = getBoxColor(props.title);
|
const { titleColor, boxColor } = getBoxColor(props.title);
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -7,13 +7,14 @@ import {
|
||||||
getAmount,
|
getAmount,
|
||||||
getHighestConnectionValue,
|
getHighestConnectionValue,
|
||||||
} from "../../../util/graph.util";
|
} from "../../../util/graph.util";
|
||||||
import { fetchData } from "./ScalarGraph";
|
import { useContext, useEffect, useState } from "react";
|
||||||
import { useEffect, useState } from "react";
|
|
||||||
import { FetchResult } from "../../../dataCache/dataCache";
|
import { FetchResult } from "../../../dataCache/dataCache";
|
||||||
import { FormattedMessage } from "react-intl";
|
import { FormattedMessage } from "react-intl";
|
||||||
|
import { S3CredentialsContext } from "../../Context/S3CredentialsContextProvider";
|
||||||
|
|
||||||
const TopologyView = () => {
|
const TopologyView = () => {
|
||||||
const [values, setValues] = useState<TopologyValues | null>(null);
|
const [values, setValues] = useState<TopologyValues | null>(null);
|
||||||
|
const { fetchData } = useContext(S3CredentialsContext);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
|
@ -229,6 +230,7 @@ const TopologyView = () => {
|
||||||
/>
|
/>
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
|
return <div>TopologyView</div>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default TopologyView;
|
export default TopologyView;
|
||||||
|
|
|
@ -17,13 +17,13 @@ const InnovenergyTab = (props: any) => {
|
||||||
marginRight: theme.spacing(1),
|
marginRight: theme.spacing(1),
|
||||||
background: "0 0",
|
background: "0 0",
|
||||||
border: "2px solid transparent",
|
border: "2px solid transparent",
|
||||||
bgcolor: theme.palette.primary.light,
|
|
||||||
borderTopLeftRadius: "0.3rem",
|
borderTopLeftRadius: "0.3rem",
|
||||||
borderTopRightRadius: "0.3rem",
|
borderTopRightRadius: "0.3rem",
|
||||||
padding: ".5rem 1rem",
|
padding: ".5rem 1rem",
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
transition: `color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out`,
|
transition: `color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out`,
|
||||||
"&.Mui-selected": {
|
"&.Mui-selected": {
|
||||||
|
backgroundColor: "#eaecf1",
|
||||||
color: colors.black,
|
color: colors.black,
|
||||||
borderColor: theme.palette.text.disabled,
|
borderColor: theme.palette.text.disabled,
|
||||||
marginTop: "1px",
|
marginTop: "1px",
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { colors } from "index";
|
||||||
interface AntTabsProps {
|
interface AntTabsProps {
|
||||||
id: string;
|
id: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
sx?: SxProps<Theme>;
|
sx?: any;
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ const InnovenergyTabs = (props: AntTabsProps) => {
|
||||||
},
|
},
|
||||||
"&.Mui-selected": {
|
"&.Mui-selected": {
|
||||||
color: colors.black,
|
color: colors.black,
|
||||||
backgroundColor: " #90A7c5",
|
backgroundColor: "#eaecf1",
|
||||||
borderColor: `#90A7c5 #90A7c5 #fff`,
|
borderColor: `#90A7c5 #90A7c5 #fff`,
|
||||||
},
|
},
|
||||||
"& .MuiTabs-indicator": {
|
"& .MuiTabs-indicator": {
|
||||||
|
@ -34,6 +34,7 @@ const InnovenergyTabs = (props: AntTabsProps) => {
|
||||||
},
|
},
|
||||||
"&.MuiTabs-root": {
|
"&.MuiTabs-root": {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
|
...(props.sx ? props.sx["&.MuiTabs-root"] : {}),
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
TextField,
|
TextField,
|
||||||
useTheme,
|
useTheme,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
import { colors } from "../../index";
|
||||||
|
|
||||||
export interface I_InnovenergyTextfieldProps {
|
export interface I_InnovenergyTextfieldProps {
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -28,18 +29,6 @@ export interface I_InnovenergyTextfieldProps {
|
||||||
export const IePropertyGrid = (props: {
|
export const IePropertyGrid = (props: {
|
||||||
rows: I_InnovenergyTextfieldProps[];
|
rows: I_InnovenergyTextfieldProps[];
|
||||||
}) => {
|
}) => {
|
||||||
const theme = useTheme();
|
|
||||||
|
|
||||||
const findLongestLength = () => {
|
|
||||||
return (
|
|
||||||
11 *
|
|
||||||
props.rows.reduce(
|
|
||||||
(acc, curr) => (acc > curr.label.length ? acc : curr.label.length),
|
|
||||||
0
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||||
<div
|
<div
|
||||||
|
@ -51,13 +40,14 @@ export const IePropertyGrid = (props: {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.rows.map((prop) => (
|
{props.rows.map((prop) => (
|
||||||
<InputLabel>{prop.label}</InputLabel>
|
<InputLabel key={prop.label}>{prop.label}</InputLabel>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
{props.rows.map((element) => {
|
{props.rows.map((element) => {
|
||||||
return (
|
return (
|
||||||
<TextField
|
<TextField
|
||||||
|
key={element.label}
|
||||||
color="secondary"
|
color="secondary"
|
||||||
id={element.id}
|
id={element.id}
|
||||||
variant="outlined"
|
variant="outlined"
|
||||||
|
@ -72,7 +62,12 @@ export const IePropertyGrid = (props: {
|
||||||
height: 15,
|
height: 15,
|
||||||
},
|
},
|
||||||
my: 0.5,
|
my: 0.5,
|
||||||
borderColor: "red",
|
".Mui-focused": {
|
||||||
|
borderRadius: 1,
|
||||||
|
},
|
||||||
|
"MuiInputLabel-root": {
|
||||||
|
color: colors.black,
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
value={element.value || ""}
|
value={element.value || ""}
|
||||||
onChange={element.handleChange}
|
onChange={element.handleChange}
|
||||||
|
|
|
@ -6,18 +6,22 @@ import InnovenergyTab from "./InnovenergyTab";
|
||||||
import InnovenergyTabs from "./InnovenergyTabs";
|
import InnovenergyTabs from "./InnovenergyTabs";
|
||||||
import { useTheme } from "@mui/material";
|
import { useTheme } from "@mui/material";
|
||||||
|
|
||||||
const NavigationButtons = () => {
|
const NavigationTabs = () => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const routeMatch = useRouteMatch([
|
const routeMatch = useRouteMatch([
|
||||||
routes.installations + "*",
|
routes.installations + "*",
|
||||||
routes.users + "*",
|
routes.users + "*",
|
||||||
]);
|
]);
|
||||||
const intl = useIntl();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<InnovenergyTabs
|
<InnovenergyTabs
|
||||||
sx={{ paddingTop: 0 }}
|
sx={{
|
||||||
|
paddingTop: 0,
|
||||||
|
"&.MuiTabs-root": {
|
||||||
|
borderBottom: "none",
|
||||||
|
},
|
||||||
|
}}
|
||||||
id="navigation-buttons-tabs"
|
id="navigation-buttons-tabs"
|
||||||
value={routeMatch?.pattern?.path}
|
value={routeMatch?.pattern?.path}
|
||||||
>
|
>
|
||||||
|
@ -25,7 +29,7 @@ const NavigationButtons = () => {
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor: theme.palette.primary.main,
|
bgcolor: theme.palette.primary.main,
|
||||||
"&.Mui-selected": {
|
"&.Mui-selected": {
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: "#eaecf1",
|
||||||
borderColor: theme.palette.text.disabled,
|
borderColor: theme.palette.text.disabled,
|
||||||
borderBottom: 0,
|
borderBottom: 0,
|
||||||
mb: -1 / 8,
|
mb: -1 / 8,
|
||||||
|
@ -46,7 +50,7 @@ const NavigationButtons = () => {
|
||||||
sx={{
|
sx={{
|
||||||
bgcolor: theme.palette.primary.main,
|
bgcolor: theme.palette.primary.main,
|
||||||
"&.Mui-selected": {
|
"&.Mui-selected": {
|
||||||
backgroundColor: theme.palette.primary.main,
|
backgroundColor: "#eaecf1",
|
||||||
borderColor: theme.palette.text.disabled,
|
borderColor: theme.palette.text.disabled,
|
||||||
borderBottom: 0,
|
borderBottom: 0,
|
||||||
mb: -1 / 8,
|
mb: -1 / 8,
|
||||||
|
@ -63,4 +67,4 @@ const NavigationButtons = () => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default NavigationButtons;
|
export default NavigationTabs;
|
|
@ -10,7 +10,6 @@ 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 SearchSidebarProps {
|
||||||
listComponent: FC<{ searchQuery: string }>;
|
listComponent: FC<{ searchQuery: string }>;
|
||||||
id: string;
|
id: string;
|
||||||
|
@ -22,7 +21,6 @@ const SearchInputTextfield = styled((props: TextFieldProps) => (
|
||||||
InputProps={{ disableUnderline: true } as Partial<OutlinedInputProps>}
|
InputProps={{ disableUnderline: true } as Partial<OutlinedInputProps>}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
))(({ theme }) => ({
|
))(({ theme }) => ({
|
||||||
"& .MuiFilledInput-root": {
|
"& .MuiFilledInput-root": {
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
|
@ -41,11 +39,9 @@ const SearchInputTextfield = styled((props: TextFieldProps) => (
|
||||||
backgroundColor: theme.palette.primary.dark,
|
backgroundColor: theme.palette.primary.dark,
|
||||||
},
|
},
|
||||||
"&.Mui-focused": {
|
"&.Mui-focused": {
|
||||||
|
|
||||||
backgroundColor: theme.palette.primary.dark,
|
backgroundColor: theme.palette.primary.dark,
|
||||||
borderColor: theme.palette.secondary.main,
|
borderColor: theme.palette.secondary.main,
|
||||||
},
|
},
|
||||||
|
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
@ -55,28 +51,17 @@ const SearchSidebar = (props: SearchSidebarProps) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: height ?? "750px", overflow: "hidden" }}>
|
<div style={{ height: height ?? "750px", overflow: "hidden" }}>
|
||||||
{/* <RedditTextField
|
|
||||||
style={{ backgroundColor: "#577ba840" }}
|
|
||||||
color="secondary"
|
|
||||||
id={id}
|
|
||||||
label={intl.formatMessage({
|
|
||||||
id: "search",
|
|
||||||
defaultMessage: "Search",
|
|
||||||
})}
|
|
||||||
type="search"
|
|
||||||
fullWidth
|
|
||||||
value={searchQuery}
|
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
|
||||||
/> */}
|
|
||||||
<SearchInputTextfield
|
<SearchInputTextfield
|
||||||
sx={{
|
sx={{
|
||||||
".MuiInputLabel-root" :{
|
".MuiInputLabel-root": {
|
||||||
color: colors.black
|
color: colors.black,
|
||||||
}}}
|
},
|
||||||
|
".Mui-focused": {
|
||||||
|
color: colors.black,
|
||||||
|
},
|
||||||
|
}}
|
||||||
id={id}
|
id={id}
|
||||||
variant="filled"
|
variant="filled"
|
||||||
onChange={(e) => setSearchQuery(e.target.value)}
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
|
||||||
export const axiosConfigWithoutToken = axios.create({
|
export const axiosConfigWithoutToken = axios.create({
|
||||||
baseURL: "https://monitor.innov.energy:5000/api",
|
baseURL: "https://localhost:7087/api",
|
||||||
});
|
});
|
||||||
|
|
||||||
const axiosConfig = axios.create({
|
const axiosConfig = axios.create({
|
||||||
baseURL: "https://monitor.innov.energy:5000/api",
|
baseURL: "https://localhost:7087/api",
|
||||||
});
|
});
|
||||||
axiosConfig.defaults.params = {};
|
axiosConfig.defaults.params = {};
|
||||||
axiosConfig.interceptors.request.use(
|
axiosConfig.interceptors.request.use(
|
||||||
|
|
|
@ -138,10 +138,13 @@ export default class DataCache<T extends Record<string, CsvEntry>> {
|
||||||
const onSuccess = (data: FetchResult<T>) => {
|
const onSuccess = (data: FetchResult<T>) => {
|
||||||
if (data === FetchResult.tryLater) {
|
if (data === FetchResult.tryLater) {
|
||||||
console.warn(FetchResult.tryLater);
|
console.warn(FetchResult.tryLater);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const value = data === FetchResult.notAvailable ? undefined : data;
|
const value =
|
||||||
|
data === FetchResult.notAvailable || data === FetchResult.tryLater
|
||||||
|
? undefined
|
||||||
|
: data;
|
||||||
|
// @ts-ignore
|
||||||
this.cache.insert(value, t);
|
this.cache.insert(value, t);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
import { useContext, useState } from "react";
|
||||||
|
import axiosConfig from "../config/axiosConfig";
|
||||||
|
import { I_Installation } from "../util/types";
|
||||||
|
import { AxiosError } from "axios";
|
||||||
|
import { S3CredentialsContext } from "../components/Context/S3CredentialsContextProvider";
|
||||||
|
|
||||||
|
const useInstallation = () => {
|
||||||
|
const [data, setData] = useState<I_Installation>();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [error, setError] = useState<AxiosError>();
|
||||||
|
|
||||||
|
const { saveS3Credentials } = useContext(S3CredentialsContext);
|
||||||
|
|
||||||
|
const getInstallation = (id?: string) => {
|
||||||
|
if (id) {
|
||||||
|
setLoading(true);
|
||||||
|
axiosConfig
|
||||||
|
.get("/GetInstallationById?id=" + id)
|
||||||
|
.then(({ data }: { data: I_Installation }) => {
|
||||||
|
const { s3Region, s3Provider, s3Secret, s3Key } = data;
|
||||||
|
setData(data);
|
||||||
|
setLoading(false);
|
||||||
|
// TODO remove if
|
||||||
|
if (id) {
|
||||||
|
saveS3Credentials({ s3Region, s3Provider, s3Secret, s3Key }, id);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((err: AxiosError) => {
|
||||||
|
setError(err);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
data,
|
||||||
|
loading,
|
||||||
|
error,
|
||||||
|
getInstallation,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default useInstallation;
|
|
@ -3,7 +3,7 @@ import ReactDOM from "react-dom/client";
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
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";
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(
|
const root = ReactDOM.createRoot(
|
||||||
|
@ -21,8 +21,8 @@ export const colors = {
|
||||||
greyDark: "#d1d7de",
|
greyDark: "#d1d7de",
|
||||||
greyLight: "#e1e4e7",
|
greyLight: "#e1e4e7",
|
||||||
|
|
||||||
orangeSelected: "#ffd280",
|
orangeSelected: "#f7b34d",
|
||||||
orangeHover: "#ffe4b3",
|
orangeHover: "#fad399",
|
||||||
|
|
||||||
orangeDark: "#ffc04d",
|
orangeDark: "#ffc04d",
|
||||||
};
|
};
|
||||||
|
@ -37,8 +37,7 @@ const theme = createTheme({
|
||||||
},
|
},
|
||||||
palette: {
|
palette: {
|
||||||
text: {
|
text: {
|
||||||
primary: colors.blueBlack,
|
primary: colors.black,
|
||||||
secondary: "#000000",
|
|
||||||
disabled: colors.borderColor,
|
disabled: colors.borderColor,
|
||||||
},
|
},
|
||||||
primary: {
|
primary: {
|
||||||
|
@ -61,7 +60,7 @@ const theme = createTheme({
|
||||||
root.render(
|
root.render(
|
||||||
<ThemeProvider theme={theme}>
|
<ThemeProvider theme={theme}>
|
||||||
<UserContextProvider>
|
<UserContextProvider>
|
||||||
<App/>
|
<App />
|
||||||
</UserContextProvider>
|
</UserContextProvider>
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
);
|
);
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 8.9 KiB |
|
@ -1,5 +1,13 @@
|
||||||
// TODO add if required or not
|
// TODO add if required or not
|
||||||
export interface I_Installation {
|
export interface S3Credentials {
|
||||||
|
s3Region: string;
|
||||||
|
s3Provider: string;
|
||||||
|
s3Key: string;
|
||||||
|
s3Secret: string;
|
||||||
|
s3Bucket?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface I_Installation extends S3Credentials {
|
||||||
type: string;
|
type: string;
|
||||||
title?: string;
|
title?: string;
|
||||||
status?: number;
|
status?: number;
|
||||||
|
@ -15,12 +23,6 @@ export interface I_Installation {
|
||||||
name: string;
|
name: string;
|
||||||
information: string;
|
information: string;
|
||||||
parentId: number;
|
parentId: number;
|
||||||
|
|
||||||
s3Bucket: string;
|
|
||||||
s3Region: string;
|
|
||||||
s3Provider: string;
|
|
||||||
s3Key: string;
|
|
||||||
s3Secret: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface I_Folder {
|
export interface I_Folder {
|
||||||
|
|
Loading…
Reference in New Issue