Localization for routes and permissions, added compression for language/getEntries
This commit is contained in:
		
							parent
							
								
									12b8a0b386
								
							
						
					
					
						commit
						0e3d27fa10
					
				| @ -115,7 +115,8 @@ namespace Core\API\Language { | |||||||
|     public function __construct(Context $context, bool $externalCall = false) { |     public function __construct(Context $context, bool $externalCall = false) { | ||||||
|       parent::__construct($context, $externalCall, [ |       parent::__construct($context, $externalCall, [ | ||||||
|         "code" => new StringType("code", 5, true, NULL), |         "code" => new StringType("code", 5, true, NULL), | ||||||
|         "modules" => new ArrayType("modules", Parameter::TYPE_STRING, true, false) |         "modules" => new ArrayType("modules", Parameter::TYPE_STRING, true, false), | ||||||
|  |         "compression" => new StringType("compression", -1, true, NULL, ["gzip", "zlib"]) | ||||||
|       ]); |       ]); | ||||||
|       $this->loginRequired = false; |       $this->loginRequired = false; | ||||||
|       $this->csrfTokenRequired = false; |       $this->csrfTokenRequired = false; | ||||||
| @ -156,7 +157,23 @@ namespace Core\API\Language { | |||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|       $this->result["code"] = $code; |       $this->result["code"] = $code; | ||||||
|  | 
 | ||||||
|  |       $compression = $this->getParam("compression"); | ||||||
|  |       if ($compression) { | ||||||
|  |         switch ($compression) { | ||||||
|  |           case "gzip": | ||||||
|  |             $this->result["compressed"] = base64_encode(gzencode(json_encode($entries), 9)); | ||||||
|  |             break; | ||||||
|  |           case "zlib": | ||||||
|  |             $this->result["compressed"] = base64_encode(gzcompress(json_encode($entries), 9, ZLIB_ENCODING_DEFLATE)); | ||||||
|  |             break; | ||||||
|  |           default: | ||||||
|  |             http_response_code(400); | ||||||
|  |             return $this->createError("Invalid compression method: $compression"); | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|         $this->result["entries"] = $entries; |         $this->result["entries"] = $entries; | ||||||
|  |       } | ||||||
|       return true; |       return true; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -19,6 +19,7 @@ return [ | |||||||
|   "cancel" => "Abbrechen", |   "cancel" => "Abbrechen", | ||||||
|   "confirm" => "Bestätigen", |   "confirm" => "Bestätigen", | ||||||
|   "add" => "Hinzufügen", |   "add" => "Hinzufügen", | ||||||
|  |   "select" => "Auswählen", | ||||||
|   "ok" => "OK", |   "ok" => "OK", | ||||||
|   "id" => "ID", |   "id" => "ID", | ||||||
|   "user" => "Benutzer", |   "user" => "Benutzer", | ||||||
|  | |||||||
							
								
								
									
										20
									
								
								Core/Localization/de_DE/permissions.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										20
									
								
								Core/Localization/de_DE/permissions.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | return [ | ||||||
|  |   "title" => "Berechtigungen", | ||||||
|  |   "title_short" => "ACL", | ||||||
|  |   "query" => "Suchanfrage", | ||||||
|  |   "add_permission" => "Berechtigung hinzufügen", | ||||||
|  |   "permission" => "Berechtigung", | ||||||
|  |   "everyone" => "Alle", | ||||||
|  |   "method" => "Methode", | ||||||
|  |   "description" => "Beschreibung", | ||||||
|  | 
 | ||||||
|  |   # dialog
 | ||||||
|  |   "delete_permission_confirm" => "Diese Berechtigung wirklich löschen?", | ||||||
|  |   "edit_permission" => "Berechtigung bearbeiten", | ||||||
|  |   "update_permission_error" => "Fehler beim Aktualisieren der Berechtigung", | ||||||
|  |   "delete_permission_error" => "Fehler beim Löschen der Berechtigung", | ||||||
|  |   "fetch_permission_error" => "Fehler beim Holen der Berechtigungen", | ||||||
|  |   "fetch_group_error" => "Fehler beim Holen der Gruppen", | ||||||
|  | ]; | ||||||
							
								
								
									
										41
									
								
								Core/Localization/de_DE/routes.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										41
									
								
								Core/Localization/de_DE/routes.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | return [ | ||||||
|  |   "title" => "Routen", | ||||||
|  |   "regenerating_cache" => "Lade Cache neu", | ||||||
|  |   "regenerate_cache" => "Cache neuladen", | ||||||
|  | 
 | ||||||
|  |   # table
 | ||||||
|  |   "route" => "Route", | ||||||
|  |   "type" => "Typ", | ||||||
|  |   "target" => "Ziel", | ||||||
|  |   "extra" => "Extra", | ||||||
|  |   "active" => "Aktiv", | ||||||
|  |   "exact" => "Exakt", | ||||||
|  | 
 | ||||||
|  |   # form
 | ||||||
|  |   "edit_route_title" => "Route bearbeiten", | ||||||
|  |   "create_route_title" => "Neue Route erstellen", | ||||||
|  |   "pattern" => "Pattern", | ||||||
|  |   "arguments" => "Argumente", | ||||||
|  |   "status_code" => "Status Code", | ||||||
|  |   "json_ok" => "JSON ok!", | ||||||
|  |   "json_err" => "Ungültiger JSON-string!", | ||||||
|  |   "json_not_object" => "Das JSON muss ein Array oder Objekt sein!", | ||||||
|  |   "validate_route" => "Route validieren", | ||||||
|  |   "validate_route_placeholder" => "Einen Pfad eingeben um die Route zu testen", | ||||||
|  | 
 | ||||||
|  |   # data
 | ||||||
|  |   "type_dynamic" => "Dynamisch", | ||||||
|  |   "type_static" => "Statisch", | ||||||
|  |   "type_redirect_permanently" => "Dauerhaft weiterleiten", | ||||||
|  |   "type_redirect_temporary" => "Temporär weiterleiten", | ||||||
|  | 
 | ||||||
|  |   # dialogs
 | ||||||
|  |   "fetch_routes_error" => "Fehler beim Holen der Routen", | ||||||
|  |   "enable_route_error" => "Fehler beim Aktivieren der Route", | ||||||
|  |   "disable_route_error" => "Fehler beim Deaktivieren der Route", | ||||||
|  |   "remove_route_error" => "Fehler beim Entfernen der Route", | ||||||
|  |   "regenerate_router_cache_error" => "Fehler beim Erzeugen des Router Caches", | ||||||
|  |   "regenerate_router_cache_success" => "Router Cache erfolgreich erzeugt", | ||||||
|  | ]; | ||||||
| @ -30,6 +30,7 @@ return [ | |||||||
|   "cancel" => "Cancel", |   "cancel" => "Cancel", | ||||||
|   "confirm" => "Confirm", |   "confirm" => "Confirm", | ||||||
|   "add" => "Add", |   "add" => "Add", | ||||||
|  |   "select" => "Select", | ||||||
|   "close" => "Close", |   "close" => "Close", | ||||||
|   "ok" => "OK", |   "ok" => "OK", | ||||||
|   "id" => "ID", |   "id" => "ID", | ||||||
|  | |||||||
							
								
								
									
										20
									
								
								Core/Localization/en_US/permissions.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										20
									
								
								Core/Localization/en_US/permissions.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | return [ | ||||||
|  |   "title" => "Permissions", | ||||||
|  |   "title_short" => "ACL", | ||||||
|  |   "query" => "Search query", | ||||||
|  |   "add_permission" => "Add permission", | ||||||
|  |   "permission" => "Permission", | ||||||
|  |   "everyone" => "Everyone", | ||||||
|  |   "method" => "Method", | ||||||
|  |   "description" => "Description", | ||||||
|  | 
 | ||||||
|  |   # dialog
 | ||||||
|  |   "delete_permission_confirm" => "Do you really want to delete this permission?", | ||||||
|  |   "edit_permission" => "Edit Permission", | ||||||
|  |   "update_permission_error" => "Error updating permission", | ||||||
|  |   "delete_permission_error" => "Error deleting permission", | ||||||
|  |   "fetch_permission_error" => "Error fetching permissions", | ||||||
|  |   "fetch_group_error" => "Error fetching groups", | ||||||
|  | ]; | ||||||
							
								
								
									
										41
									
								
								Core/Localization/en_US/routes.php
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										41
									
								
								Core/Localization/en_US/routes.php
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,41 @@ | |||||||
|  | <?php | ||||||
|  | 
 | ||||||
|  | return [ | ||||||
|  |   "title" => "Routes", | ||||||
|  |   "regenerating_cache" => "Regenerating Cache", | ||||||
|  |   "regenerate_cache" => "Regenerate Cache", | ||||||
|  | 
 | ||||||
|  |   # table
 | ||||||
|  |   "route" => "Route", | ||||||
|  |   "type" => "Type", | ||||||
|  |   "target" => "Target", | ||||||
|  |   "extra" => "Extra", | ||||||
|  |   "active" => "Active", | ||||||
|  |   "exact" => "Exact", | ||||||
|  | 
 | ||||||
|  |   # form
 | ||||||
|  |   "edit_route_title" => "Edit Route", | ||||||
|  |   "create_route_title" => "Create new Route", | ||||||
|  |   "pattern" => "Pattern", | ||||||
|  |   "arguments" => "Arguments", | ||||||
|  |   "status_code" => "Status Code", | ||||||
|  |   "json_ok" => "JSON ok!", | ||||||
|  |   "json_err" => "Invalid JSON-string!", | ||||||
|  |   "json_not_object" => "JSON must be Array or Object!", | ||||||
|  |   "validate_route" => "Validate Route", | ||||||
|  |   "validate_route_placeholder" => "Enter a path to test the route", | ||||||
|  | 
 | ||||||
|  |   # data
 | ||||||
|  |   "type_dynamic" => "Dynamic", | ||||||
|  |   "type_static" => "Static", | ||||||
|  |   "type_redirect_permanently" => "Redirect permanently", | ||||||
|  |   "type_redirect_temporary" => "Redirect temporary", | ||||||
|  | 
 | ||||||
|  |   # dialogs
 | ||||||
|  |   "fetch_routes_error" => "Error fetching routes", | ||||||
|  |   "enable_route_error" => "Error enabling route", | ||||||
|  |   "disable_route_error" => "Error disabling route", | ||||||
|  |   "remove_route_error" => "Error removing route", | ||||||
|  |   "regenerate_router_cache_error" => "Error regenerating router cache", | ||||||
|  |   "regenerate_router_cache_success" => "Router cache successfully regenerated", | ||||||
|  | ]; | ||||||
| @ -45,13 +45,13 @@ export default function AccessControlList(props) { | |||||||
|             setFetchACL(false); |             setFetchACL(false); | ||||||
|             props.api.fetchGroups().then(res => { |             props.api.fetchGroups().then(res => { | ||||||
|                if (!res.success) { |                if (!res.success) { | ||||||
|                    props.showDialog(res.msg, "Error fetching groups"); |                    props.showDialog(res.msg, L("permissions.fetch_group_error")); | ||||||
|                    navigate("/admin/dashboard"); |                    navigate("/admin/dashboard"); | ||||||
|                } else { |                } else { | ||||||
|                    setGroups(res.groups); |                    setGroups(res.groups); | ||||||
|                    props.api.fetchPermissions().then(res => { |                    props.api.fetchPermissions().then(res => { | ||||||
|                        if (!res.success) { |                        if (!res.success) { | ||||||
|                            props.showDialog(res.msg, "Error fetching permissions"); |                            props.showDialog(res.msg, L("permissions.fetch_permission_error")); | ||||||
|                            navigate("/admin/dashboard"); |                            navigate("/admin/dashboard"); | ||||||
|                        } else { |                        } else { | ||||||
|                            setACL(res.permissions); |                            setACL(res.permissions); | ||||||
| @ -67,7 +67,7 @@ export default function AccessControlList(props) { | |||||||
|     }, []); |     }, []); | ||||||
| 
 | 
 | ||||||
|     useEffect(() => { |     useEffect(() => { | ||||||
|         requestModules(props.api, ["general"], currentLocale).then(data => { |         requestModules(props.api, ["general", "permissions"], currentLocale).then(data => { | ||||||
|             if (!data.success) { |             if (!data.success) { | ||||||
|                 props.showDialog("Error fetching translations: " + data.msg); |                 props.showDialog("Error fetching translations: " + data.msg); | ||||||
|             } |             } | ||||||
| @ -103,7 +103,7 @@ export default function AccessControlList(props) { | |||||||
|                    setACL(newACL); |                    setACL(newACL); | ||||||
|                    props.api.fetchUser(); |                    props.api.fetchUser(); | ||||||
|                } else { |                } else { | ||||||
|                    props.showDialog("Error updating permission: " + data.msg); |                    props.showDialog(data.msg, L("permissions.update_permission_error")); | ||||||
|                } |                } | ||||||
|             }); |             }); | ||||||
|         } |         } | ||||||
| @ -116,7 +116,7 @@ export default function AccessControlList(props) { | |||||||
|                 setACL(newACL); |                 setACL(newACL); | ||||||
|                 props.api.fetchUser(); |                 props.api.fetchUser(); | ||||||
|             } else { |             } else { | ||||||
|                 props.showDialog("Error deleting permission: " + data.msg); |                 props.showDialog(data.msg, L("permissions.delete_permission_error")); | ||||||
|             } |             } | ||||||
|         }) |         }) | ||||||
|     }, [acl]); |     }, [acl]); | ||||||
| @ -130,7 +130,7 @@ export default function AccessControlList(props) { | |||||||
|                 setACL(newACL); |                 setACL(newACL); | ||||||
|                 props.api.fetchUser(); |                 props.api.fetchUser(); | ||||||
|             } else { |             } else { | ||||||
|                 props.showDialog("Error updating permission: " + data.msg); |                 props.showDialog(data.msg, L("permissions.update_permission_error")); | ||||||
|             } |             } | ||||||
|         }) |         }) | ||||||
|     }, [acl]); |     }, [acl]); | ||||||
| @ -162,11 +162,11 @@ export default function AccessControlList(props) { | |||||||
|                                             disabled={isRestricted(permission.method)} |                                             disabled={isRestricted(permission.method)} | ||||||
|                                             onClick={() => setDialogData({ |                                             onClick={() => setDialogData({ | ||||||
|                                                 open: true, |                                                 open: true, | ||||||
|                                                 title: L("Edit permission"), |                                                 title: L("permissions.edit_permission"), | ||||||
|                                                 inputs: [ |                                                 inputs: [ | ||||||
|                                                     { type: "label", value: L("general.method") + ":" }, |                                                     { type: "label", value: L("permissions.method") + ":" }, | ||||||
|                                                     { type: "text", name: "method", value: permission.method, disabled: true }, |                                                     { type: "text", name: "method", value: permission.method, disabled: true }, | ||||||
|                                                     { type: "label", value: L("general.description") + ":" }, |                                                     { type: "label", value: L("permissions.description") + ":" }, | ||||||
|                                                     { type: "text", name: "description", value: permission.description, maxLength: 128 } |                                                     { type: "text", name: "description", value: permission.description, maxLength: 128 } | ||||||
|                                                 ], |                                                 ], | ||||||
|                                                 onOption: (option, inputData) => option === 0 && onUpdatePermission(inputData, permission.groups) |                                                 onOption: (option, inputData) => option === 0 && onUpdatePermission(inputData, permission.groups) | ||||||
| @ -177,8 +177,8 @@ export default function AccessControlList(props) { | |||||||
|                                             disabled={isRestricted(permission.method)} |                                             disabled={isRestricted(permission.method)} | ||||||
|                                             onClick={() => setDialogData({ |                                             onClick={() => setDialogData({ | ||||||
|                                                 open: true, |                                                 open: true, | ||||||
|                                                 title: L("Do you really want to delete this permission?"), |                                                 title: L("permissions.delete_permission_confirm"), | ||||||
|                                                 message: "Method: " + permission.method, |                                                 message: L("permissions.method") + ": " + permission.method, | ||||||
|                                                 onOption: (option) => option === 0 && onDeletePermission(permission.method) |                                                 onOption: (option) => option === 0 && onDeletePermission(permission.method) | ||||||
|                                             })} > |                                             })} > | ||||||
|                                     <Delete /> |                                     <Delete /> | ||||||
| @ -212,12 +212,12 @@ export default function AccessControlList(props) { | |||||||
|             <div className={"container-fluid"}> |             <div className={"container-fluid"}> | ||||||
|                 <div className={"row mb-2"}> |                 <div className={"row mb-2"}> | ||||||
|                     <div className={"col-sm-6"}> |                     <div className={"col-sm-6"}> | ||||||
|                         <h1 className={"m-0 text-dark"}>Access Control List</h1> |                         <h1 className={"m-0 text-dark"}>{L("permissions.title")}</h1> | ||||||
|                     </div> |                     </div> | ||||||
|                     <div className={"col-sm-6"}> |                     <div className={"col-sm-6"}> | ||||||
|                         <ol className={"breadcrumb float-sm-right"}> |                         <ol className={"breadcrumb float-sm-right"}> | ||||||
|                             <li className={"breadcrumb-item"}><Link to={"/admin/dashboard"}>Home</Link></li> |                             <li className={"breadcrumb-item"}><Link to={"/admin/dashboard"}>Home</Link></li> | ||||||
|                             <li className="breadcrumb-item active">ACL</li> |                             <li className="breadcrumb-item active">{L("permissions.title_short")}</li> | ||||||
|                         </ol> |                         </ol> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
| @ -226,10 +226,10 @@ export default function AccessControlList(props) { | |||||||
|         <div className={"row"}> |         <div className={"row"}> | ||||||
|             <div className={"col-6"}> |             <div className={"col-6"}> | ||||||
|                 <div className={"form-group"}> |                 <div className={"form-group"}> | ||||||
|                     <label>{L("query")}</label> |                     <label>{L("permissions.query")}</label> | ||||||
|                     <TextField |                     <TextField | ||||||
|                         className={"form-control"} |                         className={"form-control"} | ||||||
|                         placeholder={L("search_query") + "…"} |                         placeholder={L("permissions.query") + "…"} | ||||||
|                         value={query} |                         value={query} | ||||||
|                         onChange={e => setQuery(e.target.value)} |                         onChange={e => setQuery(e.target.value)} | ||||||
|                         variant={"outlined"} |                         variant={"outlined"} | ||||||
| @ -245,7 +245,7 @@ export default function AccessControlList(props) { | |||||||
|                     <Button variant={"outlined"} className={"m-1"} startIcon={<Add />} disabled={!props.api.hasGroup(USER_GROUP_ADMIN)} |                     <Button variant={"outlined"} className={"m-1"} startIcon={<Add />} disabled={!props.api.hasGroup(USER_GROUP_ADMIN)} | ||||||
|                             onClick={() => setDialogData({ |                             onClick={() => setDialogData({ | ||||||
|                                 open: true, |                                 open: true, | ||||||
|                                 title: L("Add permission"), |                                 title: L("permissions.add_permission"), | ||||||
|                                 inputs: [ |                                 inputs: [ | ||||||
|                                     { type: "label", value: L("general.method") + ":" }, |                                     { type: "label", value: L("general.method") + ":" }, | ||||||
|                                     { type: "text", name: "method", value: "", placeholder: L("general.method") }, |                                     { type: "text", name: "method", value: "", placeholder: L("general.method") }, | ||||||
| @ -263,8 +263,8 @@ export default function AccessControlList(props) { | |||||||
|             <Table stickyHeader size={"small"} className={"table-striped"}> |             <Table stickyHeader size={"small"} className={"table-striped"}> | ||||||
|                 <TableHead> |                 <TableHead> | ||||||
|                     <TableRow> |                     <TableRow> | ||||||
|                         <TableCell>{L("permission")}</TableCell> |                         <TableCell>{L("permissions.permission")}</TableCell> | ||||||
|                         <BorderedColumn align={"center"}><i>{L("everyone")}</i></BorderedColumn> |                         <BorderedColumn align={"center"}><i>{L("permissions.everyone")}</i></BorderedColumn> | ||||||
|                         { groups.map(group => <TableCell key={"group-" + group.id} align={"center"}> |                         { groups.map(group => <TableCell key={"group-" + group.id} align={"center"}> | ||||||
|                             {group.name} |                             {group.name} | ||||||
|                         </TableCell>) } |                         </TableCell>) } | ||||||
|  | |||||||
| @ -48,7 +48,7 @@ export default function RouteEditView(props) { | |||||||
|     const [isSaving, setSaving] = useState(false); |     const [isSaving, setSaving] = useState(false); | ||||||
| 
 | 
 | ||||||
|     useEffect(() => { |     useEffect(() => { | ||||||
|         requestModules(props.api, ["general"], currentLocale).then(data => { |         requestModules(props.api, ["general", "routes"], currentLocale).then(data => { | ||||||
|             if (!data.success) { |             if (!data.success) { | ||||||
|                 props.showDialog("Error fetching translations: " + data.msg); |                 props.showDialog("Error fetching translations: " + data.msg); | ||||||
|             } |             } | ||||||
| @ -122,15 +122,13 @@ export default function RouteEditView(props) { | |||||||
|         <div className={"container-fluid"}> |         <div className={"container-fluid"}> | ||||||
|             <ol className={"breadcrumb"}> |             <ol className={"breadcrumb"}> | ||||||
|                 <li className={"breadcrumb-item"}><Link to={"/admin/dashboard"}>Home</Link></li> |                 <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"><Link to={"/admin/routes"}>{L("routes.title")}</Link></li> | ||||||
|                 <li className="breadcrumb-item active">{isNewRoute ? "New" : "Edit"}</li> |                 <li className="breadcrumb-item active">{isNewRoute ? L("general.new") : L("general.edit")}</li> | ||||||
|             </ol> |             </ol> | ||||||
|         </div> |         </div> | ||||||
|         <div className={"content"}> |         <div className={"content"}> | ||||||
|             <div className={"container-fluid"}> |             <div className={"container-fluid"}> | ||||||
|                 <h3>{L(isNewRoute ? "Create new Route" : "Edit Route")}</h3> |                 <h3>{L(isNewRoute ? "routes.create_route_title" : "routes.edit_route_title")}</h3> | ||||||
|                 <div className={"col-sm-12 col-lg-6"}> |  | ||||||
|                 </div> |  | ||||||
|             </div> |             </div> | ||||||
|         </div> |         </div> | ||||||
|         <RouteForm route={route} setRoute={setRoute} /> |         <RouteForm route={route} setRoute={setRoute} /> | ||||||
| @ -147,10 +145,10 @@ export default function RouteEditView(props) { | |||||||
|             </Button> |             </Button> | ||||||
|         </ButtonBar> |         </ButtonBar> | ||||||
|         <Box mt={3}> |         <Box mt={3}> | ||||||
|             <h5>{L("Validate Route")}</h5> |             <h5>{L("routes.validate_route")}</h5> | ||||||
|             <MonoSpaceTextField value={routeTest} onChange={e => setRouteTest(e.target.value)} |             <MonoSpaceTextField value={routeTest} onChange={e => setRouteTest(e.target.value)} | ||||||
|                 variant={"outlined"} size={"small"} fullWidth={true} |                 variant={"outlined"} size={"small"} fullWidth={true} | ||||||
|                 placeholder={L("Enter a path to test the route…")} /> |                 placeholder={L("routes.validate_route_placeholder") + "…"} /> | ||||||
|             <pre> |             <pre> | ||||||
|                 Match: {JSON.stringify(routeTestResult)} |                 Match: {JSON.stringify(routeTestResult)} | ||||||
|             </pre> |             </pre> | ||||||
|  | |||||||
| @ -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 * as React from "react"; | ||||||
| import {useCallback, useContext, useEffect, useRef} from "react"; | import {useCallback, useContext, useEffect, useRef} from "react"; | ||||||
| import {LocaleContext} from "shared/locale"; | import {LocaleContext} from "shared/locale"; | ||||||
| @ -38,30 +38,30 @@ export default function RouteForm(props) { | |||||||
| 
 | 
 | ||||||
|     const elements = [ |     const elements = [ | ||||||
|         <RouteFormControl key={"form-control-pattern"} fullWidth={true}> |         <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"} |             <TextField id={"route-pattern"} variant={"outlined"} size={"small"} | ||||||
|                        value={route.pattern} |                        value={route.pattern} | ||||||
|                        onChange={e => setRoute({...route, pattern: e.target.value})} /> |                        onChange={e => setRoute({...route, pattern: e.target.value})} /> | ||||||
|         </RouteFormControl>, |         </RouteFormControl>, | ||||||
|         <FormGroup key={"form-control-exact"}> |         <RouteFormControl key={"form-control-exact"}> | ||||||
|             <FormControlLabel label={L("Exact")} control={<Checkbox |             <FormControlLabel label={L("routes.exact")} control={<Checkbox | ||||||
|                 checked={route.exact} |                 checked={route.exact} | ||||||
|                 onChange={e => setRoute({...route, exact: e.target.checked})} />} /> |                 onChange={e => setRoute({...route, exact: e.target.checked})} />} /> | ||||||
|         </FormGroup>, |         </RouteFormControl>, | ||||||
|         <FormGroup key={"form-control-active"}> |         <RouteFormControl key={"form-control-active"}> | ||||||
|             <FormControlLabel label={L("Active")} control={<Checkbox |             <FormControlLabel label={L("routes.active")} control={<Checkbox | ||||||
|                 checked={route.active} |                 checked={route.active} | ||||||
|                 onChange={e => setRoute({...route, active: e.target.checked})} />} /> |                 onChange={e => setRoute({...route, active: e.target.checked})} />} /> | ||||||
|         </FormGroup>, |         </RouteFormControl>, | ||||||
|         <RouteFormControl key={"form-control-type"} fullWidth={true} size={"small"}> |         <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"} |             <Select value={route.type} variant={"outlined"} size={"small"} labelId={"route-type"} | ||||||
|                     onChange={e => onChangeRouteType(e.target.value)} native> |                     onChange={e => onChangeRouteType(e.target.value)} native> | ||||||
|                 <option value={""}>Select…</option> |                 <option value={""}>{L("general.select")}…</option> | ||||||
|                 <option value={"dynamic"}>Dynamic</option> |                 <option value={"dynamic"}>{L("routes.type_dynamic")}</option> | ||||||
|                 <option value={"static"}>Static</option> |                 <option value={"static"}>{L("routes.type_static")}</option> | ||||||
|                 <option value={"redirect_permanently"}>Redirect Permanently</option> |                 <option value={"redirect_permanently"}>{L("routes.type_redirect_permanently")}</option> | ||||||
|                 <option value={"redirect_temporary"}>Redirect Temporary</option> |                 <option value={"redirect_temporary"}>{L("routes.type_redirect_temporary")}</option> | ||||||
|             </Select> |             </Select> | ||||||
|         </RouteFormControl>, |         </RouteFormControl>, | ||||||
|     ]; |     ]; | ||||||
| @ -77,7 +77,7 @@ export default function RouteForm(props) { | |||||||
|     if (route.type) { |     if (route.type) { | ||||||
|         elements.push( |         elements.push( | ||||||
|             <RouteFormControl key={"form-control-target"} fullWidth={true}> |             <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"} |                 <TextField id={"route-target"} variant={"outlined"} size={"small"} | ||||||
|                            value={route.target} |                            value={route.target} | ||||||
|                            onChange={e => setRoute({...route, target: e.target.value})}/> |                            onChange={e => setRoute({...route, target: e.target.value})}/> | ||||||
| @ -95,23 +95,22 @@ export default function RouteForm(props) { | |||||||
|             } |             } | ||||||
|             elements.push( |             elements.push( | ||||||
|                 <RouteFormControl key={"form-control-extra"} fullWidth={true}> |                 <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"} |                     <textarea id={"route-extra"} | ||||||
|                               ref={extraRef} |                               ref={extraRef} | ||||||
|                               value={extraArgs ?? route.extra} |                               value={extraArgs ?? route.extra} | ||||||
|                               onChange={e => setRoute({...route, extra: minifyJson(e.target.value)})}/> |                               onChange={e => setRoute({...route, extra: minifyJson(e.target.value)})}/> | ||||||
|                     <i>{ |                     <i>{ | ||||||
|                         extraArgs === null ? |                         extraArgs === null ? | ||||||
|                             "Invalid JSON-string" : |                             L("routes.json_err") : | ||||||
|                             (type !== "object" ? |                                 (type !== "object" ? L("routes.json_not_obj") : L("routes.json_ok")) | ||||||
|                                 "JSON must be Array or Object" : "JSON ok!") |  | ||||||
|                     }</i> |                     }</i> | ||||||
|                 </RouteFormControl> |                 </RouteFormControl> | ||||||
|             ); |             ); | ||||||
|         } else if (route.type === "static") { |         } else if (route.type === "static") { | ||||||
|             elements.push( |             elements.push( | ||||||
|                 <RouteFormControl key={"form-control-extra"} fullWidth={true}> |                 <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"} |                     <TextField id={"route-extra"} variant={"outlined"} size={"small"} | ||||||
|                                type={"number"} value={route.extra} |                                type={"number"} value={route.extra} | ||||||
|                                onChange={e => setRoute({...route, extra: parseInt(e.target.value) || 200})} /> |                                onChange={e => setRoute({...route, extra: parseInt(e.target.value) || 200})} /> | ||||||
|  | |||||||
| @ -42,7 +42,7 @@ export default function RouteListView(props) { | |||||||
|             setFetchRoutes(false); |             setFetchRoutes(false); | ||||||
|             props.api.fetchRoutes().then(res => { |             props.api.fetchRoutes().then(res => { | ||||||
|                 if (!res.success) { |                 if (!res.success) { | ||||||
|                     props.showDialog(res.msg, "Error fetching routes"); |                     props.showDialog(res.msg, L("routes.fetch_routes_error")); | ||||||
|                     navigate("/admin/dashboard"); |                     navigate("/admin/dashboard"); | ||||||
|                 } else { |                 } else { | ||||||
|                     setRoutes(res.routes); |                     setRoutes(res.routes); | ||||||
| @ -56,7 +56,7 @@ export default function RouteListView(props) { | |||||||
|     }, []); |     }, []); | ||||||
| 
 | 
 | ||||||
|     useEffect(() => { |     useEffect(() => { | ||||||
|         requestModules(props.api, ["general"], currentLocale).then(data => { |         requestModules(props.api, ["general", "routes"], currentLocale).then(data => { | ||||||
|             if (!data.success) { |             if (!data.success) { | ||||||
|                 props.showDialog("Error fetching translations: " + data.msg); |                 props.showDialog("Error fetching translations: " + data.msg); | ||||||
|             } |             } | ||||||
| @ -67,7 +67,7 @@ export default function RouteListView(props) { | |||||||
|         if (active) { |         if (active) { | ||||||
|             props.api.enableRoute(id).then(data => { |             props.api.enableRoute(id).then(data => { | ||||||
|                 if (!data.success) { |                 if (!data.success) { | ||||||
|                     props.showDialog(data.msg, L("Error enabling route")); |                     props.showDialog(data.msg, L("routes.enable_route_error")); | ||||||
|                 } else { |                 } else { | ||||||
|                     setRoutes({...routes, [id]: { ...routes[id], active: true }}); |                     setRoutes({...routes, [id]: { ...routes[id], active: true }}); | ||||||
|                 } |                 } | ||||||
| @ -75,7 +75,7 @@ export default function RouteListView(props) { | |||||||
|         } else { |         } else { | ||||||
|             props.api.disableRoute(id).then(data => { |             props.api.disableRoute(id).then(data => { | ||||||
|                 if (!data.success) { |                 if (!data.success) { | ||||||
|                     props.showDialog(data.msg, L("Error enabling route")); |                     props.showDialog(data.msg, L("routes.disable_route_error")); | ||||||
|                 } else { |                 } else { | ||||||
|                     setRoutes({...routes, [id]: { ...routes[id], active: false }}); |                     setRoutes({...routes, [id]: { ...routes[id], active: false }}); | ||||||
|                 } |                 } | ||||||
| @ -86,7 +86,7 @@ export default function RouteListView(props) { | |||||||
|     const onDeleteRoute = useCallback(id => { |     const onDeleteRoute = useCallback(id => { | ||||||
|         props.api.deleteRoute(id).then(data => { |         props.api.deleteRoute(id).then(data => { | ||||||
|             if (!data.success) { |             if (!data.success) { | ||||||
|                 props.showDialog(data.msg, L("Error removing route")); |                 props.showDialog(data.msg, L("routes.remove_route_error")); | ||||||
|             } else { |             } else { | ||||||
|                 let newRoutes = { ...routes }; |                 let newRoutes = { ...routes }; | ||||||
|                 delete newRoutes[id]; |                 delete newRoutes[id]; | ||||||
| @ -100,13 +100,13 @@ export default function RouteListView(props) { | |||||||
|             setGeneratingCache(true); |             setGeneratingCache(true); | ||||||
|             props.api.regenerateRouterCache().then(data => { |             props.api.regenerateRouterCache().then(data => { | ||||||
|                 if (!data.success) { |                 if (!data.success) { | ||||||
|                     props.showDialog(data.msg, L("Error regenerating router cache")); |                     props.showDialog(data.msg, L("routes.regenerate_router_cache_error")); | ||||||
|                     setGeneratingCache(false); |                     setGeneratingCache(false); | ||||||
|                 } else { |                 } else { | ||||||
|                     setDialogData({ |                     setDialogData({ | ||||||
|                         open: true, |                         open: true, | ||||||
|                         title: L("general.success"), |                         title: L("general.success"), | ||||||
|                         message: L("Router cache successfully regenerated"), |                         message: L("routes.regenerate_router_cache_success"), | ||||||
|                         onClose: () => setGeneratingCache(false) |                         onClose: () => setGeneratingCache(false) | ||||||
|                     }) |                     }) | ||||||
|                 } |                 } | ||||||
| @ -121,12 +121,12 @@ export default function RouteListView(props) { | |||||||
|             <div className={"container-fluid"}> |             <div className={"container-fluid"}> | ||||||
|                 <div className={"row mb-2"}> |                 <div className={"row mb-2"}> | ||||||
|                     <div className={"col-sm-6"}> |                     <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> | ||||||
|                     <div className={"col-sm-6"}> |                     <div className={"col-sm-6"}> | ||||||
|                         <ol className={"breadcrumb float-sm-right"}> |                         <ol className={"breadcrumb float-sm-right"}> | ||||||
|                             <li className={"breadcrumb-item"}><Link to={"/admin/dashboard"}>Home</Link></li> |                             <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> |                         </ol> | ||||||
|                     </div> |                     </div> | ||||||
|                 </div> |                 </div> | ||||||
| @ -147,7 +147,7 @@ export default function RouteListView(props) { | |||||||
|                     <Button variant={"outlined"} className={"m-1"} startIcon={<Cached />} |                     <Button variant={"outlined"} className={"m-1"} startIcon={<Cached />} | ||||||
|                             disabled={!props.api.hasPermission("routes/generateCache") || isGeneratingCache} |                             disabled={!props.api.hasPermission("routes/generateCache") || isGeneratingCache} | ||||||
|                             onClick={onRegenerateCache} > |                             onClick={onRegenerateCache} > | ||||||
|                         {isGeneratingCache ? L("regenerating_cache") + "…" : L("regenerate_cache")} |                         {isGeneratingCache ? L("routes.regenerating_cache") + "…" : L("routes.regenerate_cache")} | ||||||
|                     </Button> |                     </Button> | ||||||
|                 </div> |                 </div> | ||||||
|             </div> |             </div> | ||||||
| @ -157,12 +157,12 @@ export default function RouteListView(props) { | |||||||
|                 <TableHead> |                 <TableHead> | ||||||
|                     <TableRow> |                     <TableRow> | ||||||
|                         <TableCell>{L("general.id")}</TableCell> |                         <TableCell>{L("general.id")}</TableCell> | ||||||
|                         <TableCell>{L("Route")}</TableCell> |                         <TableCell>{L("routes.route")}</TableCell> | ||||||
|                         <TableCell>{L("Type")}</TableCell> |                         <TableCell>{L("routes.type")}</TableCell> | ||||||
|                         <TableCell>{L("Target")}</TableCell> |                         <TableCell>{L("routes.target")}</TableCell> | ||||||
|                         <TableCell>{L("Extra")}</TableCell> |                         <TableCell>{L("routes.extra")}</TableCell> | ||||||
|                         <TableCell align={"center"}>{L("Active")}</TableCell> |                         <TableCell align={"center"}>{L("routes.active")}</TableCell> | ||||||
|                         <TableCell align={"center"}>{L("Exact")}</TableCell> |                         <TableCell align={"center"}>{L("routes.exact")}</TableCell> | ||||||
|                         <TableCell align={"center"}>{L("general.controls")}</TableCell> |                         <TableCell align={"center"}>{L("general.controls")}</TableCell> | ||||||
|                     </TableRow> |                     </TableRow> | ||||||
|                 </TableHead> |                 </TableHead> | ||||||
|  | |||||||
| @ -45,6 +45,7 @@ | |||||||
|         "date-fns": "^2.29.3", |         "date-fns": "^2.29.3", | ||||||
|         "material-ui-color-picker": "^3.5.1", |         "material-ui-color-picker": "^3.5.1", | ||||||
|         "mini-css-extract-plugin": "^2.7.1", |         "mini-css-extract-plugin": "^2.7.1", | ||||||
|  |         "pako": "^2.1.0", | ||||||
|         "react": "^18.2.0", |         "react": "^18.2.0", | ||||||
|         "react-chartjs-2": "^5.0.1", |         "react-chartjs-2": "^5.0.1", | ||||||
|         "react-collapse": "^5.1.1", |         "react-collapse": "^5.1.1", | ||||||
|  | |||||||
| @ -308,12 +308,12 @@ export default class API { | |||||||
|         return res; |         return res; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     async getLanguageEntries(modules, code=null, useCache=false) { |     async getLanguageEntries(modules, code=null, compression=null) { | ||||||
|         if (!Array.isArray(modules)) { |         if (!Array.isArray(modules)) { | ||||||
|             modules = [modules]; |             modules = [modules]; | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         return this.apiCall("language/getEntries", {code: code, modules: modules}); |         return this.apiCall("language/getEntries", {code: code, modules: modules, compression: compression}); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** ApiKeyAPI **/ |     /** ApiKeyAPI **/ | ||||||
|  | |||||||
| @ -1,7 +1,8 @@ | |||||||
| import React, {useReducer} from 'react'; | import React, {useReducer} from 'react'; | ||||||
| import {createContext, useCallback, useState} from "react"; | import {createContext, useCallback, useState} from "react"; | ||||||
| import { enUS as dateFnsEN, de as dateFnsDE } from 'date-fns/locale'; | import { enUS as dateFnsEN, de as dateFnsDE } from 'date-fns/locale'; | ||||||
| import {getCookie, getParameter} from "./util"; | import {encodeText, getCookie, getParameter} from "./util"; | ||||||
|  | import pako from "pako"; | ||||||
| 
 | 
 | ||||||
| const LocaleContext = createContext(null); | const LocaleContext = createContext(null); | ||||||
| 
 | 
 | ||||||
| @ -109,7 +110,13 @@ function LocaleProvider(props) { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         if (modules.length > 0) { |         if (modules.length > 0) { | ||||||
|             let data = await api.apiCall("language/getEntries", { code: code, modules: modules }); |             let compression = "zlib"; | ||||||
|  | 
 | ||||||
|  |             let data = await api.getLanguageEntries(modules, code, compression); | ||||||
|  | 
 | ||||||
|  |             if (compression && data.success) { | ||||||
|  |                 data.entries = JSON.parse(pako.inflate(encodeText(atob(data.compressed)), { to: 'string' })); | ||||||
|  |             } | ||||||
| 
 | 
 | ||||||
|             if (useCache) { |             if (useCache) { | ||||||
|                 if (data && data.success) { |                 if (data && data.success) { | ||||||
|  | |||||||
| @ -4858,11 +4858,6 @@ date-fns@^2.29.3: | |||||||
|   dependencies: |   dependencies: | ||||||
|     "@babel/runtime" "^7.21.0" |     "@babel/runtime" "^7.21.0" | ||||||
| 
 | 
 | ||||||
| dayjs@^1.11.10: |  | ||||||
|   version "1.11.10" |  | ||||||
|   resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" |  | ||||||
|   integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== |  | ||||||
| 
 |  | ||||||
| debug@2.6.9, debug@^2.6.0: | debug@2.6.9, debug@^2.6.0: | ||||||
|   version "2.6.9" |   version "2.6.9" | ||||||
|   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" |   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" | ||||||
| @ -8392,6 +8387,11 @@ p-try@^2.0.0: | |||||||
|   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" |   resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" | ||||||
|   integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== |   integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== | ||||||
| 
 | 
 | ||||||
|  | pako@^2.1.0: | ||||||
|  |   version "2.1.0" | ||||||
|  |   resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" | ||||||
|  |   integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== | ||||||
|  | 
 | ||||||
| param-case@^3.0.4: | param-case@^3.0.4: | ||||||
|   version "3.0.4" |   version "3.0.4" | ||||||
|   resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" |   resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5" | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user