This commit is contained in:
Sina Blattmann 2023-06-30 09:03:07 +02:00
commit c89b4ab488
41 changed files with 413 additions and 80 deletions

View File

@ -206,7 +206,10 @@ public class Controller : ControllerBase
if (user is null) if (user is null)
return Unauthorized(); return Unauthorized();
return user.AccessibleInstallations().Select(i => i.FillOrderNumbers().HideParentIfUserHasNoAccessToParent(user)).ToList(); return user
.AccessibleInstallations()
.Select(i => i.FillOrderNumbers().HideParentIfUserHasNoAccessToParent(user))
.ToList();
} }
@ -228,6 +231,8 @@ public class Controller : ControllerBase
{ {
var user = Db.GetSession(authToken)?.User; var user = Db.GetSession(authToken)?.User;
"GetAllFoldersAndInstallations".WriteLine();
if (user is null) if (user is null)
return Unauthorized(); return Unauthorized();

View File

@ -1,7 +1,8 @@
import useToken from "./hooks/useToken"; 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 } from "@mui/material";
import { Container, Grid, colors } from "@mui/material";
import routes from "./routes.json"; import routes from "./routes.json";
import { IntlProvider } from "react-intl"; import { IntlProvider } from "react-intl";
import { useContext, useState } from "react"; import { useContext, useState } from "react";
@ -14,7 +15,8 @@ import NavigationButtons from "./components/Layout/NavigationButtons";
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/innovenergy_Logo_onOrange.png"; import innovenergyLogo from "./resources/innovenergy_Logo_onOrange-2.png(1).png";
import { Background } from "reactflow";
const App = () => { const App = () => {
const { token, setToken, removeToken } = useToken(); const { token, setToken, removeToken } = useToken();
@ -43,9 +45,13 @@ const App = () => {
defaultLocale="EN" defaultLocale="EN"
> >
<Container maxWidth="xl" sx={{ marginTop: 2, height: "100vh" }}> <Container maxWidth="xl" sx={{ marginTop: 2, height: "100vh" }}>
<Grid container spacing={2} maxHeight="20vh"> <Grid container maxHeight="20vh">
<Grid item xs={3} container justifyContent="flex-start"> <Grid item xs={3} container justifyContent="flex-start">
<img src={innovenergyLogo} alt="innovenergy logo" height="50" /> <img
src={innovenergyLogo}
alt="innovenergy logo"
height="75" //style={color: #0960ac;background: #df7900;}
/>
</Grid> </Grid>
<Grid item xs={9} container justifyContent="flex-end"> <Grid item xs={9} container justifyContent="flex-end">
<LanguageSelect language={language} setLanguage={setLanguage} /> <LanguageSelect language={language} setLanguage={setLanguage} />

View File

@ -80,7 +80,7 @@ const Login = ({ setToken, setLanguage }: I_LoginProps) => {
Login Login
</InnovenergyButton> </InnovenergyButton>
</Grid> </Grid>
{loading && <CircularProgress />} {loading && <CircularProgress color="secondary" />}
</Container> </Container>
); );
}; };

View File

@ -72,7 +72,7 @@ const ResetPassword = () => {
Submit Submit
</InnovenergyButton> </InnovenergyButton>
</Grid> </Grid>
{loading && <CircularProgress />} {loading && <CircularProgress color="secondary" />}
</form> </form>
</Container> </Container>
); );

View File

