change style for multiple pages, change how s3 credentials are create
This commit is contained in:
parent
72ced4be3e
commit
3e099a68cb
|
@ -28,7 +28,7 @@
|
|||
</head>
|
||||
<body>
|
||||
<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.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
|
|
@ -2,7 +2,7 @@ import useToken from "./hooks/useToken";
|
|||
import Login from "./Login";
|
||||
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 { IntlProvider, MessageFormatElement } from "react-intl";
|
||||
import { useContext, useState } from "react";
|
||||
|
@ -12,11 +12,11 @@ import fr from "./lang/fr.json";
|
|||
import LanguageSelect from "./components/Layout/LanguageSelect";
|
||||
import LogoutButton from "./components/Layout/LogoutButton";
|
||||
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 { UserContext } from "./components/Context/UserContextProvider";
|
||||
import ResetPassword from "./ResetPassword";
|
||||
import innovenergyLogo from "./resources/test.gif";
|
||||
import innovenergyLogo from "./resources/innoveng_logo_on_orange.png";
|
||||
|
||||
const App = () => {
|
||||
const { token, setToken, removeToken } = useToken();
|
||||
|
@ -48,9 +48,9 @@ const App = () => {
|
|||
locale={language}
|
||||
defaultLocale="EN"
|
||||
>
|
||||
<Container maxWidth="xl" sx={{ marginTop: 2, height: "100vh" }}>
|
||||
<Grid container maxHeight="20vh">
|
||||
<Grid item xs={3} container justifyContent="flex-start">
|
||||
<Container maxWidth="xl" sx={{ pt: 2 }}>
|
||||
<Grid container>
|
||||
<Grid item xs={3} container justifyContent="flex-start" mb={2}>
|
||||
<img src={innovenergyLogo} alt="innovenergy logo" height="100" />
|
||||
</Grid>
|
||||
<Grid
|
||||
|
@ -64,11 +64,22 @@ const App = () => {
|
|||
<LogoutButton removeToken={removeToken} />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid container spacing={2} mt={2}>
|
||||
<Grid item xs={3} container justifyContent="flex-start">
|
||||
<NavigationButtons />
|
||||
</Container>
|
||||
<Container maxWidth="xl" sx={{ pt: 2 }}>
|
||||
<Grid spacing={2} width="100%">
|
||||
<Grid item xs={3}>
|
||||
<NavigationTabs />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Container>
|
||||
<Box
|
||||
bgcolor="#eaecf1"
|
||||
pt={3}
|
||||
borderTop="2px solid"
|
||||
borderColor=" #a8b0be"
|
||||
flex="1 0 auto"
|
||||
>
|
||||
<Container maxWidth="xl">
|
||||
<Routes>
|
||||
<Route
|
||||
path="*"
|
||||
|
@ -83,6 +94,7 @@ const App = () => {
|
|||
<Route path={routes.users + "*"} element={<Users />} />
|
||||
</Routes>
|
||||
</Container>
|
||||
</Box>
|
||||
</IntlProvider>
|
||||
</BrowserRouter>
|
||||
);
|
||||
|
|
|
@ -1,29 +1,89 @@
|
|||
import { createContext, ReactNode, useState } from "react";
|
||||
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 {
|
||||
s3Credentials?: I_User;
|
||||
setS3Credentials: (value: I_User) => void;
|
||||
interface S3CredentialsContextProviderProps {
|
||||
s3Credentials?: S3Credentials;
|
||||
saveS3Credentials: (credentials: S3Credentials, id: string) => void;
|
||||
fetchData: (timestamp: UnixTime) => Promise<FetchResult<DataRecord>>;
|
||||
}
|
||||
|
||||
export const UserContext = createContext<InstallationContextProviderProps>({
|
||||
s3Credentials: {} as I_User,
|
||||
setS3Credentials: () => {},
|
||||
export const S3CredentialsContext =
|
||||
createContext<S3CredentialsContextProviderProps>({
|
||||
s3Credentials: {} as S3Credentials,
|
||||
saveS3Credentials: () => {},
|
||||
fetchData: () => ({} as Promise<FetchResult<DataRecord>>),
|
||||
});
|
||||
|
||||
const UserContextProvider = ({ children }: { children: ReactNode }) => {
|
||||
const [s3Credentials, setS3Credentials] = useState<I_User>();
|
||||
const S3CredentialsContextProvider = ({
|
||||
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 (
|
||||
<UserContext.Provider
|
||||
<S3CredentialsContext.Provider
|
||||
value={{
|
||||
s3Credentials: s3Credentials,
|
||||
setS3Credentials: setS3Credentials,
|
||||
s3Credentials,
|
||||
saveS3Credentials,
|
||||
fetchData,
|
||||
}}
|
||||
>
|
||||
{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 AccessManagement from "./AccessManagement/AccessManagement";
|
||||
import Installation from "../Installations/Installation";
|
||||
import useRouteMatch from "../../hooks/useRouteMatch";
|
||||
import useInstallation from "../../hooks/useInstallation";
|
||||
import { useEffect } from "react";
|
||||
|
||||
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 (
|
||||
<GroupContextProvider>
|
||||
<Grid container spacing={2}>
|
||||
|
@ -25,7 +44,14 @@ const Groups = () => {
|
|||
/>
|
||||
<Route
|
||||
path={routes.installation + ":id"}
|
||||
element={<Installation hasMoveButton />}
|
||||
element={
|
||||
<Installation
|
||||
hasMoveButton
|
||||
error={error}
|
||||
values={currentInstallation}
|
||||
loading={loading}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</Grid>
|
||||
|
|
|
@ -11,6 +11,7 @@ import { instanceOfFolder } from "../../../util/group.util";
|
|||
import { Grid, CircularProgress, useTheme } from "@mui/material";
|
||||
import { useIntl } from "react-intl";
|
||||
import { colors } from "../../..";
|
||||
import { color } from "chart.js/helpers";
|
||||
|
||||
const GroupTree = () => {
|
||||
const { setCurrentType, fetchData, data, loading } = useContext(GroupContext);
|
||||
|
@ -54,7 +55,14 @@ const GroupTree = () => {
|
|||
label={element.name}
|
||||
onClick={() => setCurrentType(element.type)}
|
||||
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,
|
||||
borderRadius: 2,
|
||||
}}
|
||||
|
|
|
@ -1,35 +1,24 @@
|
|||
import { Alert, Box, CircularProgress, useTheme } from "@mui/material";
|
||||
import { AxiosError } from "axios";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { useParams } from "react-router-dom";
|
||||
import axiosConfig from "../../config/axiosConfig";
|
||||
import { I_Installation } from "../../util/types";
|
||||
import InstallationForm from "./InstallationForm";
|
||||
import { colors } from "../..";
|
||||
import { S3CredentialsContext } from "../Context/S3CredentialsContextProvider";
|
||||
|
||||
interface I_InstallationProps {
|
||||
loading?: boolean;
|
||||
values?: I_Installation;
|
||||
error?: AxiosError;
|
||||
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(() => {
|
||||
setLoading(true);
|
||||
axiosConfig
|
||||
.get("/GetInstallationById?id=" + id)
|
||||
.then((res) => {
|
||||
setValues(res.data);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch((err: AxiosError) => {
|
||||
setError(err);
|
||||
setLoading(false);
|
||||
});
|
||||
}, [id]);
|
||||
const Installation = (props: I_InstallationProps) => {
|
||||
const { hasMoveButton, values, loading, error } = props;
|
||||
const { id } = useParams();
|
||||
const theme = useTheme();
|
||||
|
||||
if (values && values.id && values.id.toString() === id) {
|
||||
return (
|
||||
|
@ -51,7 +40,7 @@ const Installation = (props: I_InstallationProps) => {
|
|||
<InstallationForm
|
||||
values={values}
|
||||
id={id}
|
||||
hasMoveButton={props.hasMoveButton}
|
||||
hasMoveButton={hasMoveButton}
|
||||
/>
|
||||
</Box>
|
||||
);
|
||||
|
|
|
@ -70,13 +70,12 @@ const InstallationList = (props: InstallationListProps) => {
|
|||
<List
|
||||
sx={{
|
||||
width: "100%",
|
||||
bgcolor: "background.paper",
|
||||
position: "relative",
|
||||
overflow: "auto",
|
||||
py: 0,
|
||||
mt: 1,
|
||||
borderRadius: 1.5,
|
||||
height:
|
||||
maxHeight:
|
||||
routeMatch?.pattern.path ===
|
||||
routes.installations + routes.list + routes.log + ":id"
|
||||
? "130px"
|
||||
|
@ -93,7 +92,7 @@ const InstallationList = (props: InstallationListProps) => {
|
|||
to={
|
||||
getPathWithoutId(routeMatch?.pattern?.path) + installation.id
|
||||
}
|
||||
style={{ textDecoration: "none", color: colors.blueBlack }}
|
||||
style={{ textDecoration: "none", color: colors.black }}
|
||||
>
|
||||
<ListItemButton
|
||||
id={"installation-list-button-" + installation.id}
|
||||
|
|
|
@ -4,18 +4,26 @@ import ModeButtons from "../Layout/ModeButtons";
|
|||
import Installations from "./Installations";
|
||||
import routes from "../../routes.json";
|
||||
import { Grid } from "@mui/material";
|
||||
import S3CredentialsContextProvider from "../Context/S3CredentialsContextProvider";
|
||||
|
||||
const InstallationPage = () => {
|
||||
return (
|
||||
<>
|
||||
<Grid container spacing={2} marginTop={1}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={3}>
|
||||
<ModeButtons />
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Routes>
|
||||
<Route path={routes.tree + "*"} element={<Groups />} />
|
||||
<Route path={routes.list + "*"} element={<Installations />} />
|
||||
<Route
|
||||
path={routes.list + "*"}
|
||||
element={
|
||||
<S3CredentialsContextProvider>
|
||||
<Installations />
|
||||
</S3CredentialsContextProvider>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -25,7 +25,6 @@ const InstallationTabs = () => {
|
|||
if (id) {
|
||||
return (
|
||||
<Box sx={{ width: "100%" }}>
|
||||
<Box sx={{}}>
|
||||
<InnovenergyTabs
|
||||
id="installation-tabs"
|
||||
value={routeMatch?.pattern?.path ?? routes.installation + ":id"}
|
||||
|
@ -53,23 +52,21 @@ const InstallationTabs = () => {
|
|||
/>
|
||||
|
||||
<InnovenergyTab
|
||||
id={"installation-tab-liveView"}
|
||||
sx={{
|
||||
"&.Mui-selected": {
|
||||
color: colors.black,
|
||||
backgroundColor: "white",
|
||||
backgroundColor: theme.palette.primary.dark,
|
||||
borderColor: theme.palette.text.disabled,
|
||||
borderBottom: 0,
|
||||
mb: -1 / 8,
|
||||
},
|
||||
}}
|
||||
id={"installation-tab-liveView"}
|
||||
label={intl.formatMessage({
|
||||
id: "liveView",
|
||||
defaultMessage: "Live view",
|
||||
})}
|
||||
value={
|
||||
routes.installations + routes.list + routes.liveView + ":id"
|
||||
}
|
||||
value={routes.installations + routes.list + routes.liveView + ":id"}
|
||||
component={Link}
|
||||
to={routes.liveView + id}
|
||||
/>
|
||||
|
@ -77,7 +74,7 @@ const InstallationTabs = () => {
|
|||
sx={{
|
||||
"&.Mui-selected": {
|
||||
color: colors.black,
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
backgroundColor: theme.palette.primary.dark,
|
||||
borderColor: theme.palette.text.disabled,
|
||||
borderBottom: 0,
|
||||
mb: -1 / 8,
|
||||
|
@ -94,7 +91,6 @@ const InstallationTabs = () => {
|
|||
/>
|
||||
</InnovenergyTabs>
|
||||
</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -13,20 +13,47 @@ import LogContextProvider from "../Context/LogContextProvider";
|
|||
import useRouteMatch from "../../hooks/useRouteMatch";
|
||||
import { Background } from "reactflow";
|
||||
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 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 (
|
||||
<InstallationsContextProvider>
|
||||
<LogContextProvider>
|
||||
<Grid container spacing={2} height="100%">
|
||||
<Grid container spacing={2}>
|
||||
<Grid item xs={3}>
|
||||
<SearchSidebar
|
||||
id="installations-search-sidebar"
|
||||
listComponent={InstallationList}
|
||||
height={routeMatch ? "200px" : undefined}
|
||||
height={routeMatch?.params?.view === "log" ? "200px" : undefined}
|
||||
/>
|
||||
<CheckboxTree />
|
||||
</Grid>
|
||||
|
@ -35,7 +62,13 @@ const Installations = () => {
|
|||
<Routes>
|
||||
<Route
|
||||
path={routes.installation + ":id"}
|
||||
element={<Installation />}
|
||||
element={
|
||||
<Installation
|
||||
loading={loading}
|
||||
values={currentInstallation}
|
||||
error={error}
|
||||
/>
|
||||
}
|
||||
index
|
||||
/>
|
||||
<Route path={routes.liveView + ":id"} element={<LiveView />} />
|
||||
|
|
|
@ -1,7 +1,28 @@
|
|||
import TopologyView from "./Log/TopologyView";
|
||||
import { Box, useTheme } from "@mui/material";
|
||||
import { colors } from "../../index";
|
||||
|
||||
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;
|
||||
|
|
|
@ -49,7 +49,6 @@ const CheckboxTree = () => {
|
|||
) => {
|
||||
event.stopPropagation();
|
||||
};
|
||||
const theme = useTheme();
|
||||
const renderTree = (data: TreeElement[]): ReactNode => {
|
||||
return data.map((element) => {
|
||||
const checked = checkedToggles.find((toggle) => element.id === toggle);
|
||||
|
@ -66,19 +65,20 @@ const CheckboxTree = () => {
|
|||
<Checkbox
|
||||
checked={!!checked}
|
||||
onClick={(e) => handleClick(e, element, checked)}
|
||||
style={{
|
||||
color: theme.palette.text.primary,
|
||||
}}
|
||||
sx={{
|
||||
paddingY: 0,
|
||||
}}
|
||||
color="secondary"
|
||||
/>
|
||||
)}
|
||||
{splitName[splitName.length - 1]}
|
||||
</>
|
||||
}
|
||||
sx={{
|
||||
".MuiTreeItem-content": { paddingY: "5px" },
|
||||
"& .MuiTreeItem-content": {
|
||||
paddingY: "5px",
|
||||
minHeight: "52px",
|
||||
},
|
||||
bgcolor: colors.greyDark,
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -14,6 +14,7 @@ interface DateRangePickerProps {
|
|||
range: Date[];
|
||||
getCacheSeries: (xaxisRange0: Date, xaxisRange1: Date) => void;
|
||||
}
|
||||
|
||||
const DateRangePicker = (props: DateRangePickerProps) => {
|
||||
const theme = useTheme();
|
||||
const { setRange, range, getCacheSeries } = props;
|
||||
|
@ -42,10 +43,6 @@ const DateRangePicker = (props: DateRangePickerProps) => {
|
|||
label="From date"
|
||||
value={dayjs(range[0])}
|
||||
sx={{
|
||||
".MuiInputLabel-root": {
|
||||
color: colors.blueBlack,
|
||||
},
|
||||
|
||||
".Mui-disabled": {
|
||||
color: "red",
|
||||
},
|
||||
|
@ -69,13 +66,12 @@ const DateRangePicker = (props: DateRangePickerProps) => {
|
|||
".MuiInputLabel-root": {
|
||||
color: colors.blueBlack,
|
||||
},
|
||||
|
||||
".Mui-disabled": {
|
||||
color: "red",
|
||||
},
|
||||
".Mui-focused fieldset.MuiOutlinedInput-notchedOutline": {
|
||||
borderColor: theme.palette.secondary.main, },
|
||||
|
||||
borderColor: theme.palette.secondary.main,
|
||||
},
|
||||
}}
|
||||
onChange={(newValue) => {
|
||||
if (newValue) {
|
||||
|
|
|
@ -1,11 +1,28 @@
|
|||
import React from "react";
|
||||
import ScalarGraph from "./ScalarGraph";
|
||||
import { colors } from "../../../index";
|
||||
import { Box, useTheme } from "@mui/material";
|
||||
|
||||
const Log = () => {
|
||||
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,
|
||||
}}
|
||||
>
|
||||
<ScalarGraph />
|
||||
</>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -22,40 +22,10 @@ import { FormattedMessage } from "react-intl";
|
|||
import DateRangePicker from "./DateRangePicker";
|
||||
import { LocalizationProvider } from "@mui/x-date-pickers";
|
||||
import { Alert, useTheme } from "@mui/material";
|
||||
import { S3CredentialsContext } from "../../Context/S3CredentialsContextProvider";
|
||||
|
||||
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 timeRange = createTimes(
|
||||
UnixTime.now() /* .fromTicks(1682085650) */
|
||||
|
@ -70,6 +40,7 @@ const ScalarGraph = () => {
|
|||
const [plotTitles, setPlotTitles] = useState<string[]>([]);
|
||||
|
||||
const { toggles, setToggles, checkedToggles } = useContext(LogContext);
|
||||
const { fetchData } = useContext(S3CredentialsContext);
|
||||
|
||||
const times$ = useMemo(() => new BehaviorSubject(timeRange), []);
|
||||
|
||||
|
@ -93,10 +64,9 @@ const ScalarGraph = () => {
|
|||
return () => subscription.unsubscribe();
|
||||
}, [toggles]);
|
||||
|
||||
const cache = useMemo(
|
||||
() => new DataCache(fetchData, TimeSpan.fromSeconds(2)),
|
||||
[]
|
||||
);
|
||||
const cache = useMemo(() => {
|
||||
return new DataCache(fetchData, TimeSpan.fromSeconds(2));
|
||||
}, []);
|
||||
|
||||
const transformToGraphData = (input: RecordSeries): GraphData => {
|
||||
const transformedObject: any = {};
|
||||
|
|
|
@ -20,7 +20,7 @@ const isInt = (value: number) => {
|
|||
return value % 1 === 0;
|
||||
};
|
||||
|
||||
export const BOX_SIZE = 85;
|
||||
export const BOX_SIZE = 75;
|
||||
const TopologyBox = (props: TopologyBoxProps) => {
|
||||
const { titleColor, boxColor } = getBoxColor(props.title);
|
||||
return (
|
||||
|
|
|
@ -7,13 +7,14 @@ import {
|
|||
getAmount,
|
||||
getHighestConnectionValue,
|
||||
} from "../../../util/graph.util";
|
||||
import { fetchData } from "./ScalarGraph";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useContext, useEffect, useState } from "react";
|
||||
import { FetchResult } from "../../../dataCache/dataCache";
|
||||
import { FormattedMessage } from "react-intl";
|
||||
import { S3CredentialsContext } from "../../Context/S3CredentialsContextProvider";
|
||||
|
||||
const TopologyView = () => {
|
||||
const [values, setValues] = useState<TopologyValues | null>(null);
|
||||
const { fetchData } = useContext(S3CredentialsContext);
|
||||
|
||||
useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
|
@ -229,6 +230,7 @@ const TopologyView = () => {
|
|||
/>
|
||||
</Alert>
|
||||
);
|
||||
return <div>TopologyView</div>;
|
||||
};
|
||||
|
||||
export default TopologyView;
|
||||
|
|
|
@ -17,13 +17,13 @@ const InnovenergyTab = (props: any) => {
|
|||
marginRight: theme.spacing(1),
|
||||
background: "0 0",
|
||||
border: "2px solid transparent",
|
||||
bgcolor: theme.palette.primary.light,
|
||||
borderTopLeftRadius: "0.3rem",
|
||||
borderTopRightRadius: "0.3rem",
|
||||
padding: ".5rem 1rem",
|
||||
textDecoration: "none",
|
||||
transition: `color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out`,
|
||||
"&.Mui-selected": {
|
||||
backgroundColor: "#eaecf1",
|
||||
color: colors.black,
|
||||
borderColor: theme.palette.text.disabled,
|
||||
marginTop: "1px",
|
||||
|
|
|
@ -5,7 +5,7 @@ import { colors } from "index";
|
|||
interface AntTabsProps {
|
||||
id: string;
|
||||
value?: string;
|
||||
sx?: SxProps<Theme>;
|
||||
sx?: any;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ const InnovenergyTabs = (props: AntTabsProps) => {
|
|||
},
|
||||
"&.Mui-selected": {
|
||||
color: colors.black,
|
||||
backgroundColor: " #90A7c5",
|
||||
backgroundColor: "#eaecf1",
|
||||
borderColor: `#90A7c5 #90A7c5 #fff`,
|
||||
},
|
||||
"& .MuiTabs-indicator": {
|
||||
|
@ -34,6 +34,7 @@ const InnovenergyTabs = (props: AntTabsProps) => {
|
|||
},
|
||||
"&.MuiTabs-root": {
|
||||
width: "100%",
|
||||
...(props.sx ? props.sx["&.MuiTabs-root"] : {}),
|
||||
},
|
||||
}}
|
||||
>
|
||||
|
|
|
@ -11,6 +11,7 @@ import {
|
|||
TextField,
|
||||
useTheme,
|
||||
} from "@mui/material";
|
||||
import { colors } from "../../index";
|
||||
|
||||
export interface I_InnovenergyTextfieldProps {
|
||||
id: string;
|
||||
|
@ -28,18 +29,6 @@ export interface I_InnovenergyTextfieldProps {
|
|||
export const IePropertyGrid = (props: {
|
||||
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 (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<div
|
||||
|
@ -51,13 +40,14 @@ export const IePropertyGrid = (props: {
|
|||
}}
|
||||
>
|
||||
{props.rows.map((prop) => (
|
||||
<InputLabel>{prop.label}</InputLabel>
|
||||
<InputLabel key={prop.label}>{prop.label}</InputLabel>
|
||||
))}
|
||||
</div>
|
||||
<div>
|
||||
{props.rows.map((element) => {
|
||||
return (
|
||||
<TextField
|
||||
key={element.label}
|
||||
color="secondary"
|
||||
id={element.id}
|
||||
variant="outlined"
|
||||
|
@ -72,7 +62,12 @@ export const IePropertyGrid = (props: {
|
|||
height: 15,
|
||||
},
|
||||
my: 0.5,
|
||||
borderColor: "red",
|
||||
".Mui-focused": {
|
||||
borderRadius: 1,
|
||||
},
|
||||
"MuiInputLabel-root": {
|
||||
color: colors.black,
|
||||
},
|
||||
}}
|
||||
value={element.value || ""}
|
||||
onChange={element.handleChange}
|
||||
|
|
|
@ -6,18 +6,22 @@ import InnovenergyTab from "./InnovenergyTab";
|
|||
import InnovenergyTabs from "./InnovenergyTabs";
|
||||
import { useTheme } from "@mui/material";
|
||||
|
||||
const NavigationButtons = () => {
|
||||
const NavigationTabs = () => {
|
||||
const theme = useTheme();
|
||||
const routeMatch = useRouteMatch([
|
||||
routes.installations + "*",
|
||||
routes.users + "*",
|
||||
]);
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<>
|
||||
<InnovenergyTabs
|
||||
sx={{ paddingTop: 0 }}
|
||||
sx={{
|
||||
paddingTop: 0,
|
||||
"&.MuiTabs-root": {
|
||||
borderBottom: "none",
|
||||
},
|
||||
}}
|
||||
id="navigation-buttons-tabs"
|
||||
value={routeMatch?.pattern?.path}
|
||||
>
|
||||
|
@ -25,7 +29,7 @@ const NavigationButtons = () => {
|
|||
sx={{
|
||||
bgcolor: theme.palette.primary.main,
|
||||
"&.Mui-selected": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
backgroundColor: "#eaecf1",
|
||||
borderColor: theme.palette.text.disabled,
|
||||
borderBottom: 0,
|
||||
mb: -1 / 8,
|
||||
|
@ -46,7 +50,7 @@ const NavigationButtons = () => {
|
|||
sx={{
|
||||
bgcolor: theme.palette.primary.main,
|
||||
"&.Mui-selected": {
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
backgroundColor: "#eaecf1",
|
||||
borderColor: theme.palette.text.disabled,
|
||||
borderBottom: 0,
|
||||
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 { useIntl } from "react-intl";
|
||||
|
||||
|
||||
interface SearchSidebarProps {
|
||||
listComponent: FC<{ searchQuery: string }>;
|
||||
id: string;
|
||||
|
@ -22,7 +21,6 @@ const SearchInputTextfield = styled((props: TextFieldProps) => (
|
|||
InputProps={{ disableUnderline: true } as Partial<OutlinedInputProps>}
|
||||
{...props}
|
||||
/>
|
||||
|
||||
))(({ theme }) => ({
|
||||
"& .MuiFilledInput-root": {
|
||||
overflow: "hidden",
|
||||
|
@ -41,11 +39,9 @@ const SearchInputTextfield = styled((props: TextFieldProps) => (
|
|||
backgroundColor: theme.palette.primary.dark,
|
||||
},
|
||||
"&.Mui-focused": {
|
||||
|
||||
backgroundColor: theme.palette.primary.dark,
|
||||
borderColor: theme.palette.secondary.main,
|
||||
},
|
||||
|
||||
},
|
||||
}));
|
||||
|
||||
|
@ -55,28 +51,17 @@ const SearchSidebar = (props: SearchSidebarProps) => {
|
|||
const intl = useIntl();
|
||||
const theme = useTheme();
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<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
|
||||
sx={{
|
||||
".MuiInputLabel-root": {
|
||||
color: colors.black
|
||||
}}}
|
||||
color: colors.black,
|
||||
},
|
||||
".Mui-focused": {
|
||||
color: colors.black,
|
||||
},
|
||||
}}
|
||||
id={id}
|
||||
variant="filled"
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import axios from "axios";
|
||||
|
||||
export const axiosConfigWithoutToken = axios.create({
|
||||
baseURL: "https://monitor.innov.energy:5000/api",
|
||||
baseURL: "https://localhost:7087/api",
|
||||
});
|
||||
|
||||
const axiosConfig = axios.create({
|
||||
baseURL: "https://monitor.innov.energy:5000/api",
|
||||
baseURL: "https://localhost:7087/api",
|
||||
});
|
||||
axiosConfig.defaults.params = {};
|
||||
axiosConfig.interceptors.request.use(
|
||||
|
|
|
@ -138,10 +138,13 @@ export default class DataCache<T extends Record<string, CsvEntry>> {
|
|||
const onSuccess = (data: FetchResult<T>) => {
|
||||
if (data === 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);
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
|
@ -21,8 +21,8 @@ export const colors = {
|
|||
greyDark: "#d1d7de",
|
||||
greyLight: "#e1e4e7",
|
||||
|
||||
orangeSelected: "#ffd280",
|
||||
orangeHover: "#ffe4b3",
|
||||
orangeSelected: "#f7b34d",
|
||||
orangeHover: "#fad399",
|
||||
|
||||
orangeDark: "#ffc04d",
|
||||
};
|
||||
|
@ -37,8 +37,7 @@ const theme = createTheme({
|
|||
},
|
||||
palette: {
|
||||
text: {
|
||||
primary: colors.blueBlack,
|
||||
secondary: "#000000",
|
||||
primary: colors.black,
|
||||
disabled: colors.borderColor,
|
||||
},
|
||||
primary: {
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 8.9 KiB |
|
@ -1,5 +1,13 @@
|
|||
// 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;
|
||||
title?: string;
|
||||
status?: number;
|
||||
|
@ -15,12 +23,6 @@ export interface I_Installation {
|
|||
name: string;
|
||||
information: string;
|
||||
parentId: number;
|
||||
|
||||
s3Bucket: string;
|
||||
s3Region: string;
|
||||
s3Provider: string;
|
||||
s3Key: string;
|
||||
s3Secret: string;
|
||||
}
|
||||
|
||||
export interface I_Folder {
|
||||
|
|
Loading…
Reference in New Issue