Browse Source

removed mui v4

Roman 4 weeks ago
parent
commit
c6f9c8894c
31 changed files with 228 additions and 495 deletions
  1. 13 0
      Core/API/Stats.class.php
  2. 1 0
      Core/Localization/de_DE/account.php
  3. 1 0
      Core/Localization/de_DE/admin.php
  4. 2 0
      Core/Localization/de_DE/routes.php
  5. 1 0
      Core/Localization/en_US/account.php
  6. 1 0
      Core/Localization/en_US/admin.php
  7. 2 0
      Core/Localization/en_US/routes.php
  8. 2 2
      react/admin-panel/src/App.jsx
  9. 5 3
      react/admin-panel/src/elements/language-selection.js
  10. 5 5
      react/admin-panel/src/views/access-control-list.js
  11. 35 31
      react/admin-panel/src/views/group/group-edit.js
  12. 13 12
      react/admin-panel/src/views/group/group-list.js
  13. 0 4
      react/admin-panel/src/views/group/index.js
  14. 2 3
      react/admin-panel/src/views/log-view.js
  15. 7 5
      react/admin-panel/src/views/login.jsx
  16. 6 3
      react/admin-panel/src/views/overview.js
  17. 0 4
      react/admin-panel/src/views/route/index.js
  18. 6 6
      react/admin-panel/src/views/route/route-edit.js
  19. 2 2
      react/admin-panel/src/views/route/route-form.js
  20. 8 6
      react/admin-panel/src/views/route/route-list.js
  21. 1 1
      react/admin-panel/src/views/settings.js
  22. 0 4
      react/admin-panel/src/views/user/index.js
  23. 1 1
      react/admin-panel/src/views/user/user-edit.js
  24. 28 18
      react/admin-panel/src/views/user/user-list.js
  25. 2 4
      react/package.json
  26. 5 0
      react/shared/elements/data-table.css
  27. 12 18
      react/shared/elements/data-table.js
  28. 6 6
      react/shared/elements/language-selection.js
  29. 1 2
      react/shared/hooks/pagination.js
  30. 8 7
      react/shared/views/login.jsx
  31. 52 348
      react/yarn.lock

+ 13 - 0
Core/API/Stats.class.php

@@ -71,6 +71,18 @@ class Stats extends Request {
       return false;
     }
 
