Removed AdminLTE, some minor improvements

This commit is contained in:
2024-05-02 14:16:04 +02:00
parent 163ef9fbfe
commit fb353d1bc8
36 changed files with 916 additions and 873 deletions

View File

@@ -11,6 +11,7 @@ import * as React from "react";
import RouteForm from "./route-form";
import {KeyboardArrowLeft, Save} from "@mui/icons-material";
import ButtonBar from "../../elements/button-bar";
import ViewContent from "../../elements/view-content";
const MonoSpaceTextField = styled(TextField)((props) => ({
"& input": {
@@ -113,42 +114,35 @@ export default function RouteEditView(props) {
return <CircularProgress/>
}
return <div className={"content-header"}>
<div className={"container-fluid"}>
<ol className={"breadcrumb"}>
<li className={"breadcrumb-item"}><Link to={"/admin/dashboard"}>Home</Link></li>
<li className="breadcrumb-item active"><Link to={"/admin/routes"}>{L("routes.title")}</Link></li>
<li className="breadcrumb-item active">{isNewRoute ? L("general.new") : L("general.edit")}</li>
</ol>
</div>
<div className={"content"}>
<div className={"container-fluid"}>
<h3>{L(isNewRoute ? "routes.create_route_title" : "routes.edit_route_title")}</h3>
</div>
</div>
<RouteForm route={route} setRoute={setRoute} />
<ButtonBar mt={2}>
<Button startIcon={<KeyboardArrowLeft />}
variant={"outlined"}
onClick={() => navigate("/admin/routes")}>
{L("general.cancel")}
</Button>
<Button startIcon={isSaving ? <CircularProgress size={14} /> : <Save />}
color={"primary"}
variant={"outlined"}
disabled={isSaving}
onClick={onSave}>
{isSaving ? L("general.saving") + "…" : L("general.save")}
</Button>
</ButtonBar>
<Box mt={3}>
<h5>{L("routes.validate_route")}</h5>
<MonoSpaceTextField value={routeTest} onChange={e => setRouteTest(e.target.value)}
variant={"outlined"} size={"small"} fullWidth={true}
placeholder={L("routes.validate_route_placeholder") + "…"} />
<pre>
Match: {JSON.stringify(routeTestResult)}
</pre>
</Box>
</div>
return <ViewContent title={L(isNewRoute ? "routes.create_route_title" : "routes.edit_route_title")}
path={[
<Link key={"home"} to={"/admin/dashboard"}>Home</Link>,
<Link key={"routes"} to={"/admin/routes"}>{L("routes.title")}</Link>,
<span key={"action"}>{isNewRoute ? L("general.new") : L("general.edit")}</span>,
]}>
<RouteForm route={route} setRoute={setRoute} />
<ButtonBar mt={2}>
<Button startIcon={<KeyboardArrowLeft />}
variant={"outlined"}
onClick={() => navigate("/admin/routes")}>
{L("general.cancel")}
</Button>
<Button startIcon={isSaving ? <CircularProgress size={14} /> : <Save />}
color={"primary"}
variant={"outlined"}
disabled={isSaving}
onClick={onSave}>
{isSaving ? L("general.saving") + "…" : L("general.save")}
</Button>
</ButtonBar>
<Box mt={3}>
<h5>{L("routes.validate_route")}</h5>
<MonoSpaceTextField value={routeTest} onChange={e => setRouteTest(e.target.value)}
variant={"outlined"} size={"small"} fullWidth={true}
placeholder={L("routes.validate_route_placeholder") + "…"} />
<pre>
Match: {JSON.stringify(routeTestResult)}
</pre>
</Box>
</ViewContent>
}

View File

@@ -9,12 +9,15 @@ import {
TableHead,
TableRow,
Button,
IconButton, Checkbox
IconButton, Checkbox, Box
} from "@mui/material";
import {useCallback, useContext, useEffect, useState} from "react";
import {LocaleContext} from "shared/locale";
import {Add, Cached, Delete, Edit, Refresh} from "@mui/icons-material";
import Dialog from "shared/elements/dialog";
import ViewContent from "../../elements/view-content";
import ButtonBar from "../../elements/button-bar";
import TableBodyStriped from "shared/elements/table-body-striped";
const RouteTableRow = styled(TableRow)((props) => ({
"& td": {
@@ -22,7 +25,6 @@ const RouteTableRow = styled(TableRow)((props) => ({
}
}));
export default function RouteListView(props) {
// meta
@@ -118,101 +120,89 @@ export default function RouteListView(props) {
const BoolCell = (props) => props.checked ? L("general.yes") : L("general.no")
return <>
<div className={"content-header"}>
<div className={"container-fluid"}>
<div className={"row mb-2"}>
<div className={"col-sm-6"}>
<h1 className={"m-0 text-dark"}>{L("routes.title")}</h1>
</div>
<div className={"col-sm-6"}>
<ol className={"breadcrumb float-sm-right"}>
<li className={"breadcrumb-item"}><Link to={"/admin/dashboard"}>Home</Link></li>
<li className="breadcrumb-item active">{L("routes.title")}</li>
</ol>
</div>
</div>
</div>
</div>
<div className={"row"}>
<div className={"col-6"} />
<div className={"col-6 text-right"}>
<div className={"form-group"}>
<Button variant={"outlined"} color={"primary"} className={"m-1"} size={"small"}
startIcon={<Refresh />} onClick={() => onFetchRoutes(true)}>
{L("general.reload")}
</Button>
<Button variant={"outlined"} className={"m-1"} startIcon={<Add />} size={"small"}
disabled={!props.api.hasPermission("routes/add")}
onClick={() => navigate("/admin/routes/new")} >
{L("general.add")}
</Button>
<Button variant={"outlined"} className={"m-1"} startIcon={<Cached />} size={"small"}
disabled={!props.api.hasPermission("routes/generateCache") || isGeneratingCache}
onClick={onRegenerateCache} >
{isGeneratingCache ? L("routes.regenerating_cache") + "…" : L("routes.regenerate_cache")}
</Button>
</div>
</div>
</div>
<TableContainer component={Paper} style={{overflowX: "initial"}}>
<Table stickyHeader size={"small"} className={"table-striped"}>
<TableHead>
<TableRow>
<TableCell>{L("general.id")}</TableCell>
<TableCell>{L("routes.route")}</TableCell>
<TableCell>{L("routes.type")}</TableCell>
<TableCell>{L("routes.target")}</TableCell>
<TableCell>{L("routes.extra")}</TableCell>
<TableCell align={"center"}>{L("routes.active")}</TableCell>
<TableCell align={"center"}>{L("routes.exact")}</TableCell>
<TableCell align={"center"}>{L("general.controls")}</TableCell>
</TableRow>
</TableHead>
<TableBody>
{Object.entries(routes).map(([id, route]) =>
<RouteTableRow key={"route-" + id}>
<TableCell>{route.id}</TableCell>
<TableCell>{route.pattern}</TableCell>
<TableCell>{route.type}</TableCell>
<TableCell>{route.target}</TableCell>
<TableCell>{route.extra}</TableCell>
<TableCell align={"center"}>
<Checkbox checked={route.active}
size={"small"}
disabled={!api.hasPermission(route.active ? "routes/disable" : "routes/enable")}
onChange={(e) => onToggleRoute(route.id, e.target.checked)} />
</TableCell>
<TableCell align={"center"}><BoolCell checked={route.exact} /></TableCell>
<TableCell align={"center"}>
<IconButton size={"small"} title={L("general.edit")}
disabled={!api.hasPermission("routes/add")}
color={"primary"}
onClick={() => navigate("/admin/routes/" + id)}>
<Edit />
</IconButton>
<IconButton size={"small"} title={L("general.delete")}
disabled={!api.hasPermission("routes/remove")}
color={"secondary"}
onClick={() => setDialogData({
open: true,
title: L("routes.delete_route_title"),
message: L("routes.delete_route_text"),
inputs: [
{ type: "text", name: "pattern", value: route.pattern, disabled: true}
],
options: [L("general.ok"), L("general.cancel")],
onOption: btn => btn === 0 ? onDeleteRoute(route.id) : true
})}>
<Delete />
</IconButton>
</TableCell>
</RouteTableRow>
)}
</TableBody>
</Table>
</TableContainer>
<ViewContent title={L("routes.title")} path={[
<Link key={"home"} to={"/admin/dashboard"}>Home</Link>,
<span key={"routes"}>{L("routes.title")}</span>
]}>
<ButtonBar mb={1}>
<Button variant={"outlined"} color={"primary"} size={"small"}
startIcon={<Refresh />} onClick={() => onFetchRoutes(true)}>
{L("general.reload")}
</Button>
<Button variant={"outlined"} startIcon={<Add />} size={"small"}
disabled={!props.api.hasPermission("routes/add")}
onClick={() => navigate("/admin/routes/new")} >
{L("general.add")}
</Button>
<Button variant={"outlined"} startIcon={<Cached />} size={"small"}
disabled={!props.api.hasPermission("routes/generateCache") || isGeneratingCache}
onClick={onRegenerateCache} >
{isGeneratingCache ? L("routes.regenerating_cache") + "…" : L("routes.regenerate_cache")}
</Button>
</ButtonBar>
<TableContainer component={Paper} sx={{overflowX: "initial"}}>
<Table stickyHeader size={"small"}>
<TableHead>
<TableRow>
<TableCell>{L("general.id")}</TableCell>
<TableCell>{L("routes.route")}</TableCell>
<TableCell>{L("routes.type")}</TableCell>
<TableCell>{L("routes.target")}</TableCell>
<TableCell>{L("routes.extra")}</TableCell>
<TableCell align={"center"}>{L("routes.active")}</TableCell>
<TableCell align={"center"}>{L("routes.exact")}</TableCell>
<TableCell align={"center"}>{L("general.controls")}</TableCell>
</TableRow>
</TableHead>
<TableBodyStriped>
{Object.entries(routes).map(([id, route]) =>
<RouteTableRow key={"route-" + id}>
<TableCell>{route.id}</TableCell>
<TableCell>{route.pattern}</TableCell>
<TableCell>{route.type}</TableCell>
<TableCell>{route.target}</TableCell>
<TableCell>{route.extra}</TableCell>
<TableCell align={"center"}>
<Checkbox checked={route.active}
size={"small"}
disabled={!api.hasPermission(route.active ? "routes/disable" : "routes/enable")}
onChange={(e) => onToggleRoute(route.id, e.target.checked)} />
</TableCell>
<TableCell align={"center"}><BoolCell checked={route.exact} /></TableCell>
<TableCell align={"center"}>
<IconButton size={"small"} title={L("general.edit")}
disabled={!api.hasPermission("routes/add")}
color={"primary"}
onClick={() => navigate("/admin/routes/" + id)}>
<Edit />
</IconButton>
<IconButton size={"small"} title={L("general.delete")}
disabled={!api.hasPermission("routes/remove")}
color={"secondary"}
onClick={() => setDialogData({
open: true,
title: L("routes.delete_route_title"),
message: L("routes.delete_route_text"),
inputs: [
{ type: "text", name: "pattern", value: route.pattern, disabled: true}
],
options: [L("general.ok"), L("general.cancel")],
onOption: btn => btn === 0 ? onDeleteRoute(route.id) : true
})}>
<Delete />
</IconButton>
</TableCell>
</RouteTableRow>
)}
</TableBodyStriped>
</Table>
</TableContainer>
</ViewContent>
<Dialog show={dialogData.open}
onClose={() => { setDialogData({open: false}); dialogData.onClose && dialogData.onClose() }}
onClose={() => {
setDialogData({open: false});
dialogData.onClose && dialogData.onClose()
}}
title={dialogData.title}
message={dialogData.message}
onOption={dialogData.onOption}