Localization for routes and permissions, added compression for language/getEntries

This commit is contained in:
2024-03-29 15:20:45 +01:00
parent 12b8a0b386
commit 0e3d27fa10
15 changed files with 219 additions and 73 deletions

View File

@@ -48,7 +48,7 @@ export default function RouteEditView(props) {
const [isSaving, setSaving] = useState(false);
useEffect(() => {
requestModules(props.api, ["general"], currentLocale).then(data => {
requestModules(props.api, ["general", "routes"], currentLocale).then(data => {
if (!data.success) {
props.showDialog("Error fetching translations: " + data.msg);
}
@@ -122,15 +122,13 @@ export default function RouteEditView(props) {
<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"}>Routes</Link></li>
<li className="breadcrumb-item active">{isNewRoute ? "New" : "Edit"}</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 ? "Create new Route" : "Edit Route")}</h3>
<div className={"col-sm-12 col-lg-6"}>
</div>
<h3>{L(isNewRoute ? "routes.create_route_title" : "routes.edit_route_title")}</h3>
</div>
</div>
<RouteForm route={route} setRoute={setRoute} />
@@ -147,10 +145,10 @@ export default function RouteEditView(props) {
</Button>
</ButtonBar>
<Box mt={3}>
<h5>{L("Validate Route")}</h5>
<h5>{L("routes.validate_route")}</h5>
<MonoSpaceTextField value={routeTest} onChange={e => setRouteTest(e.target.value)}
variant={"outlined"} size={"small"} fullWidth={true}
placeholder={L("Enter a path to test the route…")} />
placeholder={L("routes.validate_route_placeholder") + "…"} />
<pre>
Match: {JSON.stringify(routeTestResult)}
</pre>

View File

@@ -1,4 +1,4 @@
import {Box, Checkbox, FormControl, FormControlLabel, FormGroup, Select, styled, TextField} from "@material-ui/core";
import {Checkbox, FormControl, FormControlLabel, Select, styled, TextField} from "@material-ui/core";
import * as React from "react";
import {useCallback, useContext, useEffect, useRef} from "react";
import {LocaleContext} from "shared/locale";
@@ -38,30 +38,30 @@ export default function RouteForm(props) {
const elements = [
<RouteFormControl key={"form-control-pattern"} fullWidth={true}>
<label htmlFor={"route-pattern"}>{L("Pattern")}</label>
<label htmlFor={"route-pattern"}>{L("routes.pattern")}</label>
<TextField id={"route-pattern"} variant={"outlined"} size={"small"}
value={route.pattern}
onChange={e => setRoute({...route, pattern: e.target.value})} />
</RouteFormControl>,
<FormGroup key={"form-control-exact"}>
<FormControlLabel label={L("Exact")} control={<Checkbox
<RouteFormControl key={"form-control-exact"}>
<FormControlLabel label={L("routes.exact")} control={<Checkbox
checked={route.exact}
onChange={e => setRoute({...route, exact: e.target.checked})} />} />
</FormGroup>,
<FormGroup key={"form-control-active"}>
<FormControlLabel label={L("Active")} control={<Checkbox
</RouteFormControl>,
<RouteFormControl key={"form-control-active"}>
<FormControlLabel label={L("routes.active")} control={<Checkbox
checked={route.active}
onChange={e => setRoute({...route, active: e.target.checked})} />} />
</FormGroup>,
</RouteFormControl>,
<RouteFormControl key={"form-control-type"} fullWidth={true} size={"small"}>
<label htmlFor={"route-type"}>{L("Type")}</label>
<label htmlFor={"route-type"}>{L("routes.type")}</label>
<Select value={route.type} variant={"outlined"} size={"small"} labelId={"route-type"}
onChange={e => onChangeRouteType(e.target.value)} native>
<option value={""}>Select</option>
<option value={"dynamic"}>Dynamic</option>
<option value={"static"}>Static</option>
<option value={"redirect_permanently"}>Redirect Permanently</option>
<option value={"redirect_temporary"}>Redirect Temporary</option>
<option value={""}>{L("general.select")}</option>
<option value={"dynamic"}>{L("routes.type_dynamic")}</option>
<option value={"static"}>{L("routes.type_static")}</option>
<option value={"redirect_permanently"}>{L("routes.type_redirect_permanently")}</option>
<option value={"redirect_temporary"}>{L("routes.type_redirect_temporary")}</option>
</Select>
</RouteFormControl>,
];
@@ -77,7 +77,7 @@ export default function RouteForm(props) {
if (route.type) {
elements.push(
<RouteFormControl key={"form-control-target"} fullWidth={true}>
<label htmlFor={"route-target"}>{L("Target")}</label>
<label htmlFor={"route-target"}>{L("routes.target")}</label>
<TextField id={"route-target"} variant={"outlined"} size={"small"}
value={route.target}
onChange={e => setRoute({...route, target: e.target.value})}/>
@@ -95,23 +95,22 @@ export default function RouteForm(props) {
}
elements.push(
<RouteFormControl key={"form-control-extra"} fullWidth={true}>
<label htmlFor={"route-extra"}>{L("Arguments")}</label>
<label htmlFor={"route-extra"}>{L("routes.arguments")}</label>
<textarea id={"route-extra"}
ref={extraRef}
value={extraArgs ?? route.extra}
onChange={e => setRoute({...route, extra: minifyJson(e.target.value)})}/>
<i>{
extraArgs === null ?
"Invalid JSON-string" :
(type !== "object" ?
"JSON must be Array or Object" : "JSON ok!")
L("routes.json_err") :
(type !== "object" ? L("routes.json_not_obj") : L("routes.json_ok"))
}</i>
</RouteFormControl>
);
} else if (route.type === "static") {
elements.push(
<RouteFormControl key={"form-control-extra"} fullWidth={true}>
<label htmlFor={"route-extra"}>{L("Status Code")}</label>
<label htmlFor={"route-extra"}>{L("routes.status_code")}</label>
<TextField id={"route-extra"} variant={"outlined"} size={"small"}
type={"number"} value={route.extra}
onChange={e => setRoute({...route, extra: parseInt(e.target.value) || 200})} />

View File

@@ -42,7 +42,7 @@ export default function RouteListView(props) {
setFetchRoutes(false);
props.api.fetchRoutes().then(res => {
if (!res.success) {
props.showDialog(res.msg, "Error fetching routes");
props.showDialog(res.msg, L("routes.fetch_routes_error"));
navigate("/admin/dashboard");
} else {
setRoutes(res.routes);
@@ -56,7 +56,7 @@ export default function RouteListView(props) {
}, []);
useEffect(() => {
requestModules(props.api, ["general"], currentLocale).then(data => {
requestModules(props.api, ["general", "routes"], currentLocale).then(data => {
if (!data.success) {
props.showDialog("Error fetching translations: " + data.msg);
}
@@ -67,7 +67,7 @@ export default function RouteListView(props) {
if (active) {
props.api.enableRoute(id).then(data => {
if (!data.success) {
props.showDialog(data.msg, L("Error enabling route"));
props.showDialog(data.msg, L("routes.enable_route_error"));
} else {
setRoutes({...routes, [id]: { ...routes[id], active: true }});
}
@@ -75,7 +75,7 @@ export default function RouteListView(props) {
} else {
props.api.disableRoute(id).then(data => {
if (!data.success) {
props.showDialog(data.msg, L("Error enabling route"));
props.showDialog(data.msg, L("routes.disable_route_error"));
} else {
setRoutes({...routes, [id]: { ...routes[id], active: false }});
}
@@ -86,7 +86,7 @@ export default function RouteListView(props) {
const onDeleteRoute = useCallback(id => {
props.api.deleteRoute(id).then(data => {
if (!data.success) {
props.showDialog(data.msg, L("Error removing route"));
props.showDialog(data.msg, L("routes.remove_route_error"));
} else {
let newRoutes = { ...routes };
delete newRoutes[id];
@@ -100,13 +100,13 @@ export default function RouteListView(props) {
setGeneratingCache(true);
props.api.regenerateRouterCache().then(data => {
if (!data.success) {
props.showDialog(data.msg, L("Error regenerating router cache"));
props.showDialog(data.msg, L("routes.regenerate_router_cache_error"));
setGeneratingCache(false);
} else {
setDialogData({
open: true,
title: L("general.success"),
message: L("Router cache successfully regenerated"),
message: L("routes.regenerate_router_cache_success"),
onClose: () => setGeneratingCache(false)
})
}
@@ -121,12 +121,12 @@ export default function RouteListView(props) {
<div className={"container-fluid"}>
<div className={"row mb-2"}>
<div className={"col-sm-6"}>
<h1 className={"m-0 text-dark"}>Routes</h1>
<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">Routes</li>
<li className="breadcrumb-item active">{L("routes.title")}</li>
</ol>
</div>
</div>
@@ -147,7 +147,7 @@ export default function RouteListView(props) {
<Button variant={"outlined"} className={"m-1"} startIcon={<Cached />}
disabled={!props.api.hasPermission("routes/generateCache") || isGeneratingCache}
onClick={onRegenerateCache} >
{isGeneratingCache ? L("regenerating_cache") + "…" : L("regenerate_cache")}
{isGeneratingCache ? L("routes.regenerating_cache") + "…" : L("routes.regenerate_cache")}
</Button>
</div>
</div>
@@ -157,12 +157,12 @@ export default function RouteListView(props) {
<TableHead>
<TableRow>
<TableCell>{L("general.id")}</TableCell>
<TableCell>{L("Route")}</TableCell>
<TableCell>{L("Type")}</TableCell>
<TableCell>{L("Target")}</TableCell>
<TableCell>{L("Extra")}</TableCell>
<TableCell align={"center"}>{L("Active")}</TableCell>
<TableCell align={"center"}>{L("Exact")}</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>