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)
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;
"GetAllFoldersAndInstallations".WriteLine();
if (user is null)
return Unauthorized();

View File

@ -1,7 +1,8 @@
import useToken from "./hooks/useToken";
import Login from "./Login";
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 { IntlProvider } from "react-intl";
import { useContext, useState } from "react";
@ -14,7 +15,8 @@ import NavigationButtons from "./components/Layout/NavigationButtons";
import InstallationPage from "./components/Installations/InstallationPage";
import { UserContext } from "./components/Context/UserContextProvider";
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 { token, setToken, removeToken } = useToken();
@ -43,9 +45,13 @@ const App = () => {
defaultLocale="EN"
>
<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">
<img src={innovenergyLogo} alt="innovenergy logo" height="50" />
<img
src={innovenergyLogo}
alt="innovenergy logo"
height="75" //style={color: #0960ac;background: #df7900;}
/>
</Grid>
<Grid item xs={9} container justifyContent="flex-end">
<LanguageSelect language={language} setLanguage={setLanguage} />

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -38,7 +38,23 @@ const Folder = () => {
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
values={values}
handleSubmit={handleSubmit}
@ -52,7 +68,7 @@ const Folder = () => {
<Box
sx={{ width: 1 / 2, justifyContent: "center", display: "flex", mt: 10 }}
>
<CircularProgress sx={{ m: 2 }} />
<CircularProgress sx={{ m: 2 }} color="secondary" />
</Box>
);
} else if (error) {

View File

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

View File

@ -5,7 +5,11 @@ import useRouteMatch from "../../hooks/useRouteMatch";
import { useIntl } from "react-intl";
import { GroupContext } from "../Context/GroupContextProvider";
import { useContext } from "react";
import { AntTabs, StyledTab } from "../../util/installation.util";
import {
AntTabs,
StyledTab,
StyledTabBlue,
} from "../../util/installation.util";
const GroupTabs = () => {
const routeMatch = useRouteMatch([
@ -21,7 +25,7 @@ const GroupTabs = () => {
if (id) {
return (
<Box sx={{ width: "100%" }}>
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Box sx={{}}>
<AntTabs
value={routeMatch?.pattern?.path}
aria-label={intl.formatMessage({
@ -30,7 +34,8 @@ const GroupTabs = () => {
})}
>
{currentType === "Folder" ? (
<StyledTab
<StyledTabBlue
sx={{ bgcolor: "#90A7C5" }}
id="styled-tab-folder"
label={intl.formatMessage({
id: "folder",
@ -43,7 +48,8 @@ const GroupTabs = () => {
to={routes.folder + id}
/>
) : (
<StyledTab
<StyledTabBlue
sx={{ bgcolor: "#90A7C5" }}
id="styled-tab-installation"
label={intl.formatMessage({
id: "installation",
@ -60,7 +66,8 @@ const GroupTabs = () => {
/>
)}
<StyledTab
<StyledTabBlue
sx={{ bgcolor: "#90A7C5" }}
id="styled-tab-manage-access"
label={intl.formatMessage({
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)}
sx={{
".MuiTreeItem-content": { paddingY: "12px" },
bgcolor: "#CCD6E4",
borderRadius: 2,
}}
>
{getNodes(element)}
@ -64,7 +66,7 @@ const GroupTree = () => {
if (loading) {
return (
<Grid container justifyContent="center" width="100%">
<CircularProgress />
<CircularProgress color="secondary" />
</Grid>
);
}

View File

@ -31,7 +31,22 @@ const Installation = (props: I_InstallationProps) => {
if (values && values.id && values.id.toString() === id) {
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
values={values}
id={id}
@ -44,7 +59,7 @@ const Installation = (props: I_InstallationProps) => {
<Box
sx={{ width: 1 / 2, justifyContent: "center", display: "flex", mt: 10 }}
>
<CircularProgress sx={{ m: 2 }} />
<CircularProgress sx={{ m: 2 }} color="secondary" />
</Box>
);
} else if (error) {

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,8 @@
import { colors } from "@mui/material";
import { UnixTime, TimeSpan } from "../../../dataCache/time";
import { createTimes } from "../../../util/graph.util";
import InnovenergyButton from "../../Layout/InnovenergyButton";
import { red } from "@mui/material/colors";
interface ShortcutButtonProps {
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={{
display: "flex",
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`,
fontSize: "12px",
}}

View File

@ -43,7 +43,7 @@ const Detail = <T extends { id: number }>(props: I_DetailProps<T>) => {
<Box
sx={{ width: 1 / 2, justifyContent: "center", display: "flex", mt: 10 }}
>
<CircularProgress sx={{ m: 2 }} />
<CircularProgress sx={{ m: 2 }} color="secondary" />
</Box>
);
} 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 { Background } from "reactflow";
interface I_InnovenergyButtonProps {
children?: ReactNode;
@ -12,6 +14,7 @@ interface I_InnovenergyButtonProps {
const InnovenergyButton = (props: I_InnovenergyButtonProps) => {
return (
<Button
color="secondary"
id={props.id}
variant="contained"
type={props.type}

View File

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

View File

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

View File

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

View File

@ -2,7 +2,13 @@ import { FormattedMessage, useIntl } from "react-intl";
import { Link } from "react-router-dom";
import useRouteMatch from "../../hooks/useRouteMatch";
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 routeMatch = useRouteMatch([
@ -35,7 +41,7 @@ const NavigationButtons = () => {
<FormattedMessage id="users" defaultMessage="Users" />
</ToggleButton>
</ToggleButtonGroup> */}
<AntTabs
<AntTabsBig
id="navigation-buttons-group"
value={routeMatch?.pattern?.path}
aria-label={intl.formatMessage({
@ -43,7 +49,7 @@ const NavigationButtons = () => {
defaultMessage: "Navigation tabs",
})}
>
<StyledTab
<StyledTabBig
id="navigation-tab-installations"
value={routes.installations + "*"}
component={Link}
@ -55,14 +61,14 @@ const NavigationButtons = () => {
/>
}
/>
<StyledTab
<StyledTabBig
id="navigation-tab-users"
value={routes.users + "*"}
component={Link}
to={routes.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 { useIntl } from "react-intl";
@ -7,14 +14,43 @@ interface SearchSidebarProps {
id: 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 { listComponent: ListComponent, id, height } = props;
const [searchQuery, setSearchQuery] = useState("");
const intl = useIntl();
return (
<div style={{ height: height ?? "500px", overflow: "hidden" }}>
<TextField
<div style={{ height: height ?? "750px", overflow: "hidden" }}>
{/* <RedditTextField
style={{ backgroundColor: "#577ba840" }}
color="secondary"
id={id}
label={intl.formatMessage({
id: "search",
@ -24,6 +60,19 @@ const SearchSidebar = (props: SearchSidebarProps) => {
fullWidth
value={searchQuery}
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} />
</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 { FormattedMessage, useIntl } from "react-intl";
import axiosConfig from "../../config/axiosConfig";
@ -24,7 +24,7 @@ const AddUser = () => {
<>
<InnovenergyButton
id="add-user-button"
sx={{ my: 1 }}
sx={{ my: 1, }}
onClick={() => setOpen(true)}
>
<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) {
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} />
</Box>
);
@ -51,7 +66,7 @@ const Detail = (props: I_DetailProps) => {
<Box
sx={{ width: 1 / 2, justifyContent: "center", display: "flex", mt: 10 }}
>
<CircularProgress sx={{ m: 2 }} />
<CircularProgress sx={{ m: 2 }} color="secondary" />
</Box>
);
} else if (error) {

View File

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

View File

@ -60,6 +60,20 @@ const UserList = (props: UserListProps) => {
>
<ListItemButton
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} />
</ListItemButton>

View File

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

View File

@ -18,7 +18,7 @@ const Users = () => {
<Grid container spacing={2} marginTop={1}>
<Grid item xs={3}>
{getCurrentUser().hasWriteAccess && <AddUser />}
<SearchSidebar id="users-search-sidebar" listComponent={UserList} />
<SearchSidebar id="users-search-sidebar" listComponent={UserList}/>
</Grid>
<Grid item xs={9}>
<UserTabs />

View File

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

View File

@ -12,14 +12,21 @@ const root = ReactDOM.createRoot(
const theme = createTheme({
palette: {
primary: {
main: "#F59100",
},
text: {
primary: "#000000",
primary: "#2b3e54",
secondary: "#000000",
disabled: "#000000",
},
secondary: {
main: "#90A7C5",
dark: "#CCD6E4",
},
info: {
main: "#2b3e54",
},
warning: {
main: "#90a7c5",
},
},
typography: {
fontFamily: `"Ubuntu", sans-serif`,
@ -28,13 +35,11 @@ const theme = createTheme({
});
root.render(
<React.StrictMode>
<ThemeProvider theme={theme}>
<UserContextProvider>
<App />
</UserContextProvider>
</ThemeProvider>
</React.StrictMode>
);
// 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) => (
<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.25rem",
borderTopRightRadius: "0.25rem",
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: "#fff",
borderColor: "#bdbdbd #bdbdbd #fff",
marginBottom: "-3px",
backgroundColor: "#F2F4F8",
borderColor: "#90A7c5 #90A7c5 #F2F4F8",
marginTop: "1px",
bottom: -1,
},
"&.Mui-focusVisible": {
backgroundColor: "rgba(100, 95, 228, 0.32)",
},
}));
export const AntTabs = styled(Tabs)({
borderBottom: "1px solid #bdbdbd",
export const StyledTabBlue = 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",
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",
"& div.MuiTabs-scroller": {
overflow: "visible!important",
@ -34,7 +119,28 @@ export const AntTabs = styled(Tabs)({
"&.Mui-selected": {
color: "#000000",
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": {
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