+    $req = new \Core\API\Logs\Get($this->context, false);
+    $success = $req->execute([
+      "since" => (new \DateTime())->modify("-48 hours"),
+      "severity" => "error"
+    ]);
+
+    if ($success) {
+      $errorCount = $req->getResult()["pagination"]["total"];
+    } else {
+      $errorCount = "Unknown";
+    }
+
     $loadAvg = "Unknown";
     if (function_exists("sys_getloadavg")) {
       $loadAvg = sys_getloadavg();
@@ -86,6 +98,7 @@ class Stats extends Request {
       "groupCount" => $groupCount,
       "visitors" => $visitorStatistics,
       "visitorsTotal" => $visitorCount,
+      "errorCount" => $errorCount,
       "server" => [
         "version" => WEBBASE_VERSION,
         "server" => $_SERVER["SERVER_SOFTWARE"] ?? "Unknown",

+ 1 - 0
Core/Localization/de_DE/account.php

@@ -69,6 +69,7 @@ return [
   "logged_in_as" => "Eingeloggt als",
   "active" => "Aktiv",
   "group" => "Gruppe",
+  "no_members" => "Keine Mitglieder in dieser Gruppe",
 
   # dialogs
   "fetch_group_members_error" => "Fehler beim Holen der Gruppenmitglieder",

+ 1 - 0
Core/Localization/de_DE/admin.php

@@ -17,6 +17,7 @@ return [
   "users_registered" => "Benutzer registriert",
   "available_groups" => "verfügbare Gruppen",
   "routes_defined" => "Routen definiert",
+  "error_count" => "Fehler in den letzten 48 Stunden",
 
   # Dialogs
   "fetch_stats_error" => "Fehler beim Holen der Stats",

+ 2 - 0
Core/Localization/de_DE/routes.php

@@ -33,6 +33,8 @@ return [
 
   # dialogs
   "fetch_routes_error" => "Fehler beim Holen der Routen",
+  "fetch_route_error" => "Fehler beim Holen der Route",
+  "save_route_error" => "Fehler beim Speichern der Route",
   "enable_route_error" => "Fehler beim Aktivieren der Route",
   "disable_route_error" => "Fehler beim Deaktivieren der Route",
   "remove_route_error" => "Fehler beim Entfernen der Route",

+ 1 - 0
Core/Localization/en_US/account.php

@@ -69,6 +69,7 @@ return [
   "logged_in_as" => "Logged in as",
   "active" => "Active",
   "group" => "Group",
+  "no_members" => "No members in this group",
 
   # dialogs
   "fetch_group_members_error" => "Error fetching group members",

+ 1 - 0
Core/Localization/en_US/admin.php

@@ -17,6 +17,7 @@ return [
   "users_registered" => "Users registered",
   "available_groups" => "available Groups",
   "routes_defined" => "Routes defined",
+  "error_count" => "Errors in the past 48 hours",
 
   # Dialogs
   "fetch_stats_error" => "Error fetching stats",

+ 2 - 0
Core/Localization/en_US/routes.php

@@ -33,6 +33,8 @@ return [
 
   # dialogs
   "fetch_routes_error" => "Error fetching routes",
+  "fetch_route_error" => "Error fetching route",
+  "save_route_error" => "Error saving route",
   "enable_route_error" => "Error enabling route",
   "disable_route_error" => "Error disabling route",
   "remove_route_error" => "Error removing route",

+ 2 - 2
react/admin-panel/src/App.jsx

@@ -2,8 +2,8 @@ import React, {useCallback, useContext, useEffect, useMemo, useState} from 'reac
 import API from "shared/api";
 import Icon from "shared/elements/icon";
 import LoginForm from "shared/views/login";
-import {Alert} from "@material-ui/lab";
-import {Button} from "@material-ui/core";
+import {Alert} from "@mui/lab";
+import {Button} from "@mui/material";
 import {LocaleContext} from "shared/locale";
 import AdminDashboard from "./AdminDashboard";
 

+ 5 - 3
react/admin-panel/src/elements/language-selection.js

@@ -1,8 +1,8 @@
 import React, {useCallback, useContext, useState} from 'react';
-import {Box} from "@material-ui/core";
-import {makeStyles} from "@material-ui/core/styles";
+import {Box} from "@mui/material";
 import {LocaleContext} from "shared/locale";
 
+/*
 const useStyles = makeStyles((theme) => ({
     languageFlag: {
         margin: theme.spacing(0.2),
@@ -10,11 +10,13 @@ const useStyles = makeStyles((theme) => ({
         border: 0,
     }
 }));
+*/
 
 export default function LanguageSelection(props) {
 
     const api = props.api;
-    const classes = useStyles();
+    // const classes = useStyles();
+    const classes = {};
     const [languages, setLanguages] = useState(null);
     const {translate: L, setLanguageByCode} = useContext(LocaleContext);
 

+ 5 - 5
react/admin-panel/src/views/access-control-list.js

@@ -12,9 +12,9 @@ import {
     TableContainer,
     TableHead,
     TableRow,
-    IconButton, styled, FormGroup, FormLabel, FormControl, Box
-} from "@material-ui/core";
-import {Add, Delete, Edit, Refresh} from "@material-ui/icons";
+    IconButton, styled, FormGroup, FormLabel, Box
+} from "@mui/material";
+import {Add, Delete, Edit, Refresh} from "@mui/icons-material";
 import {USER_GROUP_ADMIN} from "shared/constants";
 import Dialog from "shared/elements/dialog";
 
@@ -238,11 +238,11 @@ export default function AccessControlList(props) {
                     <FormLabel>{L("general.controls")}</FormLabel>
                 </Box>
                 <Box mb={2}>
-                    <Button variant={"outlined"} color={"primary"} className={"mr-1"}
+                    <Button variant={"outlined"} color={"primary"} className={"mr-1"} size={"small"}
                             startIcon={<Refresh />} onClick={() => onFetchACL(true)}>
                         {L("general.reload")}
                     </Button>
-                    <Button variant={"outlined"} startIcon={<Add />}
+                    <Button variant={"outlined"} startIcon={<Add />} size={"small"}
                             disabled={!props.api.hasGroup(USER_GROUP_ADMIN)}
                             onClick={() => setDialogData({
                                 open: true,

+ 35 - 31
react/admin-panel/src/views/group/group-edit.js

@@ -2,16 +2,14 @@ import {useCallback, useContext, useEffect, useState} from "react";
 import {Link, useNavigate, useParams} from "react-router-dom";
 import {LocaleContext} from "shared/locale";
 import SearchField from "shared/elements/search-field";
-import {Button, CircularProgress} from "@material-ui/core";
-import * as React from "react";
-import ColorPicker from "material-ui-color-picker";
+import React from "react";
 import {ControlsColumn, DataTable, NumericColumn, StringColumn} from "shared/elements/data-table";
 import EditIcon from "@mui/icons-material/Edit";
 import usePagination from "shared/hooks/pagination";
-import {Delete, KeyboardArrowLeft, Save} from "@material-ui/icons";
 import Dialog from "shared/elements/dialog";
-import {Box, FormControl, FormGroup, FormLabel, styled, TextField} from "@mui/material";
-import {Add} from "@mui/icons-material";
+import {Box, FormControl, FormGroup, FormLabel, styled, TextField, Button, CircularProgress} from "@mui/material";
+import {Add, Delete, KeyboardArrowLeft, Save} from "@mui/icons-material";
+import {MuiColorInput} from "mui-color-input";
 
 const defaultGroupData = {
     name: "",
@@ -146,6 +144,24 @@ export default function EditGroupView(props) {
         });
     }, [api, groupId]);
 
+    const onOpenMemberDialog = useCallback(() => {
+        setDialogData({
+            open: true,
+            title: L("account.add_group_member_title"),
+            message: L("account.add_group_member_text"),
+            inputs: [
+                {
+                    type: "custom", name: "search", element: SearchField,
+                    size: "small", key: "search",
+                    onSearch: v => onSearchUser(v),
+                    onSelect: u => setSelectedUser(u),
+                    displayText: u => u.fullName || u.name
+                }
+            ],
+            onOption: (option) => option === 0 ? onAddMember() : setSelectedUser(null)
+        });
+    }, []);
+
     useEffect(() => {
         onFetchGroup();
     }, []);
@@ -202,12 +218,11 @@ export default function EditGroupView(props) {
                             {L("account.color")}
                         </FormLabel>
                         <FormControl>
-                            <ColorPicker
+                            <MuiColorInput
+                                format={"hex"}
                                 value={group.color}
                                 size={"small"}
                                 variant={"outlined"}
-                                style={{ backgroundColor: group.color }}
-                                floatingLabelText={group.color}
                                 onChange={color => setGroup({...group, color: color})}
                             />
                         </FormControl>
@@ -243,6 +258,7 @@ export default function EditGroupView(props) {
             </div>
             {!isNewGroup && api.hasPermission("groups/getMembers") ?
                 <div className={"m-3 col-6"}>
+                    <h4>{L("account.members")}</h4>
                     <DataTable
                         data={members}
                         pagination={pagination}
@@ -250,8 +266,7 @@ export default function EditGroupView(props) {
                         defaultSortColumn={0}
                         className={"table table-striped"}
                         fetchData={onFetchMembers}
-                        placeholder={L("No members in this group")}
-                        title={L("account.members")}
+                        placeholder={L("account.no_members")}
                         columns={[
                             new NumericColumn(L("general.id"), "id"),
                             new StringColumn(L("account.name"), "name"),
@@ -266,6 +281,7 @@ export default function EditGroupView(props) {
                                     label: L("general.remove"),
                                     element: Delete,
                                     disabled: !api.hasPermission("groups/removeMember"),
+                                    color: "secondary",
                                     onClick: (entry) => setDialogData({
                                         open: true,
                                         title: L("account.remove_group_member_title"),
@@ -275,27 +291,15 @@ export default function EditGroupView(props) {
                                 }
                             ]),
                         ]}
+                        buttons={[{
+                            key: "btn-add-member",
+                            color: "primary",
+                            startIcon: <Add />,
+                            disabled: !api.hasPermission("groups/addMember"),
+                            children: L("general.add"),
+                            onClick: onOpenMemberDialog
+                        }]}
                     />
-                    <Button startIcon={<Add />} color={"primary"}
-                            variant={"outlined"} disabled={!api.hasPermission("groups/addMember")}
-                            onClick={() => setDialogData({
-                                open: true,
-                                title: L("account.add_group_member_title"),
-                                message: L("account.add_group_member_text"),
-                                inputs: [
-                                    {
-                                        type: "custom", name: "search", element: SearchField,
-                                        size: "small", key: "search",
-                                        onSearch: v => onSearchUser(v),
-                                        onSelect: u => setSelectedUser(u),
-                                        displayText: u => u.fullName || u.name
-                                    }
-                                ],
-                                onOption: (option) => option === 0 ? onAddMember() : setSelectedUser(null)
-                                })
-                            }>
-                        {L("general.add")}
-                    </Button>
                 </div>
                 : <></>
             }

+ 13 - 12
react/admin-panel/src/views/group/group-list.js

@@ -1,10 +1,8 @@
 import {Link, useNavigate} from "react-router-dom";
 import {useCallback, useContext, useEffect, useState} from "react";
 import {LocaleContext} from "shared/locale";
-import {ControlsColumn, DataColumn, DataTable, NumericColumn, StringColumn} from "shared/elements/data-table";
-import {Button, IconButton} from "@material-ui/core";
-import EditIcon from '@mui/icons-material/Edit';
-import AddIcon from '@mui/icons-material/Add';
+import {ControlsColumn, DataTable, NumericColumn, StringColumn} from "shared/elements/data-table";
+import {Add, Edit} from "@mui/icons-material";
 import usePagination from "shared/hooks/pagination";
 
 
@@ -44,7 +42,7 @@ export default function GroupListView(props) {
         new StringColumn(L("account.name"), "name"),
         new NumericColumn(L("account.member_count"), "memberCount", { align: "center" }),
         new ControlsColumn(L("general.controls"), [
-            { label: L("general.edit"), element: EditIcon, onClick: (entry) => navigate(`/admin/group/${entry.id}`) }
+            { label: L("general.edit"), element: Edit, onClick: (entry) => navigate(`/admin/group/${entry.id}`) }
         ]),
     ];
 
@@ -53,6 +51,7 @@ export default function GroupListView(props) {
             <div className={"container-fluid"}>
                 <div className={"row mb-2"}>
                     <div className={"col-sm-6"}>
+                        <h1 className={"m-0 text-dark"}>{L("account.groups")}</h1>
                     </div>
                     <div className={"col-sm-6"}>
                         <ol className={"breadcrumb float-sm-right"}>
@@ -64,11 +63,6 @@ export default function GroupListView(props) {
             </div>
             <div className={"content"}>
                 <div className={"container-fluid"}>
-                    <Link to="/admin/group/new">
-                        <Button variant={"outlined"} startIcon={<AddIcon />} size={"small"}>
-                            {L("general.create_new")}
-                        </Button>
-                    </Link>
                     <DataTable
                         data={groups}
                         pagination={pagination}
@@ -77,8 +71,15 @@ export default function GroupListView(props) {
                         className={"table table-striped"}
                         fetchData={onFetchGroups}
                         placeholder={"No groups to display"}
-                        title={L("account.groups")}
-                        columns={columnDefinitions} />
+                        columns={columnDefinitions}
+                        buttons={[{
+                            key: "btn-create-group",
+                            color: "primary",
+                            startIcon: <Add />,
+                            onClick: () => navigate("/admin/group/new"),
+                            disabled: !api.hasPermission("groups/create"),
+                            children: L("general.create_new")
+                        }]}/>
                 </div>
             </div>
         </div>

+ 0 - 4
react/admin-panel/src/views/group/index.js

@@ -1,4 +0,0 @@
-import EditGroupView from "./group-edit";
-import GroupListView from "./group-list";
-
-export default { EditGroupView, GroupListView };

+ 2 - 3
react/admin-panel/src/views/log-view.js

@@ -3,14 +3,13 @@ import {LocaleContext} from "shared/locale";
 import {Link} from "react-router-dom";
 import usePagination from "shared/hooks/pagination";
 import {DataColumn, DataTable, DateTimeColumn, NumericColumn, StringColumn} from "shared/elements/data-table";
-import {TextField} from "@mui/material";
+import {Box, FormControl, FormGroup, FormLabel, IconButton, MenuItem, TextField} from "@mui/material";
 import {DateTimePicker} from "@mui/x-date-pickers";
 import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
 import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
 import {API_DATETIME_FORMAT} from "shared/constants";
 import {format, toDate} from "date-fns";
-import {Box, FormControl, FormGroup, FormLabel, IconButton, MenuItem, Select} from "@material-ui/core";
-import {ExpandLess, ExpandMore} from "@material-ui/icons";
+import {ExpandLess, ExpandMore} from "@mui/icons-material";
 
 export default function LogView(props) {
 

+ 7 - 5
react/admin-panel/src/views/login.jsx

@@ -7,17 +7,17 @@ import {
     Link,
     TextField,
     Typography
-} from "@material-ui/core";
+} from "@mui/material";
 
-import {makeStyles} from '@material-ui/core/styles';
-import {Alert} from '@material-ui/lab';
+import {Alert} from '@mui/lab';
 import React, {useCallback, useContext, useEffect, useState} from "react";
-import ReplayIcon from '@material-ui/icons/Replay';
+import ReplayIcon from '@mui/icons-material';
 import LanguageSelection from "../elements/language-selection";
 import {decodeText, encodeText, getParameter, removeParameter} from "shared/util";
 import Icon from "shared/elements/icon";
 import {LocaleContext} from "shared/locale";
 
+/*
 const useStyles = makeStyles((theme) => ({
     paper: {
         marginTop: theme.spacing(8),
@@ -66,11 +66,13 @@ const useStyles = makeStyles((theme) => ({
         }
     }
 }));
+ */
 
 export default function LoginForm(props) {
 
     const api = props.api;
-    const classes = useStyles();
+    // const classes = useStyles();
+    const classes = {};
     let [username, setUsername] = useState("");
     let [password, setPassword] = useState("");
     let [rememberMe, setRememberMe] = useState(true);

+ 6 - 3
react/admin-panel/src/views/overview.js

@@ -1,11 +1,10 @@
 import * as React from "react";
 import {Link} from "react-router-dom";
 import {format, getDaysInMonth} from "date-fns";
-import {CircularProgress} from "@material-ui/core";
 import {useCallback, useContext, useEffect, useState} from "react";
 import {LocaleContext} from "shared/locale";
-import {LibraryBooks, People} from "@material-ui/icons";
-import {ArrowCircleRight, Groups} from "@mui/icons-material";
+import {ArrowCircleRight, BugReport, Groups, LibraryBooks, People} from "@mui/icons-material";
+import {CircularProgress} from "@mui/material";
 
 const StatBox = (props) => <div className={"col-lg-3 col-6"}>
     <div className={"small-box bg-" + props.color}>
@@ -131,6 +130,10 @@ export default function Overview(props) {
                              text={L("admin.routes_defined")}
                              icon={<LibraryBooks />}
                              link={"/admin/routes"} />
+                    <StatBox color={"danger"} count={stats?.errorCount}
+                             text={L("admin.error_count")}
+                             icon={<BugReport />}
+                             link={"/admin/logs"} />
                 </div>
             </div>
         </section>

+ 0 - 4
react/admin-panel/src/views/route/index.js

@@ -1,4 +0,0 @@
-import RouteEditView from "./route-edit";
-import RouteListView from "./route-list";
-
-export default { RouteEditView, RouteListView };

+ 6 - 6
react/admin-panel/src/views/route/route-edit.js

@@ -4,12 +4,12 @@ import {LocaleContext} from "shared/locale";
 import {
     Box,
     Button,
+    TextField,
     CircularProgress, styled,
-} from "@material-ui/core";
+} from "@mui/material";
 import * as React from "react";
 import RouteForm from "./route-form";
-import {KeyboardArrowLeft, Save} from "@material-ui/icons";
-import {TextField} from "@mui/material";
+import {KeyboardArrowLeft, Save} from "@mui/icons-material";
 
 const ButtonBar = styled(Box)((props) => ({
     "& > button": {
@@ -74,7 +74,7 @@ export default function RouteEditView(props) {
             setFetchRoute(false);
             api.getRoute(routeId).then((res) => {
                 if (!res.success) {
-                    showDialog(res.msg, L("Error fetching route"));
+                    showDialog(res.msg, L("routes.fetch_route_error"));
                     navigate("/admin/routes");
                 } else {
                     setRoute(res.route);
@@ -93,7 +93,7 @@ export default function RouteEditView(props) {
                     if (res.success) {
                         navigate("/admin/routes/" + res.routeId);
                     } else {
-                        showDialog(res.msg, L("Error saving route"));
+                        showDialog(res.msg, L("routes.save_route_error"));
                     }
                 });
             } else {
@@ -101,7 +101,7 @@ export default function RouteEditView(props) {
                 api.updateRoute(...args).then(res => {
                     setSaving(false);
                     if (!res.success) {
-                        showDialog(res.msg, L("Error saving route"));
+                        showDialog(res.msg, L("routes.save_route_error"));
                     }
                 });
             }

+ 2 - 2
react/admin-panel/src/views/route/route-form.js

@@ -1,8 +1,8 @@
-import {Box, Checkbox, FormControl, FormControlLabel, Select, styled, TextField} from "@material-ui/core";
+import {Box, Checkbox, FormControl, FormControlLabel, Select, styled, TextField} from "@mui/material";
 import * as React from "react";
 import {useCallback, useContext, useEffect, useRef} from "react";
 import {LocaleContext} from "shared/locale";
-import {CheckCircle, ErrorRounded} from "@material-ui/icons";
+import {CheckCircle, ErrorRounded} from "@mui/icons-material";
 
 const RouteFormControl = styled(FormControl)((props) => ({
     "& > label": {

+ 8 - 6
react/admin-panel/src/views/route/route-list.js

@@ -8,11 +8,12 @@ import {
     TableContainer,
     TableHead,
     TableRow,
-    IconButton, Button, Checkbox
-} from "@material-ui/core";
+    Button,
+    IconButton, Checkbox
+} from "@mui/material";
 import {useCallback, useContext, useEffect, useState} from "react";
 import {LocaleContext} from "shared/locale";
-import {Add, Cached, Delete, Edit, Refresh} from "@material-ui/icons";
+import {Add, Cached, Delete, Edit, Refresh} from "@mui/icons-material";
 import Dialog from "shared/elements/dialog";
 
 const RouteTableRow = styled(TableRow)((props) => ({
@@ -136,15 +137,16 @@ export default function RouteListView(props) {
             <div className={"col-6"} />
                 <div className={"col-6 text-right"}>
                 <div className={"form-group"}>
-                    <Button variant={"outlined"} color={"primary"} className={"m-1"} startIcon={<Refresh />} onClick={() => onFetchRoutes(true)}>
+                    <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 />}
+                    <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 />}
+                    <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")}

+ 1 - 1
react/admin-panel/src/views/settings.js

@@ -10,6 +10,7 @@ import {
     TableBody,
     TableCell,
     TableHead,
+    TableContainer,
     TableRow,
     Tabs, TextField
 } from "@mui/material";
@@ -25,7 +26,6 @@ import {
     Send,
     SettingsApplications
 } from "@mui/icons-material";
-import {TableContainer} from "@material-ui/core";
 import TIME_ZONES from "shared/time-zones";
 
 const SettingsFormGroup = styled(FormGroup)((props) => ({

+ 0 - 4
react/admin-panel/src/views/user/index.js

@@ -1,4 +0,0 @@
-import UserEditView from "./user-edit";
-import UserListView from "./user-list";
-
-export default { UserEditView, UserListView };

+ 1 - 1
react/admin-panel/src/views/user/user-edit.js

@@ -1,6 +1,6 @@
 import {Link, useNavigate, useParams} from "react-router-dom";
 import {useCallback, useContext, useEffect, useState} from "react";
-import {CircularProgress} from "@material-ui/core";
+import {CircularProgress} from "@mui/material";
 import {LocaleContext} from "shared/locale";
 import * as React from "react";
 

+ 28 - 18
react/admin-panel/src/views/user/user-list.js

@@ -9,10 +9,8 @@ import {
     NumericColumn,
     StringColumn
 } from "shared/elements/data-table";
-import {Button} from "@material-ui/core";
-import EditIcon from '@mui/icons-material/Edit';
 import {Chip} from "@mui/material";
-import AddIcon from "@mui/icons-material/Add";
+import {Edit, Add} from "@mui/icons-material";
 import usePagination from "shared/hooks/pagination";
 
 
@@ -67,19 +65,29 @@ export default function UserListView(props) {
         new BoolColumn(L("account.active"), "active", { align: "center" }),
         new BoolColumn(L("account.confirmed"), "confirmed", { align: "center" }),
         new ControlsColumn(L("general.controls"), [
-            { label: L("general.edit"), element: EditIcon, onClick: (entry) => navigate(`/admin/user/${entry.id}`) }
+            { label: L("general.edit"), element: Edit, onClick: (entry) => navigate(`/admin/user/${entry.id}`) }
         ]),
     ];
 
-    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">Users</li>
-            </ol>
+    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("account.users")}</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("account.users")}</li>
+                        </ol>
+                    </div>
+                </div>
+            </div>
         </div>
         <div className={"content"}>
             <div className={"container-fluid"}>
+
                 <DataTable
                     data={users}
                     pagination={pagination}
@@ -88,14 +96,16 @@ export default function UserListView(props) {
                     className={"table table-striped"}
                     fetchData={onFetchUsers}
                     placeholder={"No users to display"}
-                    title={L("account.users")}
-                    columns={columnDefinitions} />
-                <Link to="/admin/user/new">
-                    <Button variant={"outlined"} startIcon={<AddIcon />} size={"small"}>
-                        {L("general.create_new")}
-                    </Button>
-                </Link>
+                    columns={columnDefinitions}
+                    buttons={[{
+                        key: "btn-create",
+                        color: "primary",
+                        startIcon: <Add />,
+                        children: L("general.create_new"),
+                        disabled: !api.hasPermission("user/create") && !api.hasPermission("user/invite"),
+                        onClick: () => navigate("/admin/user/new")
+                    }]}/>
             </div>
         </div>
-    </div>
+    </>
 }

+ 2 - 4
react/package.json

@@ -34,17 +34,15 @@
     "dependencies": {
         "@emotion/react": "^11.11.4",
         "@emotion/styled": "^11.11.0",
-        "@material-ui/core": "^4.12.4",
-        "@material-ui/icons": "^4.11.3",
-        "@material-ui/lab": "^4.0.0-alpha.61",
         "@mui/icons-material": "^5.11.0",
+        "@mui/lab": "^5.0.0-alpha.170",
         "@mui/material": "^5.15.14",
         "@mui/x-date-pickers": "^7.0.0",
         "chart.js": "^4.0.1",
         "clsx": "^1.2.1",
         "date-fns": "^2.29.3",
-        "material-ui-color-picker": "^3.5.1",
         "mini-css-extract-plugin": "^2.7.1",
+        "mui-color-input": "^2.0.3",
         "pako": "^2.1.0",
         "react": "^18.2.0",
         "react-chartjs-2": "^5.0.1",

+ 5 - 0
react/shared/elements/data-table.css

@@ -48,4 +48,9 @@
     margin-left: 4px;
     margin-right: 4px;
     cursor: pointer;
+}
+
+.data-table-button-bar button {
+    margin-right: 8px;
+    margin-top: 8px;
 }

+ 12 - 18
react/shared/elements/data-table.js

@@ -1,14 +1,11 @@
-import {Table, TableBody, TableCell, TableHead, TableRow} from "@material-ui/core";
-import ArrowUpwardIcon from "@material-ui/icons/ArrowUpward";
-import ArrowDownwardIcon from "@material-ui/icons/ArrowDownward";
 import React, {useCallback, useContext, useEffect, useState} from "react";
 import "./data-table.css";
 import {LocaleContext} from "../locale";
 import clsx from "clsx";
-import {Box, IconButton, Select, TextField} from "@mui/material";
+import {Box, Button, Select, TextField, Table, TableBody, TableCell, TableHead, TableRow} from "@mui/material";
 import {formatDate, formatDateTime} from "../util";
-import CachedIcon from "@material-ui/icons/Cached";
 import {isNumber} from "chart.js/helpers";
+import {ArrowUpward, ArrowDownward, Refresh} from "@mui/icons-material";
 
 
 export function DataTable(props) {
@@ -18,7 +15,8 @@ export function DataTable(props) {
         fetchData, onClick, onFilter,
         defaultSortColumn, defaultSortOrder,
         forceReload,
-        title, ...other } = props;
+        buttons,
+        ...other } = props;
 
     const {translate: L} = useContext(LocaleContext);
 
@@ -84,7 +82,7 @@ export function DataTable(props) {
                                       onClick={() => onChangeSort(index, column)}
                                       align={column.align}>
                 {sortColumn === index ?
-                    (sortAscending ? <ArrowUpwardIcon /> : <ArrowDownwardIcon />) :
+                    (sortAscending ? <ArrowUpward /> : <ArrowDownward />) :
                     <></>
                 }
                 {column.renderHead(index)}
@@ -124,17 +122,13 @@ export function DataTable(props) {
     }
 
     return <Box position={"relative"}>
-            {title ?
-                <h3>
-                    {fetchData ?
-                        <IconButton onClick={() => onFetchData(true)} title={L("general.reload")}>
-                            <CachedIcon/>&nbsp;
-                        </IconButton>
-                        : <></>
-                    }
-                    {title}
-                </h3> : <></>
-            }
+            <Box textAlign={"left"} mb={1} className={"data-table-button-bar"}>
+                <Button startIcon={<Refresh />} size={"small"} variant={"outlined"}
+                    onClick={() => onFetchData(true)}>
+                    {L("general.reload")}
+                </Button>
+                {(buttons || []).map(b => <Button size={"small"} variant={"outlined"} {...b} />)}
+            </Box>
             <Table className={clsx("data-table", className)} size="small" {...other}>
                 <TableHead>
                     <TableRow>

+ 6 - 6
react/shared/elements/language-selection.js

@@ -1,8 +1,8 @@
 import React, {useCallback, useContext, useState} from 'react';
-import {Box} from "@material-ui/core";
-import {makeStyles} from "@material-ui/core/styles";
+import {Box, Button} from "@mui/material";
 import {LocaleContext} from "shared/locale";
 
+/*
 const useStyles = makeStyles((theme) => ({
     languageFlag: {
         margin: theme.spacing(0.2),
@@ -10,11 +10,11 @@ const useStyles = makeStyles((theme) => ({
         border: 0,
     }
 }));
+*/
 
 export default function LanguageSelection(props) {
 
     const api = props.api;
-    const classes = useStyles();
     const [languages, setLanguages] = useState(null);
     const {translate: L, setLanguageByCode} = useContext(LocaleContext);
 
@@ -39,10 +39,10 @@ export default function LanguageSelection(props) {
     } else {
         for (const language of Object.values(languages)) {
             let key = `lang-${language.code}`;
-            flags.push(<button type={"button"} title={language.name} onClick={() => onSetLanguage(language.code)}
-                               key={key} className={classes.languageFlag} >
+            flags.push(<Button type={"button"} title={language.name} onClick={() => onSetLanguage(language.code)}
+                               key={key} >
                 <img alt={key} src={`/img/icons/lang/${language.code}.gif`} />
-            </button>);
+            </Button>);
         }
     }
 

+ 1 - 2
react/shared/hooks/pagination.js

@@ -1,7 +1,6 @@
 import React, {useState} from "react";
-import {Box, Select, Pagination as MuiPagination} from "@mui/material";
+import {FormControl, Box, Select, Pagination as MuiPagination} from "@mui/material";
 import {sprintf} from "sprintf-js";
-import {FormControl} from "@material-ui/core";
 
 class Pagination {
 

+ 8 - 7
react/shared/views/login.jsx

@@ -1,5 +1,4 @@
-import {
-    Box,
+import {Box,
     Button,
     Checkbox, CircularProgress, Container,
     FormControlLabel,
@@ -7,16 +6,16 @@ import {
     Link,
     TextField,
     Typography
-} from "@material-ui/core";
+} from "@mui/material";
 
-import {makeStyles} from '@material-ui/core/styles';
-import {Alert} from '@material-ui/lab';
+import {Alert} from '@mui/lab';
 import React, {useCallback, useContext, useEffect, useState} from "react";
-import ReplayIcon from '@material-ui/icons/Replay';
+import ReplayIcon from '@mui/icons-material/Replay';
 import LanguageSelection from "../elements/language-selection";
 import {decodeText, encodeText, getParameter, removeParameter} from "shared/util";
 import {LocaleContext} from "shared/locale";
 
+/*
 const useStyles = makeStyles((theme) => ({
     paper: {
         marginTop: theme.spacing(8),
@@ -65,11 +64,13 @@ const useStyles = makeStyles((theme) => ({
         }
     }
 }));
+*/
 
 export default function LoginForm(props) {
 
     const api = props.api;
-    const classes = useStyles();
+    // const classes = useStyles();
+    const classes = { };
 
     // inputs
     let [username, setUsername] = useState("");

+ 52 - 348
react/yarn.lock

@@ -1107,7 +1107,7 @@
   resolved "https://registry.yarnpkg.com/@babel/regjsgen/-/regjsgen-0.8.0.tgz#f0ba69b075e1f05fb2825b7fad991e7adbb18310"
   integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
 
-"@babel/runtime@^7.0.0", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.3", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
+"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.3", "@babel/runtime@^7.18.3", "@babel/runtime@^7.21.0", "@babel/runtime@^7.23.2", "@babel/runtime@^7.23.9", "@babel/runtime@^7.24.0", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
   version "7.24.1"
   resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.1.tgz#431f9a794d173b53720e69a6464abc6f0e2a5c57"
   integrity sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==
@@ -1264,6 +1264,11 @@
   resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz#2cbcf822bf3764c9658c4d2e568bd0c0cb748016"
   integrity sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==
 
+"@ctrl/tinycolor@^4.0.3":
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-4.0.3.tgz#c56d96ef0d7be598cf68d1ab53f990849a79f5b4"
+  integrity sha512-e9nEVehVJwkymQpkGhdSNzLT2Lr9UTTby+JePq4Z2SxBbOQjY7pLgSouAaXvfaGQVSAaY0U4eJdwfSDmCbItcw==
+
 "@emotion/babel-plugin@^11.11.0":
   version "11.11.0"
   resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c"
@@ -1292,11 +1297,6 @@
     "@emotion/weak-memoize" "^0.3.1"
     stylis "4.2.0"
 
-"@emotion/hash@^0.8.0":
-  version "0.8.0"
-  resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.8.0.tgz#bbbff68978fefdbe68ccb533bc8cbe1d1afb5413"
-  integrity sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==
-
 "@emotion/hash@^0.9.1":
   version "0.9.1"
   resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43"
@@ -1454,11 +1454,6 @@
   resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz#d9fae00a2d5cb40f92cfe64b47ad749fbc38f917"
   integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==
 
-"@icons/material@^0.2.4":
-  version "0.2.4"
-  resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
-  integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==
-
 "@isaacs/cliui@^8.0.2":
   version "8.0.2"
   resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550"
@@ -1789,88 +1784,6 @@
   resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.8.5.tgz#8233e8762440b0f4632c47a09b1b6f23de8b934c"
   integrity sha512-4wvrf5BgnR8RpogHhtpCPJMKBmvyZPhhUtEwMJbXh0ni2BucpfF07jlmyM11zRqQ2XIq6PbC2j7W7UCCcm1rRQ==
 
-"@material-ui/core@^4.12.4":
-  version "4.12.4"
-  resolved "https://registry.yarnpkg.com/@material-ui/core/-/core-4.12.4.tgz#4ac17488e8fcaf55eb6a7f5efb2a131e10138a73"
-  integrity sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==
-  dependencies:
-    "@babel/runtime" "^7.4.4"
-    "@material-ui/styles" "^4.11.5"
-    "@material-ui/system" "^4.12.2"
-    "@material-ui/types" "5.1.0"
-    "@material-ui/utils" "^4.11.3"
-    "@types/react-transition-group" "^4.2.0"
-    clsx "^1.0.4"
-    hoist-non-react-statics "^3.3.2"
-    popper.js "1.16.1-lts"
-    prop-types "^15.7.2"
-    react-is "^16.8.0 || ^17.0.0"
-    react-transition-group "^4.4.0"
-
-"@material-ui/icons@^4.11.3":
-  version "4.11.3"
-  resolved "https://registry.yarnpkg.com/@material-ui/icons/-/icons-4.11.3.tgz#b0693709f9b161ce9ccde276a770d968484ecff1"
-  integrity sha512-IKHlyx6LDh8n19vzwH5RtHIOHl9Tu90aAAxcbWME6kp4dmvODM3UvOHJeMIDzUbd4muuJKHmlNoBN+mDY4XkBA==
-  dependencies:
-    "@babel/runtime" "^7.4.4"
-
-"@material-ui/lab@^4.0.0-alpha.61":
-  version "4.0.0-alpha.61"
-  resolved "https://registry.yarnpkg.com/@material-ui/lab/-/lab-4.0.0-alpha.61.tgz#9bf8eb389c0c26c15e40933cc114d4ad85e3d978"
-  integrity sha512-rSzm+XKiNUjKegj8bzt5+pygZeckNLOr+IjykH8sYdVk7dE9y2ZuUSofiMV2bJk3qU+JHwexmw+q0RyNZB9ugg==
-  dependencies:
-    "@babel/runtime" "^7.4.4"
-    "@material-ui/utils" "^4.11.3"
-    clsx "^1.0.4"
-    prop-types "^15.7.2"
-    react-is "^16.8.0 || ^17.0.0"
-
-"@material-ui/styles@^4.11.5", "@material-ui/styles@^4.8.2":
-  version "4.11.5"
-  resolved "https://registry.yarnpkg.com/@material-ui/styles/-/styles-4.11.5.tgz#19f84457df3aafd956ac863dbe156b1d88e2bbfb"
-  integrity sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==
-  dependencies:
-    "@babel/runtime" "^7.4.4"
-    "@emotion/hash" "^0.8.0"
-    "@material-ui/types" "5.1.0"
-    "@material-ui/utils" "^4.11.3"
-    clsx "^1.0.4"
-    csstype "^2.5.2"
-    hoist-non-react-statics "^3.3.2"
-    jss "^10.5.1"
-    jss-plugin-camel-case "^10.5.1"
-    jss-plugin-default-unit "^10.5.1"
-    jss-plugin-global "^10.5.1"
-    jss-plugin-nested "^10.5.1"
-    jss-plugin-props-sort "^10.5.1"
-    jss-plugin-rule-value-function "^10.5.1"
-    jss-plugin-vendor-prefixer "^10.5.1"
-    prop-types "^15.7.2"
-
-"@material-ui/system@^4.12.2":
-  version "4.12.2"
-  resolved "https://registry.yarnpkg.com/@material-ui/system/-/system-4.12.2.tgz#f5c389adf3fce4146edd489bf4082d461d86aa8b"
-  integrity sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==
-  dependencies:
-    "@babel/runtime" "^7.4.4"
-    "@material-ui/utils" "^4.11.3"
-    csstype "^2.5.2"
-    prop-types "^15.7.2"
-
-"@material-ui/types@5.1.0":
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/@material-ui/types/-/types-5.1.0.tgz#efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2"
-  integrity sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==
-
-"@material-ui/utils@^4.11.3":
-  version "4.11.3"
-  resolved "https://registry.yarnpkg.com/@material-ui/utils/-/utils-4.11.3.tgz#232bd86c4ea81dab714f21edad70b7fdf0253942"
-  integrity sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==
-  dependencies:
-    "@babel/runtime" "^7.4.4"
-    prop-types "^15.7.2"
-    react-is "^16.8.0 || ^17.0.0"
-
 "@mischnic/json-sourcemap@^0.1.0":
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/@mischnic/json-sourcemap/-/json-sourcemap-0.1.1.tgz#0ef9b015a8f575dd9a8720d9a6b4dbc988425906"
@@ -1935,6 +1848,19 @@
   dependencies:
     "@babel/runtime" "^7.23.9"
 
+"@mui/lab@^5.0.0-alpha.170":
+  version "5.0.0-alpha.170"
+  resolved "https://registry.yarnpkg.com/@mui/lab/-/lab-5.0.0-alpha.170.tgz#4519dfc8d1c51ca54fb9d8b91b95a3733d07be16"
+  integrity sha512-0bDVECGmrNjd3+bLdcLiwYZ0O4HP5j5WSQm5DV6iA/Z9kr8O6AnvZ1bv9ImQbbX7Gj3pX4o43EKwCutj3EQxQg==
+  dependencies:
+    "@babel/runtime" "^7.23.9"
+    "@mui/base" "5.0.0-beta.40"
+    "@mui/system" "^5.15.15"
+    "@mui/types" "^7.2.14"
+    "@mui/utils" "^5.15.14"
+    clsx "^2.1.0"
+    prop-types "^15.8.1"
+
 "@mui/material@^5.15.14":
   version "5.15.14"
   resolved "https://registry.yarnpkg.com/@mui/material/-/material-5.15.14.tgz#a40bd5eccfa9fc925535e1f4d70c6cef77fa3a75"
@@ -1986,6 +1912,20 @@
     csstype "^3.1.3"
     prop-types "^15.8.1"
 
+"@mui/system@^5.15.15":
+  version "5.15.15"
+  resolved "https://registry.yarnpkg.com/@mui/system/-/system-5.15.15.tgz#658771b200ce3c4a0f28e58169f02e5e718d1c53"
+  integrity sha512-aulox6N1dnu5PABsfxVGOZffDVmlxPOVgj56HrUnJE8MCSh8lOvvkd47cebIVQQYAjpwieXQXiDPj5pwM40jTQ==
+  dependencies:
+    "@babel/runtime" "^7.23.9"
+    "@mui/private-theming" "^5.15.14"
+    "@mui/styled-engine" "^5.15.14"
+    "@mui/types" "^7.2.14"
+    "@mui/utils" "^5.15.14"
+    clsx "^2.1.0"
+    csstype "^3.1.3"
+    prop-types "^15.8.1"
+
 "@mui/types@^7.2.14":
   version "7.2.14"
   resolved "https://registry.yarnpkg.com/@mui/types/-/types-7.2.14.tgz#8a02ac129b70f3d82f2f9b76ded2c8d48e3fc8c9"
@@ -3224,7 +3164,7 @@
   resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb"
   integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==
 
-"@types/react-transition-group@^4.2.0", "@types/react-transition-group@^4.4.10":
+"@types/react-transition-group@^4.4.10":
   version "4.4.10"
   resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.10.tgz#6ee71127bdab1f18f11ad8fb3322c6da27c327ac"
   integrity sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==
@@ -3871,7 +3811,7 @@ arraybuffer.prototype.slice@^1.0.3:
     is-array-buffer "^3.0.4"
     is-shared-array-buffer "^1.0.2"
 
-asap@~2.0.3, asap@~2.0.6:
+asap@~2.0.6:
   version "2.0.6"
   resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46"
   integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==
@@ -4277,11 +4217,6 @@ chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.2:
     ansi-styles "^4.1.0"
     supports-color "^7.1.0"
 
-change-emitter@^0.1.2:
-  version "0.1.6"
-  resolved "https://registry.yarnpkg.com/change-emitter/-/change-emitter-0.1.6.tgz#e8b2fe3d7f1ab7d69a32199aff91ea6931409515"
-  integrity sha512-YXzt1cQ4a2jqazhcuSWEOc1K2q8g9H6eWNsyZgi640LDzRWVQ2eDe+Y/kVdftH+vYdPF2rgDb3dLdpxE1jvAxw==
-
 char-regex@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf"
@@ -4355,7 +4290,7 @@ clone@^2.1.1:
   resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.2.tgz#1b7f4b9f591f1e8f83670401600345a02887435f"
   integrity sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==
 
-clsx@^1.0.4, clsx@^1.2.1:
+clsx@^1.2.1:
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12"
   integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==
@@ -4539,11 +4474,6 @@ core-js-pure@^3.23.3:
   resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.36.1.tgz#1461c89e76116528b54eba20a0aff30164087a94"
   integrity sha512-NXCvHvSVYSrewP0L5OhltzXeWFJLo2AL2TYnj6iLV3Bw8mM62wAQMNgUCRI6EBu6hVVpbCxmOPlxh1Ikw2PfUA==
 
-core-js@^1.0.0:
-  version "1.2.7"
-  resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636"
-  integrity sha512-ZiPp9pZlgxpWRu0M+YWbm6+aQ84XEfH1JRXvfOc/fILWI0VKhLC2LX13X1NYq4fULzLMq7Hfh43CSo2/aIaUPA==
-
 core-js@^3.19.2:
   version "3.36.1"
   resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.36.1.tgz#c97a7160ebd00b2de19e62f4bbd3406ab720e578"
@@ -4692,14 +4622,6 @@ css-tree@^1.1.2, css-tree@^1.1.3:
     mdn-data "2.0.14"
     source-map "^0.6.1"
 
-css-vendor@^2.0.8:
-  version "2.0.8"
-  resolved "https://registry.yarnpkg.com/css-vendor/-/css-vendor-2.0.8.tgz#e47f91d3bd3117d49180a3c935e62e3d9f7f449d"
-  integrity sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==
-  dependencies:
-    "@babel/runtime" "^7.8.3"
-    is-in-browser "^1.0.2"
-
 css-what@^3.2.1:
   version "3.4.2"
   resolved "https://registry.yarnpkg.com/css-what/-/css-what-3.4.2.tgz#ea7026fcb01777edbde52124e21f327e7ae950e4"
@@ -4793,11 +4715,6 @@ cssstyle@^2.3.0:
   dependencies:
     cssom "~0.3.6"
 
-csstype@^2.5.2:
-  version "2.6.21"
-  resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.21.tgz#2efb85b7cc55c80017c66a5ad7cbd931fda3a90e"
-  integrity sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==
-
 csstype@^3.0.2, csstype@^3.1.3:
   version "3.1.3"
   resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.3.tgz#d80ff294d114fb0e6ac500fbf85b60137d7eff81"
@@ -5178,13 +5095,6 @@ encodeurl@~1.0.2:
   resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
   integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==
 
-encoding@^0.1.11:
-  version "0.1.13"
-  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9"
-  integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==
-  dependencies:
-    iconv-lite "^0.6.2"
-
 enhanced-resolve@^5.16.0:
   version "5.16.0"
   resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz#65ec88778083056cb32487faa9aef82ed0864787"
@@ -5786,19 +5696,6 @@ fb-watchman@^2.0.0:
   dependencies:
     bser "2.1.1"
 
-fbjs@^0.8.1:
-  version "0.8.18"
-  resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.18.tgz#9835e0addb9aca2eff53295cd79ca1cfc7c9662a"
-  integrity sha512-EQaWFK+fEPSoibjNy8IxUtaFOMXcWsY0JaVrQoZR9zC8N2Ygf9iDITPWjUTVIax95b6I742JFLqASHfsag/vKA==
-  dependencies:
-    core-js "^1.0.0"
-    isomorphic-fetch "^2.1.1"
-    loose-envify "^1.0.0"
-    object-assign "^4.1.0"
-    promise "^7.1.1"
-    setimmediate "^1.0.5"
-    ua-parser-js "^0.7.30"
-
 file-entry-cache@^6.0.1:
   version "6.0.1"
   resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027"
@@ -6238,12 +6135,7 @@ he@^1.2.0:
   resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
   integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
 
-hoist-non-react-statics@^2.3.1:
-  version "2.5.5"
-  resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-2.5.5.tgz#c5903cf409c0dfd908f388e619d86b9c1174cb47"
-  integrity sha512-rqcy4pJo55FTTLWt+bU8ukscqHeE/e9KWvsOW2b/a3afxQZhwkQdT1rPPCJ0rYXdj4vNcasY8zHTH+jF/qStxw==
-
-hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
+hoist-non-react-statics@^3.3.1:
   version "3.3.2"
   resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
   integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@@ -6408,11 +6300,6 @@ human-signals@^2.1.0:
   resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
   integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
 
-hyphenate-style-name@^1.0.3:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz#691879af8e220aea5750e8827db4ef62a54e361d"
-  integrity sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==
-
 iconv-lite@0.4.24:
   version "0.4.24"
   resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@@ -6420,7 +6307,7 @@ iconv-lite@0.4.24:
   dependencies:
     safer-buffer ">= 2.1.2 < 3"
 
-iconv-lite@^0.6.2, iconv-lite@^0.6.3:
+iconv-lite@^0.6.3:
   version "0.6.3"
   resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
   integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
@@ -6626,11 +6513,6 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
   dependencies:
     is-extglob "^2.1.1"
 
-is-in-browser@^1.0.2, is-in-browser@^1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/is-in-browser/-/is-in-browser-1.1.3.tgz#56ff4db683a078c6082eb95dad7dc62e1d04f835"
-  integrity sha512-FeXIBgG/CPGd/WUxuEyvgGTEfwiG9Z4EKGxjNMRqviiIIfsmgrpnHLffEDdwUHqNva1VEW91o3xBT/m8Elgl9g==
-
 is-json@^2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/is-json/-/is-json-2.0.1.tgz#6be166d144828a131d686891b983df62c39491ff"
@@ -6713,11 +6595,6 @@ is-shared-array-buffer@^1.0.2, is-shared-array-buffer@^1.0.3:
   dependencies:
     call-bind "^1.0.7"
 
-is-stream@^1.0.1:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
-  integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==
-
 is-stream@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077"
@@ -6791,14 +6668,6 @@ isexe@^2.0.0:
   resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
   integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==
 
-isomorphic-fetch@^2.1.1:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
-  integrity sha512-9c4TNAKYXM5PRyVcwUZrF3W09nQ+sO7+jydgs4ZGW9dhsLG2VOlISJABombdQqQRXCwuYG3sYV/puGf5rp0qmA==
-  dependencies:
-    node-fetch "^1.0.1"
-    whatwg-fetch ">=0.10.0"
-
 istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
   version "3.2.2"
   resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756"
@@ -7486,76 +7355,6 @@ jsonpointer@^5.0.0:
   resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-5.0.1.tgz#2110e0af0900fd37467b5907ecd13a7884a1b559"
   integrity sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==
 
-jss-plugin-camel-case@^10.5.1:
-  version "10.10.0"
-  resolved "https://registry.yarnpkg.com/jss-plugin-camel-case/-/jss-plugin-camel-case-10.10.0.tgz#27ea159bab67eb4837fa0260204eb7925d4daa1c"
-  integrity sha512-z+HETfj5IYgFxh1wJnUAU8jByI48ED+v0fuTuhKrPR+pRBYS2EDwbusU8aFOpCdYhtRc9zhN+PJ7iNE8pAWyPw==
-  dependencies:
-    "@babel/runtime" "^7.3.1"
-    hyphenate-style-name "^1.0.3"
-    jss "10.10.0"
-
-jss-plugin-default-unit@^10.5.1:
-  version "10.10.0"
-  resolved "https://registry.yarnpkg.com/jss-plugin-default-unit/-/jss-plugin-default-unit-10.10.0.tgz#db3925cf6a07f8e1dd459549d9c8aadff9804293"
-  integrity sha512-SvpajxIECi4JDUbGLefvNckmI+c2VWmP43qnEy/0eiwzRUsafg5DVSIWSzZe4d2vFX1u9nRDP46WCFV/PXVBGQ==
-  dependencies:
-    "@babel/runtime" "^7.3.1"
-    jss "10.10.0"
-
-jss-plugin-global@^10.5.1:
-  version "10.10.0"
-  resolved "https://registry.yarnpkg.com/jss-plugin-global/-/jss-plugin-global-10.10.0.tgz#1c55d3c35821fab67a538a38918292fc9c567efd"
-  integrity sha512-icXEYbMufiNuWfuazLeN+BNJO16Ge88OcXU5ZDC2vLqElmMybA31Wi7lZ3lf+vgufRocvPj8443irhYRgWxP+A==
-  dependencies:
-    "@babel/runtime" "^7.3.1"
-    jss "10.10.0"
-
-jss-plugin-nested@^10.5.1:
-  version "10.10.0"
-  resolved "https://registry.yarnpkg.com/jss-plugin-nested/-/jss-plugin-nested-10.10.0.tgz#db872ed8925688806e77f1fc87f6e62264513219"
-  integrity sha512-9R4JHxxGgiZhurDo3q7LdIiDEgtA1bTGzAbhSPyIOWb7ZubrjQe8acwhEQ6OEKydzpl8XHMtTnEwHXCARLYqYA==
-  dependencies:
-    "@babel/runtime" "^7.3.1"
-    jss "10.10.0"
-    tiny-warning "^1.0.2"
-
-jss-plugin-props-sort@^10.5.1:
-  version "10.10.0"
-  resolved "https://registry.yarnpkg.com/jss-plugin-props-sort/-/jss-plugin-props-sort-10.10.0.tgz#67f4dd4c70830c126f4ec49b4b37ccddb680a5d7"
-  integrity sha512-5VNJvQJbnq/vRfje6uZLe/FyaOpzP/IH1LP+0fr88QamVrGJa0hpRRyAa0ea4U/3LcorJfBFVyC4yN2QC73lJg==
-  dependencies:
-    "@babel/runtime" "^7.3.1"
-    jss "10.10.0"
-
-jss-plugin-rule-value-function@^10.5.1:
-  version "10.10.0"
-  resolved "https://registry.yarnpkg.com/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.10.0.tgz#7d99e3229e78a3712f78ba50ab342e881d26a24b"
-  integrity sha512-uEFJFgaCtkXeIPgki8ICw3Y7VMkL9GEan6SqmT9tqpwM+/t+hxfMUdU4wQ0MtOiMNWhwnckBV0IebrKcZM9C0g==
-  dependencies:
-    "@babel/runtime" "^7.3.1"
-    jss "10.10.0"
-    tiny-warning "^1.0.2"
-
-jss-plugin-vendor-prefixer@^10.5.1:
-  version "10.10.0"
-  resolved "https://registry.yarnpkg.com/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.10.0.tgz#c01428ef5a89f2b128ec0af87a314d0c767931c7"
-  integrity sha512-UY/41WumgjW8r1qMCO8l1ARg7NHnfRVWRhZ2E2m0DMYsr2DD91qIXLyNhiX83hHswR7Wm4D+oDYNC1zWCJWtqg==
-  dependencies:
-    "@babel/runtime" "^7.3.1"
-    css-vendor "^2.0.8"
-    jss "10.10.0"
-
-jss@10.10.0, jss@^10.5.1:
-  version "10.10.0"
-  resolved "https://registry.yarnpkg.com/jss/-/jss-10.10.0.tgz#a75cc85b0108c7ac8c7b7d296c520a3e4fbc6ccc"
-  integrity sha512-cqsOTS7jqPsPMjtKYDUpdFC0AbhYFLTcuGRqymgmdJIeQ8cH7+AgX7YSgQy79wXloZq2VvATYxUOUQEvS1V/Zw==
-  dependencies:
-    "@babel/runtime" "^7.3.1"
-    csstype "^3.0.2"
-    is-in-browser "^1.1.3"
-    tiny-warning "^1.0.2"
-
 "jsx-ast-utils@^2.4.1 || ^3.0.0", jsx-ast-utils@^3.3.5:
   version "3.3.5"
   resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz#4766bd05a8e2a11af222becd19e15575e52a853a"
@@ -7765,11 +7564,6 @@ locate-path@^6.0.0:
   dependencies:
     p-locate "^5.0.0"
 
-lodash-es@^4.17.15:
-  version "4.17.21"
-  resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
-  integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
-
 lodash.debounce@^4.0.8:
   version "4.0.8"
   resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
@@ -7800,12 +7594,12 @@ lodash.uniq@^4.5.0:
   resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
   integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
 
-lodash@^4.0.1, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
+lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0:
   version "4.17.21"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
   integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
 
-loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.4.0:
+loose-envify@^1.1.0, loose-envify@^1.4.0:
   version "1.4.0"
   resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
   integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -7866,21 +7660,6 @@ makeerror@1.0.12:
   dependencies:
     tmpl "1.0.5"
 
-material-colors@^1.2.1:
-  version "1.2.6"
-  resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46"
-  integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==
-
-material-ui-color-picker@^3.5.1:
-  version "3.5.1"
-  resolved "https://registry.yarnpkg.com/material-ui-color-picker/-/material-ui-color-picker-3.5.1.tgz#2f33f02a0a22647b135af848662409cad15f56e5"
-  integrity sha512-0mxnmfpl31m6ton13SbwWy3uUqQtmzV0bZl+pEK9lD+4daYB4+FeM05IW0wNU9pAum6JNT7ddYBUQ0tyDA1kvQ==
-  dependencies:
-    "@material-ui/styles" "^4.8.2"
-    prop-types "^15.7.2"
-    react-color "^2.18.0"
-    recompose "^0.30.0"
-
 mdn-data@2.0.14:
   version "2.0.14"
   resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
@@ -8040,6 +7819,13 @@ msgpackr@^1.9.5, msgpackr@^1.9.9:
   optionalDependencies:
     msgpackr-extract "^3.0.2"
 
+mui-color-input@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/mui-color-input/-/mui-color-input-2.0.3.tgz#2bd1595e3b972bf42bd68a4f9ebfc28568d528a0"
+  integrity sha512-rAd040qQ0Y+8dk4gE8kkCiJ/vCgA0j4vv1quJ43BfORTFE3uHarHj0xY1Vo9CPbojtx1f5vW+CjckYPRIZPIRg==
+  dependencies:
+    "@ctrl/tinycolor" "^4.0.3"
+
 multicast-dns@^7.2.5:
   version "7.2.5"
   resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced"
@@ -8100,14 +7886,6 @@ node-addon-api@^7.0.0:
   resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-7.1.0.tgz#71f609369379c08e251c558527a107107b5e0fdb"
   integrity sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g==
 
-node-fetch@^1.0.1:
-  version "1.7.3"
-  resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.3.tgz#980f6f72d85211a5347c6b2bc18c5b84c3eb47ef"
-  integrity sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==
-  dependencies:
-    encoding "^0.1.11"
-    is-stream "^1.0.1"
-
 node-forge@^1:
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"
@@ -8181,7 +7959,7 @@ nwsapi@^2.2.0:
   resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30"
   integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==
 
-object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+object-assign@^4.0.1, object-assign@^4.1.1:
   version "4.1.1"
   resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
   integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
@@ -8542,11 +8320,6 @@ pkg-up@^3.1.0:
   dependencies:
     find-up "^3.0.0"
 
-popper.js@1.16.1-lts:
-  version "1.16.1-lts"
-  resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1-lts.tgz#cf6847b807da3799d80ee3d6d2f90df8a3f50b05"
-  integrity sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==
-
 possible-typed-array-names@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f"
@@ -9180,13 +8953,6 @@ process-nextick-args@~2.0.0:
   resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
   integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
 
-promise@^7.1.1:
-  version "7.3.1"
-  resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"
-  integrity sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==
-  dependencies:
-    asap "~2.0.3"
-
 promise@^8.1.0:
   version "8.3.0"
   resolved "https://registry.yarnpkg.com/promise/-/promise-8.3.0.tgz#8cb333d1edeb61ef23869fbb8a4ea0279ab60e0a"
@@ -9202,7 +8968,7 @@ prompts@^2.0.1, prompts@^2.4.2:
     kleur "^3.0.3"
     sisteransi "^1.0.5"
 
-prop-types@^15.5.10, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1:
+prop-types@^15.6.2, prop-types@^15.8.1:
   version "15.8.1"
   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
   integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@@ -9309,19 +9075,6 @@ react-collapse@^5.1.1:
   resolved "https://registry.yarnpkg.com/react-collapse/-/react-collapse-5.1.1.tgz#a2fa08ef13f372141b02e6a7d49ef72427bcbc2b"
   integrity sha512-k6cd7csF1o9LBhQ4AGBIdxB60SUEUMQDAnL2z1YvYNr9KoKr+nDkhN6FK7uGaBd/rYrYfrMpzpmJEIeHRYogBw==
 
-react-color@^2.18.0:
-  version "2.19.3"
-  resolved "https://registry.yarnpkg.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d"
-  integrity sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==
-  dependencies:
-    "@icons/material" "^0.2.4"
-    lodash "^4.17.15"
-    lodash-es "^4.17.15"
-    material-colors "^1.2.1"
-    prop-types "^15.5.10"
-    reactcss "^1.2.0"
-    tinycolor2 "^1.4.1"
-
 react-dev-utils@^12.0.1:
   version "12.0.1"
   resolved "https://registry.yarnpkg.com/react-dev-utils/-/react-dev-utils-12.0.1.tgz#ba92edb4a1f379bd46ccd6bcd4e7bc398df33e73"
@@ -9375,7 +9128,7 @@ react-is@^16.13.1, react-is@^16.7.0:
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
   integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
 
-"react-is@^16.8.0 || ^17.0.0", react-is@^17.0.1:
+react-is@^17.0.1:
   version "17.0.2"
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0"
   integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==
@@ -9385,11 +9138,6 @@ react-is@^18.0.0, react-is@^18.2.0:
   resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
   integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
 
-react-lifecycles-compat@^3.0.2:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
-  integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
-
 react-refresh@^0.11.0:
   version "0.11.0"
   resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.11.0.tgz#77198b944733f0f1f1a90e791de4541f9f074046"
@@ -9470,7 +9218,7 @@ react-scripts@^5.0.1:
   optionalDependencies:
     fsevents "^2.3.2"
 
-react-transition-group@^4.4.0, react-transition-group@^4.4.5:
+react-transition-group@^4.4.5:
   version "4.4.5"
   resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
   integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
@@ -9487,13 +9235,6 @@ react@^18.2.0:
   dependencies:
     loose-envify "^1.1.0"
 
-reactcss@^1.2.0:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd"
-  integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==
-  dependencies:
-    lodash "^4.0.1"
-
 read-cache@^1.0.0:
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
@@ -9530,18 +9271,6 @@ readdirp@~3.6.0:
   dependencies:
     picomatch "^2.2.1"
 
-recompose@^0.30.0:
-  version "0.30.0"
-  resolved "https://registry.yarnpkg.com/recompose/-/recompose-0.30.0.tgz#82773641b3927e8c7d24a0d87d65aeeba18aabd0"
-  integrity sha512-ZTrzzUDa9AqUIhRk4KmVFihH0rapdCSMFXjhHbNrjAWxBuUD/guYlyysMnuHjlZC/KRiOKRtB4jf96yYSkKE8w==
-  dependencies:
-    "@babel/runtime" "^7.0.0"
-    change-emitter "^0.1.2"
-    fbjs "^0.8.1"
-    hoist-non-react-statics "^2.3.1"
-    react-lifecycles-compat "^3.0.2"
-    symbol-observable "^1.0.4"
-
 recursive-readdir@^2.2.2:
   version "2.2.3"
   resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.2.3.tgz#e726f328c0d69153bcabd5c322d3195252379372"
@@ -9959,11 +9688,6 @@ set-function-name@^2.0.1, set-function-name@^2.0.2:
     functions-have-names "^1.2.3"
     has-property-descriptors "^1.0.2"
 
-setimmediate@^1.0.5:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
-  integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
-
 setprototypeof@1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
@@ -10430,11 +10154,6 @@ svgo@^2.4.0, svgo@^2.7.0:
     picocolors "^1.0.0"
     stable "^0.1.8"
 
-symbol-observable@^1.0.4:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
-  integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
-
 symbol-tree@^3.2.4:
   version "3.2.4"
   resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
@@ -10570,16 +10289,6 @@ timsort@^0.3.0:
   resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"
   integrity sha512-qsdtZH+vMoCARQtyod4imc2nIJwg9Cc7lPRrw9CzF8ZKR0khdr8+2nX80PBhET3tcyTtJDxAffGh2rXH4tyU8A==
 
-tiny-warning@^1.0.2:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754"
-  integrity sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==
-
-tinycolor2@^1.4.1:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e"
-  integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==
-
 tmpl@1.0.5:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
@@ -10756,11 +10465,6 @@ typedarray-to-buffer@^3.1.5:
   dependencies:
     is-typedarray "^1.0.0"
 
-ua-parser-js@^0.7.30:
-  version "0.7.37"
-  resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.37.tgz#e464e66dac2d33a7a1251d7d7a99d6157ec27832"
-  integrity sha512-xV8kqRKM+jhMvcHWUKthV9fNebIzrNy//2O9ZwWcfiBFR5f25XVZPLlEajk/sf3Ra15V92isyQqnIEXRDaZWEA==
-
 unbox-primitive@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e"
@@ -11091,7 +10795,7 @@ whatwg-encoding@^1.0.5:
   dependencies:
     iconv-lite "0.4.24"
 
-whatwg-fetch@>=0.10.0, whatwg-fetch@^3.6.2:
+whatwg-fetch@^3.6.2:
   version "3.6.20"
   resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz#580ce6d791facec91d37c72890995a0b48d31c70"
   integrity sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==