@ -12,8 +12,8 @@ const AccessManagement = () => {
return ( return (
<UsersContextProvider> <UsersContextProvider>
<Grid container sx={{ mt: 1 }}> <Grid container sx={{ mt: 0 }}>
<Grid item xs={6}> <Grid item xs={60} bgcolor={"#CCD6E4"}>
{getCurrentUser().hasWriteAccess && <AvailableUserDialog />} {getCurrentUser().hasWriteAccess && <AvailableUserDialog />}
<InnovenergyList id="access-management-list"> <InnovenergyList id="access-management-list">
<UsersWithDirectAccess /> <UsersWithDirectAccess />

View File

@ -4,6 +4,7 @@ import {
DialogContent, DialogContent,
DialogTitle, DialogTitle,
TextField, TextField,
colors,
} from "@mui/material"; } from "@mui/material";
import DialogActions from "@mui/material/DialogActions"; import DialogActions from "@mui/material/DialogActions";
import { useContext, useState } from "react"; import { useContext, useState } from "react";
@ -98,6 +99,7 @@ const AvailableUserDialog = () => {
id="available-user-dialog-submit-button" id="available-user-dialog-submit-button"
type="submit" type="submit"
onClick={() => setOpen(true)} onClick={() => setOpen(true)}
sx={{ m: 2 }}
> >
<FormattedMessage id="manageAccess" defaultMessage="Manage access" /> <FormattedMessage id="manageAccess" defaultMessage="Manage access" />
</InnovenergyButton> </InnovenergyButton>

View File

@ -10,11 +10,11 @@ const InnovenergyList = (props: InnovenergyListProps) => {
return ( return (
<List <List
sx={{ sx={{
bgcolor: "background.paper", bgcolor: "white",
position: "relative", position: "relative",
overflow: "auto", overflow: "auto",
maxHeight: 500, maxHeight: 500,
pr: 2, pb: 0,
}} }}
component="nav" component="nav"
aria-labelledby="nested-list-subheader" aria-labelledby="nested-list-subheader"

View File

@ -38,7 +38,23 @@ const Folder = () => {
return ( return (
<> <>
<Box sx={{ py: 3 }}> <Box
sx={{
py: 3,
bgcolor: "#CCD6E4",
px: 1,
borderBottom: 1,
borderRight: 1,
borderLeft: 1,
bordertop: 0,
borderTopLeftRadius: 0,
WebkitBorderTopRightRadius: 0,
borderBottomLeftRadius: 4,
borderBottomRightRadius: 4,
borderColor: "#90a7c5",
marginTop: 0.05,
}}
>
<FolderForm <FolderForm
values={values} values={values}
handleSubmit={handleSubmit} handleSubmit={handleSubmit}
@ -52,7 +68,7 @@ const Folder = () => {
<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 }} /> <CircularProgress sx={{ m: 2 }} color="secondary" />
</Box> </Box>
); );
} else if (error) { } else if (error) {

View File

@ -79,7 +79,7 @@ const FolderForm = (props: I_CustomerFormProps) => {
handleChange={formik.handleChange} handleChange={formik.handleChange}
/> />
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}> <Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
{loading && <CircularProgress />} {loading && <CircularProgress color="secondary" />}
{!readOnly && {!readOnly &&
additionalButtons && additionalButtons &&
additionalButtons.map((button) => button)} additionalButtons.map((button) => button)}

View File

@ -5,7 +5,11 @@ import useRouteMatch from "../../hooks/useRouteMatch";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { GroupContext } from "../Context/GroupContextProvider"; import { GroupContext } from "../Context/GroupContextProvider";
import { useContext } from "react"; import { useContext } from "react";
import { AntTabs, StyledTab } from "../../util/installation.util"; import {
AntTabs,
StyledTab,
StyledTabBlue,
} from "../../util/installation.util";
const GroupTabs = () => { const GroupTabs = () => {
const routeMatch = useRouteMatch([ const routeMatch = useRouteMatch([
@ -21,7 +25,7 @@ const GroupTabs = () => {
if (id) { if (id) {
return ( return (
<Box sx={{ width: "100%" }}> <Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}> <Box sx={{}}>
<AntTabs <AntTabs
value={routeMatch?.pattern?.path} value={routeMatch?.pattern?.path}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
@ -30,7 +34,8 @@ const GroupTabs = () => {
})} })}
> >
{currentType === "Folder" ? ( {currentType === "Folder" ? (
<StyledTab <StyledTabBlue
sx={{ bgcolor: "#90A7C5" }}
id="styled-tab-folder" id="styled-tab-folder"
label={intl.formatMessage({ label={intl.formatMessage({
id: "folder", id: "folder",
@ -43,7 +48,8 @@ const GroupTabs = () => {
to={routes.folder + id} to={routes.folder + id}
/> />
) : ( ) : (
<StyledTab <StyledTabBlue
sx={{ bgcolor: "#90A7C5" }}
id="styled-tab-installation" id="styled-tab-installation"
label={intl.formatMessage({ label={intl.formatMessage({
id: "installation", id: "installation",
@ -60,7 +66,8 @@ const GroupTabs = () => {
/> />
)} )}
<StyledTab <StyledTabBlue
sx={{ bgcolor: "#90A7C5" }}
id="styled-tab-manage-access" id="styled-tab-manage-access"
label={intl.formatMessage({ label={intl.formatMessage({
id: "manageAccess", id: "manageAccess",

View File

@ -0,0 +1,4 @@
.groupTreeLink {
text-decoration: "none";
color: "red";
}

View File

@ -53,6 +53,8 @@ const GroupTree = () => {
onClick={() => setCurrentType(element.type)} onClick={() => setCurrentType(element.type)}
sx={{ sx={{
".MuiTreeItem-content": { paddingY: "12px" }, ".MuiTreeItem-content": { paddingY: "12px" },
bgcolor: "#CCD6E4",
borderRadius: 2,
}} }}
> >
{getNodes(element)} {getNodes(element)}
@ -64,7 +66,7 @@ const GroupTree = () => {
if (loading) { if (loading) {
return ( return (
<Grid container justifyContent="center" width="100%"> <Grid container justifyContent="center" width="100%">
<CircularProgress /> <CircularProgress color="secondary" />
</Grid> </Grid>
); );
} }

View File

@ -31,7 +31,22 @@ const Installation = (props: I_InstallationProps) => {
if (values && values.id && values.id.toString() === id) { if (values && values.id && values.id.toString() === id) {
return ( return (
<Box sx={{ py: 3 }}> <Box
sx={{
py: 3,
bgcolor: "#CCD6E4",
px: 1,
borderLeft: 1,
borderRight: 1,
borderBottom: 1,
borderTopLeftRadius: 0,
WebkitBorderTopRightRadius: 0,
borderBottomLeftRadius: 4,
borderBottomRightRadius: 4,
borderColor: "#90a7c5",
marginTop: 0.05,
}}
>
<InstallationForm <InstallationForm
values={values} values={values}
id={id} id={id}
@ -44,7 +59,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 }} /> <CircularProgress sx={{ m: 2 }} color="secondary" />
</Box> </Box>
); );
} else if (error) { } else if (error) {

View File

@ -53,7 +53,7 @@ const InstallationList = (props: InstallationListProps) => {
if (loading) { if (loading) {
return ( return (
<Grid container justifyContent="center" width="100%"> <Grid container justifyContent="center" width="100%">
<CircularProgress sx={{ m: 6 }} /> <CircularProgress sx={{ m: 6 }} color="secondary" />
</Grid> </Grid>
); );
} else if (data && data.length) { } else if (data && data.length) {
@ -66,12 +66,11 @@ const InstallationList = (props: InstallationListProps) => {
overflow: "auto", overflow: "auto",
py: 0, py: 0,
mt: 1, mt: 1,
maxHeight: "70vh",
height: height:
routeMatch?.pattern.path === routeMatch?.pattern.path ===
routes.installations + routes.list + routes.log + ":id" routes.installations + routes.list + routes.log + ":id"
? "130px" ? "130px"
: "80vh", : "500px",
}} }}
component="nav" component="nav"
aria-labelledby="nested-list-subheader" aria-labelledby="nested-list-subheader"
@ -84,11 +83,25 @@ const InstallationList = (props: InstallationListProps) => {
to={ to={
getPathWithoutId(routeMatch?.pattern?.path) + installation.id getPathWithoutId(routeMatch?.pattern?.path) + installation.id
} }
style={{ textDecoration: "none", color: "black" }} style={{ textDecoration: "none", color: "#2b3e54" }}
> >
<ListItemButton <ListItemButton
id={"installation-list-button-" + installation.id} id={"installation-list-button-" + installation.id}
selected={installation.id === Number(routeMatch?.params.id)} selected={installation.id === Number(routeMatch?.params.id)}
sx={{
mr: "1px",
borderStyle: "solid",
backgroundColor: "#577ba840",
"&.Mui-selected": {
backgroundColor: "#90A7C5",
},
":hover": {
backgroundColor: "#AFC0D5",
},
"&.Mui-selected:hover": {
backgroundColor: "#90A7C5",
},
}}
> >
<ListItemText <ListItemText
id={"installation-list-text-" + installation.id} id={"installation-list-text-" + installation.id}
@ -96,7 +109,6 @@ const InstallationList = (props: InstallationListProps) => {
/> />
</ListItemButton> </ListItemButton>
</Link> </Link>
<Divider />
</Fragment> </Fragment>
); );
})} })}

View File

@ -4,7 +4,14 @@ import { Link } from "react-router-dom";
import routes from "../../routes.json"; import routes from "../../routes.json";
import useRouteMatch from "../../hooks/useRouteMatch"; import useRouteMatch from "../../hooks/useRouteMatch";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { AntTabs, StyledTab } from "../../util/installation.util"; import {
AntTabs,
StyledTab,
StyledTabBlue,
StyledTabWhite,
} from "../../util/installation.util";
import { colors } from "@mui/material";
import { Background } from "reactflow";
const InstallationTabs = () => { const InstallationTabs = () => {
const routeMatch = useRouteMatch([ const routeMatch = useRouteMatch([
@ -19,7 +26,7 @@ const InstallationTabs = () => {
if (id) { if (id) {
return ( return (
<Box sx={{ width: "100%" }}> <Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}> <Box sx={{}}>
<AntTabs <AntTabs
value={routeMatch?.pattern?.path ?? routes.installation + ":id"} value={routeMatch?.pattern?.path ?? routes.installation + ":id"}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
@ -27,7 +34,8 @@ const InstallationTabs = () => {
defaultMessage: "Installation tabs", defaultMessage: "Installation tabs",
})} })}
> >
<StyledTab <StyledTabBlue
sx={{ bgcolor: "#90A7C5" }}
id={"installation-tab-installation"} id={"installation-tab-installation"}
label={intl.formatMessage({ label={intl.formatMessage({
id: "installation", id: "installation",
@ -39,7 +47,8 @@ const InstallationTabs = () => {
component={Link} component={Link}
to={routes.installation + id} to={routes.installation + id}
/> />
<StyledTab <StyledTabWhite
sx={{ bgcolor: "#90A7C5" }}
id={"installation-tab-liveView"} id={"installation-tab-liveView"}
label={intl.formatMessage({ label={intl.formatMessage({
id: "liveView", id: "liveView",
@ -52,6 +61,7 @@ const InstallationTabs = () => {
to={routes.liveView + id} to={routes.liveView + id}
/> />
<StyledTab <StyledTab
sx={{ bgcolor: "#90A7C5" }}
id={"installation-tab-log"} id={"installation-tab-log"}
label={intl.formatMessage({ label={intl.formatMessage({
id: "log", id: "log",

View File

@ -1,4 +1,4 @@
import { Grid } from "@mui/material"; import { Grid, colors } from "@mui/material";
import { Routes, Route } from "react-router"; import { Routes, Route } from "react-router";
import LiveView from "./LiveView"; import LiveView from "./LiveView";
import InstallationTabs from "./InstallationTabs"; import InstallationTabs from "./InstallationTabs";
@ -11,6 +11,8 @@ import Installation from "./Installation";
import CheckboxTree from "./Log/CheckboxTree"; import CheckboxTree from "./Log/CheckboxTree";
import LogContextProvider from "../Context/LogContextProvider"; import LogContextProvider from "../Context/LogContextProvider";
import useRouteMatch from "../../hooks/useRouteMatch"; import useRouteMatch from "../../hooks/useRouteMatch";
import { Background } from "reactflow";
import { red } from "@mui/material/colors";
const Installations = () => { const Installations = () => {
const routeMatch = useRouteMatch([ const routeMatch = useRouteMatch([

View File

@ -1,5 +1,5 @@
import { TreeItem, TreeView } from "@mui/lab"; import { TreeItem, TreeView } from "@mui/lab";
import { Checkbox, Divider } from "@mui/material"; import { Checkbox, Divider, colors } from "@mui/material";
import { useContext, ReactNode } from "react"; import { useContext, ReactNode } from "react";
import { LogContext } from "../../Context/LogContextProvider"; import { LogContext } from "../../Context/LogContextProvider";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
@ -7,6 +7,7 @@ import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import useRouteMatch from "../../../hooks/useRouteMatch"; import useRouteMatch from "../../../hooks/useRouteMatch";
import routes from "../../../routes.json"; import routes from "../../../routes.json";
import React from "react"; import React from "react";
import { blueGrey } from "@mui/material/colors";
export interface ToggleElement { export interface ToggleElement {
[key: string]: boolean; [key: string]: boolean;
@ -71,7 +72,8 @@ const CheckboxTree = () => {
</> </>
} }
sx={{ sx={{
".MuiTreeItem-content": { paddingY: "5px", minHeight: "52px" }, ".MuiTreeItem-content": { paddingY: "5px" },
bgcolor: "#CCD6E4",
}} }}
> >
{getNodes(element)} {getNodes(element)}
@ -89,12 +91,14 @@ const CheckboxTree = () => {
defaultCollapseIcon={<ExpandMoreIcon />} defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />} defaultExpandIcon={<ChevronRightIcon />}
sx={{ sx={{
flexGrow: 1, flexGrow: 100,
overflow: "auto", overflow: "auto",
overflowX: "hidden", overflowX: "hidden",
position: ["sticky", "-webkit-sticky"], position: ["sticky", "-webkit-sticky"],
top: 1, top: 1,
maxHeight: "90vh", maxHeight: "90vh",
borderBottomLeftRadius: 5,
borderBottomRightRadius: 5,
}} }}
> >
{renderTree(toggles)} {renderTree(toggles)}

View File

@ -6,6 +6,7 @@ import { FormattedMessage } from "react-intl";
import ShortcutButton from "./ShortcutButton"; import ShortcutButton from "./ShortcutButton";
import { createTimes } from "../../../util/graph.util"; import { createTimes } from "../../../util/graph.util";
import { TimeRange, UnixTime } from "../../../dataCache/time"; import { TimeRange, UnixTime } from "../../../dataCache/time";
import { TextField } from "@mui/material";
interface DateRangePickerProps { interface DateRangePickerProps {
setRange: (value: Date[]) => void; setRange: (value: Date[]) => void;

View File

@ -1,6 +1,8 @@
import { colors } from "@mui/material";
import { UnixTime, TimeSpan } from "../../../dataCache/time"; import { UnixTime, TimeSpan } from "../../../dataCache/time";
import { createTimes } from "../../../util/graph.util"; import { createTimes } from "../../../util/graph.util";
import InnovenergyButton from "../../Layout/InnovenergyButton"; import InnovenergyButton from "../../Layout/InnovenergyButton";
import { red } from "@mui/material/colors";
interface ShortcutButtonProps { interface ShortcutButtonProps {
setRange: (value: Date[]) => void; setRange: (value: Date[]) => void;

View File

@ -0,0 +1,10 @@
.topologyBoxTitle{
margin-block-start: "0";
margin-block-end: "0";
background-color: titleColor;
padding: "5px";
border-top-left-radius: "4px";
border-top-right-radius: "4px";
display: "flex";
justify-content: "center";
}

View File

@ -45,7 +45,18 @@ const TopologyView = () => {
sx={{ sx={{
display: "flex", display: "flex",
flexDirection: "row", flexDirection: "row",
padding: 2, paddingTop: 3,
paddingBottom: 3,
bgcolor: "white",
px: 3 / 8,
border: 1,
borderTopLeftRadius: 0,
WebkitBorderTopRightRadius: 0,
borderBottomLeftRadius: 4,
borderBottomRightRadius: 4,
borderColor: "#CCD6E4",
borderTopColor: "white",
marginTop: 0.05,
fontFamily: `"Ubuntu", sans-serif`, fontFamily: `"Ubuntu", sans-serif`,
fontSize: "12px", fontSize: "12px",
}} }}

View File

@ -43,7 +43,7 @@ const Detail = <T extends { id: number }>(props: I_DetailProps<T>) => {
<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 }} /> <CircularProgress sx={{ m: 2 }} color="secondary" />
</Box> </Box>
); );
} else if (error) { } else if (error) {

View File

@ -1,5 +1,7 @@
import { Button, SxProps, Theme } from "@mui/material"; import { Button, SxProps, Theme, colors } from "@mui/material";
import { DAY_MARGIN } from "@mui/x-date-pickers/internals";
import { ReactNode } from "react"; import { ReactNode } from "react";
import { Background } from "reactflow";
interface I_InnovenergyButtonProps { interface I_InnovenergyButtonProps {
children?: ReactNode; children?: ReactNode;
@ -12,6 +14,7 @@ interface I_InnovenergyButtonProps {
const InnovenergyButton = (props: I_InnovenergyButtonProps) => { const InnovenergyButton = (props: I_InnovenergyButtonProps) => {
return ( return (
<Button <Button
color="secondary"
id={props.id} id={props.id}
variant="contained" variant="contained"
type={props.type} type={props.type}

View File

@ -21,20 +21,20 @@ const InnovenergyTextfield = (props: I_InnovenergyTextfieldProps) => {
</Grid> </Grid>
<Grid item xs={9}> <Grid item xs={9}>
<TextField <TextField
color="info"
id={props.id} id={props.id}
variant="outlined" variant="outlined"
name={props.name} name={props.name}
type={props.type} type={props.type}
fullWidth fullWidth
sx={{ sx={{
input: {
bgcolor: "white",
border: 0.5,
borderRadius: 1,
},
my: 0.5, my: 0.5,
".Mui-disabled": { borderColor: "red",
"-webkit-text-fill-color": "black",
color: "black",
},
".MuiFormHelperText-root": {
marginLeft: 0,
},
}} }}
value={props.value || ""} value={props.value || ""}
onChange={props.handleChange} onChange={props.handleChange}

View File

@ -8,6 +8,7 @@ interface LanguageSelectProps {
const LanguageSelect = (props: LanguageSelectProps) => { const LanguageSelect = (props: LanguageSelectProps) => {
return ( return (
<Select <Select
color="info"
id="language-select" id="language-select"
value={props.language} value={props.language}
label="Age" label="Age"

View File

@ -39,6 +39,7 @@ const ModeButtons = () => {
size="small" size="small"
> >
<ToggleButton <ToggleButton
color="info"
id="mode-toggle-button-list" id="mode-toggle-button-list"
value={routes.installations + routes.list + "*"} value={routes.installations + routes.list + "*"}
component={Link} component={Link}
@ -47,6 +48,7 @@ const ModeButtons = () => {
<ListIcon id="mode-toggle-button-list-icon" /> <ListIcon id="mode-toggle-button-list-icon" />
</ToggleButton> </ToggleButton>
<ToggleButton <ToggleButton
color="info"
id="mode-toggle-button-tree" id="mode-toggle-button-tree"
value={routes.installations + routes.tree + "*"} value={routes.installations + routes.tree + "*"}
component={Link} component={Link}

View File

@ -2,7 +2,13 @@ import { FormattedMessage, useIntl } from "react-intl";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import useRouteMatch from "../../hooks/useRouteMatch"; import useRouteMatch from "../../hooks/useRouteMatch";
import routes from "../../routes.json"; import routes from "../../routes.json";
import { AntTabs, StyledTab } from "../../util/installation.util"; import {
AntTabs,
AntTabsBig,
StyledTab,
StyledTabBig,
} from "../../util/installation.util";
import { Background } from "reactflow";
const NavigationButtons = () => { const NavigationButtons = () => {
const routeMatch = useRouteMatch([ const routeMatch = useRouteMatch([
@ -35,7 +41,7 @@ const NavigationButtons = () => {
<FormattedMessage id="users" defaultMessage="Users" /> <FormattedMessage id="users" defaultMessage="Users" />
</ToggleButton> </ToggleButton>
</ToggleButtonGroup> */} </ToggleButtonGroup> */}
<AntTabs <AntTabsBig
id="navigation-buttons-group" id="navigation-buttons-group"
value={routeMatch?.pattern?.path} value={routeMatch?.pattern?.path}
aria-label={intl.formatMessage({ aria-label={intl.formatMessage({
@ -43,7 +49,7 @@ const NavigationButtons = () => {
defaultMessage: "Navigation tabs", defaultMessage: "Navigation tabs",
})} })}
> >
<StyledTab <StyledTabBig
id="navigation-tab-installations" id="navigation-tab-installations"
value={routes.installations + "*"} value={routes.installations + "*"}
component={Link} component={Link}
@ -55,14 +61,14 @@ const NavigationButtons = () => {
/> />
} }
/> />
<StyledTab <StyledTabBig
id="navigation-tab-users" id="navigation-tab-users"
value={routes.users + "*"} value={routes.users + "*"}
component={Link} component={Link}
to={routes.users} to={routes.users}
label={<FormattedMessage id="users" defaultMessage="Users" />} label={<FormattedMessage id="users" defaultMessage="Users" />}
/> />
</AntTabs> </AntTabsBig>
</> </>
); );
}; };

View File

@ -1,4 +1,11 @@
import { TextField } from "@mui/material"; import {
OutlinedInputProps,
TextField,
TextFieldProps,
alpha,
colors,
styled,
} from "@mui/material";
import { FC, useState } from "react"; import { FC, useState } from "react";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
@ -7,14 +14,43 @@ interface SearchSidebarProps {
id: string; id: string;
height?: string; height?: string;
} }
const SearchInputTextfield = styled((props: TextFieldProps) => (
<TextField
InputProps={{ disableUnderline: true } as Partial<OutlinedInputProps>}
{...props}
/>
))(({ theme }) => ({
"& .MuiFilledInput-root": {
overflow: "hidden",
borderRadius: 4,
backgroundColor: "#577ba840",
border: "1px solid",
borderColor: "#577ba840",
transition: theme.transitions.create([
"border-color",
"background-color",
"box-shadow",
]),
"&:hover": {
backgroundColor: "#577ba840",
},
"&.Mui-focused": {
backgroundColor: "#AFCOD5",
borderColor: "#577ba840",
color: "info",
},
},
}));
const SearchSidebar = (props: SearchSidebarProps) => { const SearchSidebar = (props: SearchSidebarProps) => {
const { listComponent: ListComponent, id, height } = props; const { listComponent: ListComponent, id, height } = props;
const [searchQuery, setSearchQuery] = useState(""); const [searchQuery, setSearchQuery] = useState("");
const intl = useIntl(); const intl = useIntl();
return ( return (
<div style={{ height: height ?? "500px", overflow: "hidden" }}> <div style={{ height: height ?? "750px", overflow: "hidden" }}>
<TextField {/* <RedditTextField
style={{ backgroundColor: "#577ba840" }}
color="secondary"
id={id} id={id}
label={intl.formatMessage({ label={intl.formatMessage({
id: "search", id: "search",
@ -24,6 +60,19 @@ const SearchSidebar = (props: SearchSidebarProps) => {
fullWidth fullWidth
value={searchQuery} value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)} onChange={(e) => setSearchQuery(e.target.value)}
/> */}
<SearchInputTextfield
id={id}
variant="filled"
onChange={(e) => setSearchQuery(e.target.value)}
value={searchQuery}
fullWidth
label={intl.formatMessage({
id: "search",
defaultMessage: "Search",
})}
color="info"
type="search"
/> />
<ListComponent searchQuery={searchQuery} /> <ListComponent searchQuery={searchQuery} />
</div> </div>

View File

@ -1,4 +1,4 @@
import { Dialog, DialogTitle, IconButton, DialogContent } from "@mui/material"; import { Dialog, DialogTitle, IconButton, DialogContent, colors } from "@mui/material";
import { useState } from "react"; import { useState } from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import axiosConfig from "../../config/axiosConfig"; import axiosConfig from "../../config/axiosConfig";
@ -24,7 +24,7 @@ const AddUser = () => {
<> <>
<InnovenergyButton <InnovenergyButton
id="add-user-button" id="add-user-button"
sx={{ my: 1 }} sx={{ my: 1, }}
onClick={() => setOpen(true)} onClick={() => setOpen(true)}
> >
<FormattedMessage id="addUser" defaultMessage="Create user" /> <FormattedMessage id="addUser" defaultMessage="Create user" />

View File

@ -42,7 +42,22 @@ const Detail = (props: I_DetailProps) => {
if (values && values.id && values.id.toString() === id) { if (values && values.id && values.id.toString() === id) {
return ( return (
<Box sx={{ py: 3 }}> <Box
sx={{
py: 3,
bgcolor: "#CCD6E4",
px: 1,
borderBottom: 1,
borderRight: 1,
borderLeft: 1,
bordertop: 0,
borderTopLeftRadius: 0,
WebkitBorderTopRightRadius: 0,
borderBottomLeftRadius: 4,
borderBottomRightRadius: 4,
borderColor: "#90a7c5",
}}
>
<UserForm values={values} handleSubmit={handleUpdate} /> <UserForm values={values} handleSubmit={handleUpdate} />
</Box> </Box>
); );
@ -51,7 +66,7 @@ const Detail = (props: I_DetailProps) => {
<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 }} /> <CircularProgress sx={{ m: 2 }} color="secondary" />
</Box> </Box>
); );
} else if (error) { } else if (error) {

View File

@ -88,7 +88,7 @@ const UserForm = (props: I_UserFormProps) => {
disabled={readOnly} disabled={readOnly}
/> />
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}> <Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
{loading && <CircularProgress />} {loading && <CircularProgress color="secondary" />}
{currentUser.hasWriteAccess && ( {currentUser.hasWriteAccess && (
<InnovenergyButton type="submit"> <InnovenergyButton type="submit">
<FormattedMessage id="submit" defaultMessage="Submit" /> <FormattedMessage id="submit" defaultMessage="Submit" />

View File

@ -60,6 +60,20 @@ const UserList = (props: UserListProps) => {
> >
<ListItemButton <ListItemButton
selected={user.id === Number(routeMatch?.params.id)} selected={user.id === Number(routeMatch?.params.id)}
sx={{
mr: "1px",
borderStyle: "solid",
backgroundColor: "#577ba840",
"&.Mui-selected": {
backgroundColor: "#90A7C5",
},
":hover": {
backgroundColor: "#AFC0D5",
},
"&.Mui-selected:hover": {
backgroundColor: "#90A7C5",
},
}}
> >
<ListItemText primary={user.name} /> <ListItemText primary={user.name} />
</ListItemButton> </ListItemButton>

View File

@ -3,7 +3,11 @@ import { Link } from "react-router-dom";
import routes from "../../routes.json"; import routes from "../../routes.json";
import useRouteMatch from "../../hooks/useRouteMatch"; import useRouteMatch from "../../hooks/useRouteMatch";
import { useIntl } from "react-intl"; import { useIntl } from "react-intl";
import { AntTabs, StyledTab } from "../../util/installation.util"; import {
AntTabs,
StyledTab,
StyledTabBlue,
} from "../../util/installation.util";
const UserTabs = () => { const UserTabs = () => {
const routeMatch = useRouteMatch([routes.users + routes.user + ":id"]); const routeMatch = useRouteMatch([routes.users + routes.user + ":id"]);
@ -21,7 +25,7 @@ const UserTabs = () => {
defaultMessage: "user tabs", defaultMessage: "user tabs",
})} })}
> >
<StyledTab <StyledTabBlue
id="users-tab-user" id="users-tab-user"
label={intl.formatMessage({ label={intl.formatMessage({
id: "user", id: "user",

View File

@ -11,3 +11,8 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace; monospace;
} }
body {
background-color: #F2F4F8;
}

View File

@ -12,14 +12,21 @@ const root = ReactDOM.createRoot(
const theme = createTheme({ const theme = createTheme({
palette: { palette: {
primary: {
main: "#F59100",
},
text: { text: {
primary: "#000000", primary: "#2b3e54",
secondary: "#000000", secondary: "#000000",
disabled: "#000000", disabled: "#000000",
}, },
secondary: {
main: "#90A7C5",
dark: "#CCD6E4",
},
info: {
main: "#2b3e54",
},
warning: {
main: "#90a7c5",
},
}, },
typography: { typography: {
fontFamily: `"Ubuntu", sans-serif`, fontFamily: `"Ubuntu", sans-serif`,
@ -28,13 +35,11 @@ const theme = createTheme({
}); });
root.render( root.render(
<React.StrictMode>
<ThemeProvider theme={theme}> <ThemeProvider theme={theme}>
<UserContextProvider> <UserContextProvider>
<App /> <App />
</UserContextProvider> </UserContextProvider>
</ThemeProvider> </ThemeProvider>
</React.StrictMode>
); );
// If you want to start measuring performance in your app, pass a function // If you want to start measuring performance in your app, pass a function

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -3,30 +3,115 @@ import { styled, Tab, Tabs } from "@mui/material";
export const StyledTab = styled((props: any) => ( export const StyledTab = styled((props: any) => (
<Tab disableRipple {...props} /> <Tab disableRipple {...props} />
))(({ theme }) => ({ ))(({ theme }) => ({
bottom: -1,
textTransform: "uppercase", textTransform: "uppercase",
fontWeight: theme.typography.fontWeightRegular, fontWeight: theme.typography.fontWeightRegular,
fontSize: theme.typography.pxToRem(14), fontSize: theme.typography.pxToRem(14),
marginRight: theme.spacing(1), marginRight: theme.spacing(1),
background: "0 0", background: "0 0",
border: "1px solid transparent", border: "1px solid transparent",
borderTopLeftRadius: "0.25rem", borderTopLeftRadius: "0.3rem",
borderTopRightRadius: "0.25rem", 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": {
color: "#000000", color: "#000000",
backgroundColor: "#fff", backgroundColor: "#F2F4F8",
borderColor: "#bdbdbd #bdbdbd #fff", borderColor: "#90A7c5 #90A7c5 #F2F4F8",
marginBottom: "-3px", marginTop: "1px",
bottom: -1,
}, },
"&.Mui-focusVisible": { "&.Mui-focusVisible": {
backgroundColor: "rgba(100, 95, 228, 0.32)", backgroundColor: "rgba(100, 95, 228, 0.32)",
}, },
})); }));
export const AntTabs = styled(Tabs)({ export const StyledTabBlue = styled((props: any) => (
borderBottom: "1px solid #bdbdbd", <Tab disableRipple {...props} />
))(({ theme }) => ({
bottom: -1,
textTransform: "uppercase",
fontWeight: theme.typography.fontWeightRegular,
fontSize: theme.typography.pxToRem(14),
marginRight: theme.spacing(1),
background: "0 0",
border: "1px solid transparent",
borderBottom: "0px",
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": {
bottom: -1,
color: "#000000",
backgroundColor: "#CCD6E4",
borderColor: "#90A7c5 #90A7c5 #CCD6E4",
marginTop: "1px",
},
"&.Mui-focusVisible": {
backgroundColor: "rgba(100, 95, 228, 0.32)",
},
}));
export const StyledTabBig = styled((props: any) => (
<Tab disableRipple {...props} />
))(({ theme }) => ({
bottom: -2,
textTransform: "uppercase",
fontWeight: theme.typography.fontWeightRegular,
fontSize: theme.typography.pxToRem(14),
marginRight: theme.spacing(1),
background: "0 0",
border: "2px solid transparent",
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": {
color: "#000000",
backgroundColor: "#F2F4F8",
borderColor: "#90A7c5 #90A7c5 #F2F4F8",
marginTop: "1px",
bottom: -2,
},
"&.Mui-focusVisible": {
backgroundColor: "rgba(100, 95, 228, 0.32)",
},
}));
export const StyledTabWhite = styled((props: any) => (
<Tab disableRipple {...props} />
))(({ theme }) => ({
bottom: -1,
textTransform: "uppercase",
fontWeight: theme.typography.fontWeightRegular,
fontSize: theme.typography.pxToRem(14),
marginRight: theme.spacing(1),
background: "0 0",
border: "1px solid transparent",
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": {
color: "#000000",
backgroundColor: "White",
borderColor: "#90A7c5 #90A7c5 White",
marginTop: "1px",
bottom: -1,
},
"&.Mui-focusVisible": {
backgroundColor: "rgba(100, 95, 228, 0.32)",
},
}));
export const AntTabsBig = styled(Tabs)({
borderBottom: "2px solid #90A7c5",
overflow: "visible!important", overflow: "visible!important",
"& div.MuiTabs-scroller": { "& div.MuiTabs-scroller": {
overflow: "visible!important", overflow: "visible!important",
@ -34,7 +119,28 @@ export const AntTabs = styled(Tabs)({
"&.Mui-selected": { "&.Mui-selected": {
color: "#000000", color: "#000000",
backgroundColor: "red", backgroundColor: "red",
borderColor: `#bdbdbd #bdbdbd #fff`, borderColor: `#90A7c5 #90A7c5 #fff`,
},
"& .MuiTabs-indicator": {
display: "flex",
justifyContent: "center",
backgroundColor: "transparent",
},
"&.MuiTabs-root": {
width: "100%",
},
});
export const AntTabs = styled(Tabs)({
borderBottom: "1px solid #90A7c5",
overflow: "visible!important",
"& div.MuiTabs-scroller": {
overflow: "visible!important",
},
"&.Mui-selected": {
color: "#000000",
backgroundColor: "red",
borderColor: `#90A7c5 #90A7c5 #fff`,
}, },
"& .MuiTabs-indicator": { "& .MuiTabs-indicator": {
display: "flex", display: "flex",

7
typescript/Web/dist/server.js.map vendored Normal file

File diff suppressed because one or more lines are too long

7
typescript/Web/dist/www/client.js.map vendored Normal file

File diff suppressed because one or more lines are too long