change style for multiple pages, change how s3 credentials are create

This commit is contained in:
Sina Blattmann 2023-07-13 09:36:20 +02:00
parent 72ced4be3e
commit 3e099a68cb
28 changed files with 481 additions and 312 deletions

View File

@ -1,20 +1,20 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<head>
<meta charset="utf-8"/>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="theme-color" content="#000000"/>
<meta
name="description"
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
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.
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`.
-->
<title>Innovenergy</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<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.
@ -38,6 +38,6 @@
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
-->
</body>
</html>

View File

@ -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>
);

View File

@ -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;

View File

@ -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>

View File

@ -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,
}}
@ -68,7 +76,7 @@ const GroupTree = () => {
if (loading) {
return (
<Grid container justifyContent="center" width="100%">
<CircularProgress sx={{color: theme.palette.secondary.main}} />
<CircularProgress sx={{ color: theme.palette.secondary.main }} />
</Grid>
);
}

View File

@ -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>
);
@ -60,7 +49,7 @@ const Installation = (props: I_InstallationProps) => {
<Box
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>
);
} else if (error) {

View File

@ -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}

View File

@ -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>
</>
);

View File

@ -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;

View File

@ -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 />} />

View File

@ -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;

View File

@ -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,
}}
>

View File

@ -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) {

View File

@ -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>
);
};

View File

@ -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 = {};

View File

@ -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 (

View File

@ -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;

View File

@ -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",

View File

@ -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"] : {}),
},
}}
>

View File

@ -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}

View File

@ -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;

View File

@ -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
}}}
".MuiInputLabel-root": {
color: colors.black,
},
".Mui-focused": {
color: colors.black,
},
}}
id={id}
variant="filled"
onChange={(e) => setSearchQuery(e.target.value)}

View File

@ -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(

View File

@ -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);
};

View File

@ -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;

View File

@ -3,7 +3,7 @@ import ReactDOM from "react-dom/client";
import "./index.css";
import App from "./App";
import reportWebVitals from "./reportWebVitals";
import {createTheme, ThemeProvider} from "@mui/material";
import { createTheme, ThemeProvider } from "@mui/material";
import UserContextProvider from "./components/Context/UserContextProvider";
const root = ReactDOM.createRoot(
@ -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: {
@ -61,7 +60,7 @@ const theme = createTheme({
root.render(
<ThemeProvider theme={theme}>
<UserContextProvider>
<App/>
<App />
</UserContextProvider>
</ThemeProvider>
);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -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 {