more improvements (coloring, themes)

This commit is contained in:
Roman 2024-05-02 15:06:00 +02:00
parent 5abbbac2b6
commit c4037684ba
8 changed files with 117 additions and 129 deletions

@ -8,7 +8,7 @@ import {LocaleContext} from "shared/locale";
// views // views
import View404 from "./views/404"; import View404 from "./views/404";
import clsx from "clsx"; import {createTheme, CssBaseline, ThemeProvider} from "@mui/material";
const Overview = lazy(() => import('./views/overview')); const Overview = lazy(() => import('./views/overview'));
const UserListView = lazy(() => import('./views/user/user-list')); const UserListView = lazy(() => import('./views/user/user-list'));
const UserEditView = lazy(() => import('./views/user/user-edit')); const UserEditView = lazy(() => import('./views/user/user-edit'));
@ -58,25 +58,43 @@ export default function AdminDashboard(props) {
hideDialog: hideDialog hideDialog: hideDialog
}; };
const lightTheme = createTheme({
palette: {
mode: 'light',
},
});
const darkTheme = createTheme({
palette: {
mode: 'dark',
background: {
paper: '#343a40',
},
},
});
return <BrowserRouter> return <BrowserRouter>
<Sidebar {...controlObj}> <Sidebar theme={darkTheme} {...controlObj}>
<Suspense fallback={<div>{L("general.loading")}... </div>}> <ThemeProvider theme={lightTheme}>
<Routes> <CssBaseline />
<Route path={"/admin"} element={<Navigate to={"/admin/dashboard"} />}/> <Suspense fallback={<div>{L("general.loading")}... </div>}>
<Route path={"/admin/dashboard"} element={<Overview {...controlObj} />}/> <Routes>
<Route path={"/admin/users"} element={<UserListView {...controlObj} />}/> <Route path={"/admin"} element={<Navigate to={"/admin/dashboard"} />}/>
<Route path={"/admin/user/:userId"} element={<UserEditView {...controlObj} />}/> <Route path={"/admin/dashboard"} element={<Overview {...controlObj} />}/>
<Route path={"/admin/groups"} element={<GroupListView {...controlObj} />}/> <Route path={"/admin/users"} element={<UserListView {...controlObj} />}/>
<Route path={"/admin/group/:groupId"} element={<EditGroupView {...controlObj} />}/> <Route path={"/admin/user/:userId"} element={<UserEditView {...controlObj} />}/>
<Route path={"/admin/logs"} element={<LogView {...controlObj} />}/> <Route path={"/admin/groups"} element={<GroupListView {...controlObj} />}/>
<Route path={"/admin/permissions"} element={<AccessControlList {...controlObj} />}/> <Route path={"/admin/group/:groupId"} element={<EditGroupView {...controlObj} />}/>
<Route path={"/admin/routes"} element={<RouteListView {...controlObj} />}/> <Route path={"/admin/logs"} element={<LogView {...controlObj} />}/>
<Route path={"/admin/routes/:routeId"} element={<RouteEditView {...controlObj} />}/> <Route path={"/admin/permissions"} element={<AccessControlList {...controlObj} />}/>
<Route path={"/admin/settings"} element={<SettingsView {...controlObj} />}/> <Route path={"/admin/routes"} element={<RouteListView {...controlObj} />}/>
<Route path={"/admin/profile"} element={<ProfileView {...controlObj} />}/> <Route path={"/admin/routes/:routeId"} element={<RouteEditView {...controlObj} />}/>
<Route path={"*"} element={<View404 />} /> <Route path={"/admin/settings"} element={<SettingsView {...controlObj} />}/>
</Routes> <Route path={"/admin/profile"} element={<ProfileView {...controlObj} />}/>
</Suspense> <Route path={"*"} element={<View404 />} />
</Routes>
</Suspense>
</ThemeProvider>
<Footer info={info} /> <Footer info={info} />
</Sidebar> </Sidebar>
<Dialog {...dialog}/> <Dialog {...dialog}/>

