diff --git a/typescript/Frontend/src/App.tsx b/typescript/Frontend/src/App.tsx
index 14e903ff0..fc1a9108c 100644
--- a/typescript/Frontend/src/App.tsx
+++ b/typescript/Frontend/src/App.tsx
@@ -1,7 +1,7 @@
import useToken from "./hooks/useToken";
import Login from "./Login";
import { BrowserRouter, Navigate, Route, Routes } from "react-router-dom";
-import { Grid } from "@mui/material";
+import { Container, Grid } from "@mui/material";
import routes from "./routes.json";
import { IntlProvider } from "react-intl";
import { useState } from "react";
@@ -10,21 +10,23 @@ import de from "./lang/de.json";
import Installations from "./components/Installations/Installations";
import LanguageSelect from "./components/Layout/LanguageSelect";
import LogoutButton from "./components/Layout/LogoutButton";
-import Groups from "./components/Groups/Groups";
+import Users from "./components/Users/Users";
+import NavigationButtons from "./components/Layout/NavigationButtons";
+import InstallationPage from "./components/Installations/InstallationPage";
const App = () => {
const { token, setToken, removeToken } = useToken();
- const [language, setLanguage] = useState("en");
+ const [language, setLanguage] = useState("EN");
const getTranslations = () => {
- if (language === "de") {
+ if (language === "DE") {
return de;
}
return en;
};
if (!token) {
- return ;
+ return ;
}
return (
@@ -32,23 +34,36 @@ const App = () => {
-
-
-
-
-
- }
- />
- }
- />
- } />
-
+
+
+
+
+
+
+
+
+
+
+
+ }
+ />
+ }
+ />
+ } />
+
+
);
diff --git a/typescript/Frontend/src/Login.tsx b/typescript/Frontend/src/Login.tsx
index bd06de185..9bafc45d3 100644
--- a/typescript/Frontend/src/Login.tsx
+++ b/typescript/Frontend/src/Login.tsx
@@ -10,7 +10,12 @@ const loginUser = async (username: string, password: string) => {
});
};
-const Login = ({ setToken }: { setToken: (value: string) => void }) => {
+interface I_LoginProps {
+ setToken: (value: string) => void;
+ setLanguage: (value: string) => void;
+}
+
+const Login = ({ setToken, setLanguage }: I_LoginProps) => {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [loading, setLoading] = useState(false);
@@ -31,6 +36,7 @@ const Login = ({ setToken }: { setToken: (value: string) => void }) => {
.then(() => {
setToken(data.token);
setLoading(false);
+ setLanguage(data.user.language);
})
.catch((err) => {
setError(err);
diff --git a/typescript/Frontend/src/components/Context/UserContextProvider.tsx b/typescript/Frontend/src/components/Context/UserContextProvider.tsx
new file mode 100644
index 000000000..05fd19712
--- /dev/null
+++ b/typescript/Frontend/src/components/Context/UserContextProvider.tsx
@@ -0,0 +1,109 @@
+import {
+ createContext,
+ ReactNode,
+ useCallback,
+ useContext,
+ useEffect,
+ useState,
+} from "react";
+import { useParams } from "react-router-dom";
+import axiosConfig from "../../config/axiosConfig";
+import { I_User, UserWithInheritedAccess } from "../../util/user.util";
+import { GroupContext } from "./GroupContextProvider";
+
+interface UserContextProviderProps {
+ directAccessUsers: I_User[];
+ setDirectAccessUsers: (value: I_User[]) => void;
+ inheritedAccessUsers: UserWithInheritedAccess[];
+ setInheritedAccessUsers: (value: UserWithInheritedAccess[]) => void;
+ availableUsers: I_User[];
+ setAvailableUsers: (value: I_User[]) => void;
+ getAvailableUsers: () => I_User[];
+ fetchUsersWithInheritedAccessForResource: () => Promise;
+ fetchUsersWithDirectAccessForResource: () => Promise;
+}
+
+export const UserContext = createContext({
+ directAccessUsers: [],
+ setDirectAccessUsers: () => {},
+ inheritedAccessUsers: [],
+ setInheritedAccessUsers: () => {},
+ availableUsers: [],
+ setAvailableUsers: () => {},
+ getAvailableUsers: () => {
+ return [];
+ },
+ fetchUsersWithInheritedAccessForResource: () => {
+ return Promise.resolve();
+ },
+ fetchUsersWithDirectAccessForResource: () => {
+ return Promise.resolve();
+ },
+});
+
+const UserContextProvider = ({ children }: { children: ReactNode }) => {
+ const [directAccessUsers, setDirectAccessUsers] = useState([]);
+ const [inheritedAccessUsers, setInheritedAccessUsers] = useState<
+ UserWithInheritedAccess[]
+ >([]);
+ const [availableUsers, setAvailableUsers] = useState([]);
+
+ const { currentType } = useContext(GroupContext);
+ const { id } = useParams();
+
+ const fetchUsers = useCallback(
+ async (route: string, setState: (value: any) => void) => {
+ axiosConfig.get(route + currentType, { params: { id } }).then((res) => {
+ setState(res.data);
+ });
+ },
+ [currentType, id]
+ );
+
+ const fetchUsersWithInheritedAccessForResource = useCallback(async () => {
+ fetchUsers("/GetUsersWithInheritedAccessTo", setInheritedAccessUsers);
+ }, [fetchUsers]);
+
+ const fetchUsersWithDirectAccessForResource = useCallback(async () => {
+ fetchUsers("/GetUsersWithDirectAccessTo", setDirectAccessUsers);
+ }, [fetchUsers]);
+
+ const getAvailableUsersForResource = () => {
+ const inheritedUsers = inheritedAccessUsers.map(
+ (inheritedAccessUser) => inheritedAccessUser.user
+ );
+ const allUsersWithAccess = [...inheritedUsers, ...directAccessUsers];
+ return availableUsers.filter(
+ (availableUser) =>
+ !allUsersWithAccess.find(
+ (userWithAccess) => availableUser.id === userWithAccess.id
+ )
+ );
+ };
+
+ useEffect(() => {
+ axiosConfig.get("/GetAllChildUsers").then((res) => {
+ setAvailableUsers(res.data);
+ });
+ }, []);
+
+ return (
+
+ {children}
+
+ );
+};
+
+export default UserContextProvider;
diff --git a/typescript/Frontend/src/components/Groups/Users/Users.tsx b/typescript/Frontend/src/components/Groups/AccessManagement/AccessManagement.tsx
similarity index 56%
rename from typescript/Frontend/src/components/Groups/Users/Users.tsx
rename to typescript/Frontend/src/components/Groups/AccessManagement/AccessManagement.tsx
index b1b3134be..c35e5d0a9 100644
--- a/typescript/Frontend/src/components/Groups/Users/Users.tsx
+++ b/typescript/Frontend/src/components/Groups/AccessManagement/AccessManagement.tsx
@@ -1,23 +1,24 @@
import { Grid } from "@mui/material";
-import AvailableUserList from "./AvailableUserList";
-import InnovenergyList from "./UserList";
+import UserContextProvider from "../../Context/UserContextProvider";
+import AvailableUserDialog from "./AvailableUserDialog";
+import InnovenergyList from "./InnovenergyList";
import UsersWithDirectAccess from "./UsersWithDirectAccess";
import UsersWithInheritedAccess from "./UsersWithInheritedAccess";
-const Users = () => {
+const AccessManagement = () => {
return (
- <>
-
+
+
- >
+
);
};
-export default Users;
+export default AccessManagement;
diff --git a/typescript/Frontend/src/components/Groups/Users/AvailableUserList.tsx b/typescript/Frontend/src/components/Groups/AccessManagement/AvailableUserDialog.tsx
similarity index 50%
rename from typescript/Frontend/src/components/Groups/Users/AvailableUserList.tsx
rename to typescript/Frontend/src/components/Groups/AccessManagement/AvailableUserDialog.tsx
index d63b0db51..5d46d6bd1 100644
--- a/typescript/Frontend/src/components/Groups/Users/AvailableUserList.tsx
+++ b/typescript/Frontend/src/components/Groups/AccessManagement/AvailableUserDialog.tsx
@@ -1,23 +1,32 @@
-import { Autocomplete, Button, Grid, TextField } from "@mui/material";
-import { useContext, useEffect, useState } from "react";
+import {
+ Autocomplete,
+ Button,
+ Dialog,
+ DialogContent,
+ DialogTitle,
+ TextField,
+} from "@mui/material";
+import DialogActions from "@mui/material/DialogActions";
+import { useContext, useState } from "react";
import { FormattedMessage } from "react-intl";
import { useParams } from "react-router-dom";
import axiosConfig from "../../../config/axiosConfig";
-import { User } from "../../../util/user.util";
+import { I_User } from "../../../util/user.util";
import { GroupContext } from "../../Context/GroupContextProvider";
+import { UserContext } from "../../Context/UserContextProvider";
-const AvailableUserList = () => {
- const [users, setUsers] = useState([]);
- const [selectedUsers, setSelectedUsers] = useState([]);
+const AvailableUserDialog = () => {
+ const [selectedUsers, setSelectedUsers] = useState([]);
+ const [open, setOpen] = useState(false);
const { currentType } = useContext(GroupContext);
const { id } = useParams();
+ const {
+ getAvailableUsers,
+ fetchUsersWithDirectAccessForResource,
+ fetchUsersWithInheritedAccessForResource,
+ } = useContext(UserContext);
- useEffect(() => {
- axiosConfig.get("/GetAllChildUsers").then((res) => {
- setUsers(res.data);
- });
- }, []);
const handleGrant = () => {
selectedUsers.forEach((user) => {
const bodyProp = currentType === "Folder" ? "folderId" : "installationId";
@@ -29,20 +38,32 @@ const AvailableUserList = () => {
: "/GrantUserAccessToInstallation",
{ userId: user.id, [bodyProp]: elementId }
)
- .then((res) => {
- console.log(res);
+ .then(() => {
+ fetchUsersWithDirectAccessForResource();
+ fetchUsersWithInheritedAccessForResource();
});
});
};
- if (users) {
- return (
- <>
-
+
+ return (
+ <>
+
- >
- );
- }
- return null;
+
+
+
+ >
+ );
};
-export default AvailableUserList;
+export default AvailableUserDialog;
diff --git a/typescript/Frontend/src/components/Groups/Users/UserList.tsx b/typescript/Frontend/src/components/Groups/AccessManagement/InnovenergyList.tsx
similarity index 100%
rename from typescript/Frontend/src/components/Groups/Users/UserList.tsx
rename to typescript/Frontend/src/components/Groups/AccessManagement/InnovenergyList.tsx
diff --git a/typescript/Frontend/src/components/Groups/Users/UsersWithDirectAccess.tsx b/typescript/Frontend/src/components/Groups/AccessManagement/UsersWithDirectAccess.tsx
similarity index 75%
rename from typescript/Frontend/src/components/Groups/Users/UsersWithDirectAccess.tsx
rename to typescript/Frontend/src/components/Groups/AccessManagement/UsersWithDirectAccess.tsx
index 18587a27b..14383a4b8 100644
--- a/typescript/Frontend/src/components/Groups/Users/UsersWithDirectAccess.tsx
+++ b/typescript/Frontend/src/components/Groups/AccessManagement/UsersWithDirectAccess.tsx
@@ -6,31 +6,23 @@ import {
Avatar,
ListItemAvatar,
} from "@mui/material";
-import { Fragment, useCallback, useContext, useEffect, useState } from "react";
+import { Fragment, useContext, useEffect } from "react";
import axiosConfig from "../../../config/axiosConfig";
-import { User } from "../../../util/user.util";
import PersonRemoveIcon from "@mui/icons-material/PersonRemove";
-import { GroupContext } from "../../Context/GroupContextProvider";
-import { useParams } from "react-router-dom";
import PersonIcon from "@mui/icons-material/Person";
+import { UserContext } from "../../Context/UserContextProvider";
+import { useParams } from "react-router-dom";
+import { GroupContext } from "../../Context/GroupContextProvider";
const UsersWithDirectAccess = () => {
- const [users, setUsers] = useState();
-
+ const { fetchUsersWithDirectAccessForResource, directAccessUsers } =
+ useContext(UserContext);
const { currentType } = useContext(GroupContext);
const { id } = useParams();
- const fetchUsers = useCallback(async () => {
- axiosConfig
- .get("/GetUsersWithDirectAccessTo" + currentType, { params: { id } })
- .then((res) => {
- setUsers(res.data);
- });
- }, [currentType, id]);
-
useEffect(() => {
- fetchUsers();
- }, [fetchUsers]);
+ fetchUsersWithDirectAccessForResource();
+ }, [fetchUsersWithDirectAccessForResource]);
const handleIconClick = (userId: number) => {
const folderId = id ? parseInt(id) : "";
@@ -40,14 +32,14 @@ const UsersWithDirectAccess = () => {
folderId: folderId,
})
.then((res) => {
- fetchUsers();
+ fetchUsersWithDirectAccessForResource();
});
};
- if (users && users.length) {
+ if (directAccessUsers && directAccessUsers.length) {
return (
<>
- {users.map((user) => {
+ {directAccessUsers.map((user) => {
return (
{
- const [users, setUsers] = useState();
-
- const { currentType } = useContext(GroupContext);
- const { id } = useParams();
-
- const fetchUsers = useCallback(async () => {
- axiosConfig
- .get("/GetUsersWithInheritedAccessTo" + currentType, { params: { id } })
- .then((res) => {
- setUsers(res.data);
- });
- }, [currentType, id]);
+ const { fetchUsersWithInheritedAccessForResource, inheritedAccessUsers } =
+ useContext(UserContext);
useEffect(() => {
- fetchUsers();
- }, [fetchUsers]);
+ fetchUsersWithInheritedAccessForResource();
+ }, [fetchUsersWithInheritedAccessForResource]);
- if (users && users.length) {
+ if (inheritedAccessUsers && inheritedAccessUsers.length) {
return (
<>
- {filterDuplicateUsers(users).map(
+ {filterDuplicateUsers(inheritedAccessUsers).map(
({ user, folderName }: UserWithInheritedAccess) => {
return (
@@ -52,7 +41,11 @@ const UsersWithInheritedAccess = () => {
secondary={
<>
Inherited access from{" "}
-
+
{folderName}
>
diff --git a/typescript/Frontend/src/components/Groups/AddNewDialog.tsx b/typescript/Frontend/src/components/Groups/AddNewDialog.tsx
new file mode 100644
index 000000000..6af3b2465
--- /dev/null
+++ b/typescript/Frontend/src/components/Groups/AddNewDialog.tsx
@@ -0,0 +1,46 @@
+import { Button, Dialog, DialogContent, DialogTitle } from "@mui/material";
+import { useState } from "react";
+import { FormattedMessage } from "react-intl";
+import axiosConfig from "../../config/axiosConfig";
+import { I_Folder } from "../../util/types";
+import FolderForm from "./FolderForm";
+
+interface AddNewDialogProps {
+ values: I_Folder;
+}
+
+const AddNewDialog = (props: AddNewDialogProps) => {
+ const [open, setOpen] = useState(false);
+
+ const handleSubmit = (data: I_Folder, childData: Partial) => {
+ return axiosConfig.post("/CreateFolder", {
+ ...childData,
+ parentId: data.id,
+ });
+ };
+
+ return (
+ <>
+
+
+ >
+ );
+};
+
+export default AddNewDialog;
diff --git a/typescript/Frontend/src/components/Groups/Folder.tsx b/typescript/Frontend/src/components/Groups/Folder.tsx
index 3215d7564..457eff010 100644
--- a/typescript/Frontend/src/components/Groups/Folder.tsx
+++ b/typescript/Frontend/src/components/Groups/Folder.tsx
@@ -3,12 +3,14 @@ import { AxiosError } from "axios";
import { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import axiosConfig from "../../config/axiosConfig";
-import { I_Installation } from "../../util/types";
+import { I_Folder } from "../../util/types";
+import AddNewDialog from "./AddNewDialog";
import FolderForm from "./FolderForm";
+import MoveDialog from "./Tree/MoveDialog";
const Folder = () => {
const { id } = useParams();
- const [values, setValues] = useState();
+ const [values, setValues] = useState();
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
@@ -26,11 +28,22 @@ const Folder = () => {
});
}, [id]);
+ const handleSubmit = (data: I_Folder, formikValues: Partial) => {
+ return axiosConfig.put("/UpdateFolder", { ...data, ...formikValues });
+ };
+
if (values && values.id && values.id.toString() === id) {
+ const moveDialog = ;
+ const addNewDialog = ;
+
return (
<>
-
+
>
);
diff --git a/typescript/Frontend/src/components/Groups/FolderForm.tsx b/typescript/Frontend/src/components/Groups/FolderForm.tsx
index 26852bce8..6d612b425 100644
--- a/typescript/Frontend/src/components/Groups/FolderForm.tsx
+++ b/typescript/Frontend/src/components/Groups/FolderForm.tsx
@@ -1,25 +1,24 @@
import { Button, CircularProgress, Grid } from "@mui/material";
+import { AxiosResponse } from "axios";
import { useFormik } from "formik";
-import { useContext, useState } from "react";
+import { ReactNode, useContext, useState } from "react";
import { FormattedMessage, useIntl } from "react-intl";
-import axiosConfig from "../../config/axiosConfig";
import { I_Folder } from "../../util/types";
import { GroupContext } from "../Context/GroupContextProvider";
import InnovenergySnackbar from "../InnovenergySnackbar";
import InnovenergyTextfield from "../Layout/InnovenergyTextfield";
-import MoveDialog from "./Tree/MoveDialog";
interface I_CustomerFormProps {
values: I_Folder;
- id: string;
+ handleSubmit: (
+ data: I_Folder,
+ formikValues: Partial
+ ) => Promise;
+ additionalButtons?: ReactNode[];
}
-const updateFolder = (data: I_Folder) => {
- return axiosConfig.put("/UpdateFolder", data);
-};
-
const FolderForm = (props: I_CustomerFormProps) => {
- const { values, id } = props;
+ const { values, additionalButtons, handleSubmit } = props;
const intl = useIntl();
const { fetchData } = useContext(GroupContext);
@@ -34,14 +33,8 @@ const FolderForm = (props: I_CustomerFormProps) => {
},
onSubmit: (formikValues) => {
setLoading(true);
- const idAsNumber = parseInt(id, 10);
- updateFolder({
- ...values,
- ...formikValues,
- id: idAsNumber,
- })
- .then((res) => {
- // TODO figure out why this isnt refreshing tree
+ handleSubmit(values, formikValues)
+ .then(() => {
fetchData();
setSnackbarOpen(true);
setLoading(false);
@@ -79,12 +72,9 @@ const FolderForm = (props: I_CustomerFormProps) => {
/>
{loading && }
-
+ {additionalButtons && additionalButtons.map((button) => button)}
{
const routeMatch = useRouteMatch([
routes.groups + routes.folder + ":id",
- routes.groups + routes.users + ":id",
+ routes.groups + routes.manageAccess + ":id",
routes.groups + routes.installation + ":id",
]);
const id = routeMatch?.params?.id;
const intl = useIntl();
- const { currentType } = React.useContext(GroupContext);
+ const { currentType } = useContext(GroupContext);
if (id) {
return (
-
{currentType === "Folder" ? (
- {
to={routes.folder + id}
/>
) : (
- {
/>
)}
-
-
+
);
diff --git a/typescript/Frontend/src/components/Groups/Groups.tsx b/typescript/Frontend/src/components/Groups/Groups.tsx
index e1a80f23a..b715275c2 100644
--- a/typescript/Frontend/src/components/Groups/Groups.tsx
+++ b/typescript/Frontend/src/components/Groups/Groups.tsx
@@ -2,36 +2,43 @@ import { Grid } from "@mui/material";
import { Container } from "@mui/system";
import { Routes, Route } from "react-router";
import routes from "../../routes.json";
-import Installation from "../Installations/Installation";
import Folder from "./Folder";
import GroupTabs from "./GroupTabs";
import GroupContextProvider from "../Context/GroupContextProvider";
import GroupTree from "./Tree/GroupTree";
import NavigationButtons from "../Layout/NavigationButtons";
-import Users from "./Users/Users";
+import AccessManagement from "./AccessManagement/AccessManagement";
+import { I_Installation } from "../../util/types";
+import InstallationForm from "../Installations/InstallationForm";
+import Detail from "../Layout/Detail";
const Groups = () => {
return (
-
-
-
-
-
-
-
-
-
- } index />
- } />
- }
- />
-
-
+
+
+
-
+
+
+
+ } index />
+ }
+ />
+
+ route="/GetInstallationById?id="
+ formComponent={InstallationForm}
+ />
+ }
+ />
+
+
+
);
};
diff --git a/typescript/Frontend/src/components/Installations/CustomerForm.tsx b/typescript/Frontend/src/components/Installations/InstallationForm.tsx
similarity index 93%
rename from typescript/Frontend/src/components/Installations/CustomerForm.tsx
rename to typescript/Frontend/src/components/Installations/InstallationForm.tsx
index 4be46703b..638f9bdd7 100644
--- a/typescript/Frontend/src/components/Installations/CustomerForm.tsx
+++ b/typescript/Frontend/src/components/Installations/InstallationForm.tsx
@@ -4,13 +4,14 @@ import { useState } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import axiosConfig from "../../config/axiosConfig";
import { I_Installation } from "../../util/types";
+import MoveDialog from "../Groups/Tree/MoveDialog";
import InnovenergyTextfield from "../Layout/InnovenergyTextfield";
-interface I_CustomerFormProps {
+interface I_InstallationFormProps {
values: I_Installation;
id: string | undefined;
}
-const CustomerForm = (props: I_CustomerFormProps) => {
+const InstallationForm = (props: I_InstallationFormProps) => {
const { values, id } = props;
const [open, setOpen] = useState(false);
@@ -93,6 +94,7 @@ const CustomerForm = (props: I_CustomerFormProps) => {
handleChange={formik.handleChange}
/>
+
@@ -117,4 +119,4 @@ const CustomerForm = (props: I_CustomerFormProps) => {
);
};
-export default CustomerForm;
+export default InstallationForm;
diff --git a/typescript/Frontend/src/components/Installations/InstallationList.tsx b/typescript/Frontend/src/components/Installations/InstallationList.tsx
index 602f94fb6..d110f5cc2 100644
--- a/typescript/Frontend/src/components/Installations/InstallationList.tsx
+++ b/typescript/Frontend/src/components/Installations/InstallationList.tsx
@@ -43,7 +43,6 @@ const InstallationList = (props: InstallationListProps) => {
const routeMatch = useRouteMatch([
routes.installations + routes.installation + ":id",
routes.installations + routes.alarms + ":id",
- routes.installations + routes.users + ":id",
routes.installations + routes.log + ":id",
]);
diff --git a/typescript/Frontend/src/components/Installations/InstallationPage.tsx b/typescript/Frontend/src/components/Installations/InstallationPage.tsx
new file mode 100644
index 000000000..7650d1d67
--- /dev/null
+++ b/typescript/Frontend/src/components/Installations/InstallationPage.tsx
@@ -0,0 +1,23 @@
+import { Route, Routes } from "react-router-dom";
+import Groups from "../Groups/Groups";
+import ModeButtons from "../Layout/ModeButtons";
+import Installations from "./Installations";
+import routes from "../../routes.json";
+import { Grid } from "@mui/material";
+
+const InstallationPage = () => {
+ return (
+ <>
+
+
+
+
+
+
+ } />
+ } />
+
+ >
+ );
+};
+export default InstallationPage;
diff --git a/typescript/Frontend/src/components/Installations/InstallationTabs.tsx b/typescript/Frontend/src/components/Installations/InstallationTabs.tsx
index 1b56e574d..273173287 100644
--- a/typescript/Frontend/src/components/Installations/InstallationTabs.tsx
+++ b/typescript/Frontend/src/components/Installations/InstallationTabs.tsx
@@ -2,17 +2,18 @@ import * as React from "react";
import Tabs from "@mui/material/Tabs";
import Tab from "@mui/material/Tab";
import Box from "@mui/material/Box";
-import { Link } from "react-router-dom";
+import { Link, Routes } from "react-router-dom";
import routes from "../../routes.json";
import useRouteMatch from "../../hooks/useRouteMatch";
import { useIntl } from "react-intl";
+import { styled } from "@mui/material";
+import { AntTabs, StyledTab } from "../../util/installation.util";
const InstallationTabs = () => {
const routeMatch = useRouteMatch([
- routes.installations + routes.installation + ":id",
- routes.installations + routes.alarms + ":id",
- routes.installations + routes.users + ":id",
- routes.installations + routes.log + ":id",
+ routes.installations + routes.list + routes.installation + ":id",
+ routes.installations + routes.list + routes.alarms + ":id",
+ routes.installations + routes.list + routes.log + ":id",
]);
const id = routeMatch?.params?.id;
@@ -22,47 +23,40 @@ const InstallationTabs = () => {
return (
-
-
-
-
-
-
+
);
diff --git a/typescript/Frontend/src/components/Installations/Installations.tsx b/typescript/Frontend/src/components/Installations/Installations.tsx
index c78588d83..703c9abda 100644
--- a/typescript/Frontend/src/components/Installations/Installations.tsx
+++ b/typescript/Frontend/src/components/Installations/Installations.tsx
@@ -3,38 +3,40 @@ import { Container } from "@mui/system";
import { Routes, Route } from "react-router";
import NavigationButtons from "../Layout/NavigationButtons";
import Sidebar from "../Layout/Sidebar";
-import BasicTable from "../Layout/Table";
import Alarms from "./Alarms";
-import Installation from "./Installation";
import InstallationTabs from "./InstallationTabs";
import Log from "./Log";
import routes from "../../routes.json";
import InstallationContextProvider from "../Context/InstallationContextProvider";
+import Detail from "../Layout/Detail";
+import { I_Installation } from "../../util/types";
+import InstallationForm from "./InstallationForm";
const Installations = () => {
return (
-
-
-
-
-
-
-
-
-
- }
- index
- />
- } />
- } />
- } />
-
-
+
+
+
-
+
+
+
+
+ route="/GetInstallationById?id="
+ formComponent={InstallationForm}
+ />
+ }
+ index
+ />
+ } />
+ } />
+
+
+
);
};
diff --git a/typescript/Frontend/src/components/Installations/Installation.tsx b/typescript/Frontend/src/components/Layout/Detail.tsx
similarity index 61%
rename from typescript/Frontend/src/components/Installations/Installation.tsx
rename to typescript/Frontend/src/components/Layout/Detail.tsx
index 85432d2e3..33823cca1 100644
--- a/typescript/Frontend/src/components/Installations/Installation.tsx
+++ b/typescript/Frontend/src/components/Layout/Detail.tsx
@@ -1,22 +1,27 @@
-import { Alert, Box, CircularProgress } from "@mui/material";
+import { Box, CircularProgress, Alert } from "@mui/material";
import { AxiosError } from "axios";
-import { useEffect, useState } from "react";
+import { useState, useEffect, FC } from "react";
import { useParams } from "react-router-dom";
-import CustomerForm from "./CustomerForm";
import axiosConfig from "../../config/axiosConfig";
-import { I_Installation } from "../../util/types";
-import LocationForm from "../Groups/LocationForm";
-
-const Installation = () => {
+export interface I_FormProps {
+ values: T;
+ id: string;
+}
+interface I_DetailProps {
+ formComponent: FC>;
+ route: string;
+}
+const Detail = (props: I_DetailProps) => {
const { id } = useParams();
- const [values, setValues] = useState();
+ const { formComponent: FormComponent, route } = props;
+ const [values, setValues] = useState();
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
useEffect(() => {
setLoading(true);
axiosConfig
- .get("/GetInstallationById?id=" + id)
+ .get(route + id)
.then((res) => {
setValues(res.data);
setLoading(false);
@@ -25,15 +30,10 @@ const Installation = () => {
setError(err);
setLoading(false);
});
- }, [id]);
+ }, [id, route]);
if (values && values.id && values.id.toString() === id) {
- return (
-
-
-
-
- );
+ return ;
} else if (loading) {
return (
{
return null;
};
-export default Installation;
+export default Detail;
diff --git a/typescript/Frontend/src/components/Layout/LanguageSelect.tsx b/typescript/Frontend/src/components/Layout/LanguageSelect.tsx
index 6349befc0..ef466afb8 100644
--- a/typescript/Frontend/src/components/Layout/LanguageSelect.tsx
+++ b/typescript/Frontend/src/components/Layout/LanguageSelect.tsx
@@ -14,10 +14,10 @@ const LanguageSelect = (props: LanguageSelectProps) => {
label="Age"
onChange={(e) => props.setLanguage(e.target.value)}
>
-