@ -62,37 +62,6 @@ export default function App() {
onInit(); onInit();
}, []); }, []);
/*
const onTotp2FA = useCallback((code, callback) => {
this.setState({ ...this.state, error: "" });
return this.api.verifyTotp2FA(code).then((res) => {
if (res.success) {
this.api.fetchUser().then(() => {
this.setState({ ...this.state, user: res });
callback(res);
})
} else {
callback(res);
}
});
}, [api]);
onKey2FA(credentialID, clientDataJson, authData, signature, callback) {
this.setState({ ...this.state, error: "" });
return this.api.verifyKey2FA(credentialID, clientDataJson, authData, signature).then((res) => {
if (res.success) {
this.api.fetchUser().then(() => {
this.setState({ ...this.state, user: res });
callback(res);
})
} else {
callback(res);
}
});
}
*/
if (!loaded) { if (!loaded) {
if (error) { if (error) {
return <Alert severity={"error"} title={L("general.error_occurred")}> return <Alert severity={"error"} title={L("general.error_occurred")}>

@ -2,10 +2,10 @@ import React, {useCallback, useContext, useEffect, useState} from 'react';
import {Link, useNavigate} from "react-router-dom"; import {Link, useNavigate} from "react-router-dom";
import {LocaleContext} from "shared/locale"; import {LocaleContext} from "shared/locale";
import { import {
Box, CssBaseline, Divider, Box, Divider,
IconButton, List, ListItem, ListItemButton, ListItemIcon, ListItemText, IconButton, List, ListItem, ListItemButton, ListItemIcon, ListItemText,
Select, Drawer, Select, Drawer,
styled, MenuItem, Menu, useTheme, styled, MenuItem, Menu, ThemeProvider, CssBaseline,
} from "@mui/material"; } from "@mui/material";
import { Dropdown } from '@mui/base/Dropdown'; import { Dropdown } from '@mui/base/Dropdown';
import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import ChevronRightIcon from '@mui/icons-material/ChevronRight';
@ -93,14 +93,13 @@ const StyledDrawer = styled(Drawer, { shouldForwardProp: (prop) => prop !== 'ope
export default function Sidebar(props) { export default function Sidebar(props) {
const api = props.api; const {api, showDialog, theme, children, ...other} = props;
const showDialog = props.showDialog;
const {translate: L, currentLocale, setLanguageByCode} = useContext(LocaleContext); const {translate: L, currentLocale, setLanguageByCode} = useContext(LocaleContext);
const [languages, setLanguages] = useState(null); const [languages, setLanguages] = useState(null);
const [fetchLanguages, setFetchLanguages] = useState(true); const [fetchLanguages, setFetchLanguages] = useState(true);
const [drawerOpen, setDrawerOpen] = useState(window.screen.width >= 1000); const [drawerOpen, setDrawerOpen] = useState(window.screen.width >= 1000);
const [anchorEl, setAnchorEl] = useState(null); const [anchorEl, setAnchorEl] = useState(null);
const theme = useTheme();
const navigate = useNavigate(); const navigate = useNavigate();
const currentPath = useCurrentPath(); const currentPath = useCurrentPath();
@ -197,73 +196,75 @@ export default function Sidebar(props) {
li.push(<NavbarItem key={"logout"} name={"general.logout"} icon={<ArrowBack />} onClick={onLogout}/>); li.push(<NavbarItem key={"logout"} name={"general.logout"} icon={<ArrowBack />} onClick={onLogout}/>);
return <Box sx={{ display: 'flex' }}> return <ThemeProvider theme={theme}>
<CssBaseline /> <CssBaseline />
<StyledDrawer variant={"permanent"} open={drawerOpen}> <Box sx={{ display: 'flex' }} {...other}>
<DrawerHeader> <StyledDrawer variant={"permanent"} open={drawerOpen}>
{drawerOpen && <> <DrawerHeader>
<img src={"/img/icons/logo.png"} alt={"Logo"} /> {drawerOpen && <>
<span>WebBase</span> <img src={"/img/icons/logo.png"} alt={"Logo"} />
</>} <span>WebBase</span>
<IconButton onClick={() => setDrawerOpen(!drawerOpen)}> </>}
{drawerOpen ? <ChevronLeftIcon/> : <ChevronRightIcon/>} <IconButton onClick={() => setDrawerOpen(!drawerOpen)}>
</IconButton> {drawerOpen ? <ChevronLeftIcon/> : <ChevronRightIcon/>}
</DrawerHeader> </IconButton>
<Divider/> </DrawerHeader>
<ListItem sx={{display: 'block'}}> <Divider/>
<Box sx={{opacity: drawerOpen ? 1 : 0}}>{L("account.logged_in_as")}:</Box> <ListItem sx={{display: 'block'}}>
<ProfileLink to={"/admin/profile"}> <Box sx={{opacity: drawerOpen ? 1 : 0}}>{L("account.logged_in_as")}:</Box>
<ProfilePicture user={api.user}/> <ProfileLink to={"/admin/profile"}>
{drawerOpen && <span>{api.user?.name || L("account.not_logged_in")}</span>} <ProfilePicture user={api.user}/>
</ProfileLink> {drawerOpen && <span>{api.user?.name || L("account.not_logged_in")}</span>}
</ListItem> </ProfileLink>
<Divider/> </ListItem>
<List> <Divider/>
{li} <List>
</List> {li}
<Divider/> </List>
<ListItem sx={{display: 'block'}}> <Divider/>
{ drawerOpen ? <ListItem sx={{display: 'block'}}>
<Select native value={currentLocale} size={"small"} fullWidth={true} { drawerOpen ?
onChange={e => onSetLanguage(e.target.value)}> <Select native value={currentLocale} size={"small"} fullWidth={true}
{Object.values(languages || {}).map(language => onChange={e => onSetLanguage(e.target.value)}>
<option key={language.code} value={language.code}> {Object.values(languages || {}).map(language =>
{language.name} <option key={language.code} value={language.code}>
</option>) {language.name}
} </option>)
</Select> }
: <ListItemButton sx={{ </Select>
minHeight: 48, : <ListItemButton sx={{
justifyContent: 'center', minHeight: 48,
px: 2.5, justifyContent: 'center',
}}> px: 2.5,
<Dropdown> }}>
<ListItemIcon onClick={e => setAnchorEl(e.currentTarget)} sx={{ <Dropdown>
minWidth: 0, <ListItemIcon onClick={e => setAnchorEl(e.currentTarget)} sx={{
mr: 'auto', minWidth: 0,
justifyContent: 'center', mr: 'auto',
}}> justifyContent: 'center',
<Translate /> }}>
</ListItemIcon> <Translate />
<Menu open={!!anchorEl} </ListItemIcon>
anchorEl={anchorEl} <Menu open={!!anchorEl}
onClose={() => setAnchorEl(null)} anchorEl={anchorEl}
onClick={() => setAnchorEl(null)} onClose={() => setAnchorEl(null)}
transformOrigin={{ horizontal: 'left', vertical: 'bottom' }} onClick={() => setAnchorEl(null)}
anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}> transformOrigin={{ horizontal: 'left', vertical: 'bottom' }}
{Object.values(languages || {}).map(language => anchorOrigin={{ horizontal: 'left', vertical: 'bottom' }}>
<MenuItem key={language.code} onClick={() => onSetLanguage(language.code)}> {Object.values(languages || {}).map(language =>
{language.name} <MenuItem key={language.code} onClick={() => onSetLanguage(language.code)}>
</MenuItem>) {language.name}
} </MenuItem>)
</Menu> }
</Dropdown> </Menu>
</ListItemButton> </Dropdown>
} </ListItemButton>
</ListItem> }
</StyledDrawer> </ListItem>
<Box component="main" sx={{flexGrow: 1, p: 1}}> </StyledDrawer>
{props.children} <Box component="main" sx={{flexGrow: 1, p: 1}}>
{children}
</Box>
</Box> </Box>
</Box> </ThemeProvider>
} }

@ -231,10 +231,10 @@ export default function AccessControlList(props) {
</Box> </Box>
<ButtonBar mb={2}> <ButtonBar mb={2}>
<Button variant={"outlined"} color={"primary"} size={"small"} <Button variant={"outlined"} color={"primary"} size={"small"}
startIcon={<Refresh/>} onClick={() => onFetchACL(true)}> startIcon={<Refresh />} onClick={() => onFetchACL(true)}>
{L("general.reload")} {L("general.reload")}
</Button> </Button>
<Button variant={"outlined"} startIcon={<Add/>} size={"small"} <Button variant={"outlined"} startIcon={<Add />} size={"small"} color={"success"}
disabled={!props.api.hasGroup(USER_GROUP_ADMIN)} disabled={!props.api.hasGroup(USER_GROUP_ADMIN)}
onClick={() => setDialogData({ onClick={() => setDialogData({
open: true, open: true,

@ -274,7 +274,7 @@ export default function EditGroupView(props) {
]} ]}
buttons={[{ buttons={[{
key: "btn-add-member", key: "btn-add-member",
color: "primary", color: "success",
startIcon: <Add />, startIcon: <Add />,
disabled: !api.hasPermission("groups/addMember"), disabled: !api.hasPermission("groups/addMember"),
children: L("general.add"), children: L("general.add"),

@ -61,7 +61,7 @@ export default function GroupListView(props) {
columns={columnDefinitions} columns={columnDefinitions}
buttons={[{ buttons={[{
key: "btn-create-group", key: "btn-create-group",
color: "primary", color: "success",
startIcon: <Add />, startIcon: <Add />,
onClick: () => navigate("/admin/group/new"), onClick: () => navigate("/admin/group/new"),
disabled: !api.hasPermission("groups/create"), disabled: !api.hasPermission("groups/create"),

@ -129,12 +129,12 @@ export default function RouteListView(props) {
startIcon={<Refresh />} onClick={() => onFetchRoutes(true)}> startIcon={<Refresh />} onClick={() => onFetchRoutes(true)}>
{L("general.reload")} {L("general.reload")}
</Button> </Button>
<Button variant={"outlined"} startIcon={<Add />} size={"small"} <Button variant={"outlined"} color={"success"} startIcon={<Add />} size={"small"}
disabled={!props.api.hasPermission("routes/add")} disabled={!props.api.hasPermission("routes/add")}
onClick={() => navigate("/admin/routes/new")} > onClick={() => navigate("/admin/routes/new")} >
{L("general.add")} {L("general.add")}
</Button> </Button>
<Button variant={"outlined"} startIcon={<Cached />} size={"small"} <Button variant={"outlined"} color={"info"} startIcon={<Cached />} size={"small"}
disabled={!props.api.hasPermission("routes/generateCache") || isGeneratingCache} disabled={!props.api.hasPermission("routes/generateCache") || isGeneratingCache}
onClick={onRegenerateCache} > onClick={onRegenerateCache} >
{isGeneratingCache ? L("routes.regenerating_cache") + "…" : L("routes.regenerate_cache")} {isGeneratingCache ? L("routes.regenerating_cache") + "…" : L("routes.regenerate_cache")}

@ -83,7 +83,7 @@ export default function UserListView(props) {
columns={columnDefinitions} columns={columnDefinitions}
buttons={[{ buttons={[{
key: "btn-create", key: "btn-create",
color: "primary", color: "success",
startIcon: <Add />, startIcon: <Add />,
children: L("general.create_new"), children: L("general.create_new"),
disabled: !api.hasPermission("user/create") && !api.hasPermission("user/invite"), disabled: !api.hasPermission("user/create") && !api.hasPermission("user/invite"),