add loading indicators, clean up code, add user tree prototype

This commit is contained in:
Sina Blattmann 2023-02-24 13:31:53 +01:00
parent 633c3de5bc
commit cc31922ba4
11 changed files with 484 additions and 207 deletions

View File

@ -11,6 +11,7 @@
"@emotion/react": "^11.10.5", "@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5", "@emotion/styled": "^11.10.5",
"@mui/icons-material": "^5.11.0", "@mui/icons-material": "^5.11.0",
"@mui/lab": "^5.0.0-alpha.120",
"@mui/material": "^5.11.7", "@mui/material": "^5.11.7",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",
@ -3256,6 +3257,79 @@
} }
} }
}, },
"node_modules/@mui/lab": {
"version": "5.0.0-alpha.120",
"resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.120.tgz",
"integrity": "sha512-vjlF2jTKSZnNxtUO0xxHEDfpL5cG0LLNRsfKv8TYOiPs0Q1bbqO3YfqJsqxv8yh+wx7EFZc8lwJ4NSAQdenW3A==",
"dependencies": {
"@babel/runtime": "^7.20.13",
"@mui/base": "5.0.0-alpha.118",
"@mui/system": "^5.11.9",
"@mui/types": "^7.2.3",
"@mui/utils": "^5.11.9",
"clsx": "^1.2.1",
"prop-types": "^15.8.1",
"react-is": "^18.2.0"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui"
},
"peerDependencies": {
"@emotion/react": "^11.5.0",
"@emotion/styled": "^11.3.0",
"@mui/material": "^5.0.0",
"@types/react": "^17.0.0 || ^18.0.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@emotion/react": {
"optional": true
},
"@emotion/styled": {
"optional": true
},
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/lab/node_modules/@mui/base": {
"version": "5.0.0-alpha.118",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.118.tgz",
"integrity": "sha512-GAEpqhnuHjRaAZLdxFNuOf2GDTp9sUawM46oHZV4VnYPFjXJDkIYFWfIQLONb0nga92OiqS5DD/scGzVKCL0Mw==",
"dependencies": {
"@babel/runtime": "^7.20.13",
"@emotion/is-prop-valid": "^1.2.0",
"@mui/types": "^7.2.3",
"@mui/utils": "^5.11.9",
"@popperjs/core": "^2.11.6",
"clsx": "^1.2.1",
"prop-types": "^15.8.1",
"react-is": "^18.2.0"
},
"engines": {
"node": ">=12.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/mui"
},
"peerDependencies": {
"@types/react": "^17.0.0 || ^18.0.0",
"react": "^17.0.0 || ^18.0.0",
"react-dom": "^17.0.0 || ^18.0.0"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
}
}
},
"node_modules/@mui/material": { "node_modules/@mui/material": {
"version": "5.11.8", "version": "5.11.8",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.8.tgz", "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.8.tgz",
@ -3301,12 +3375,12 @@
} }
}, },
"node_modules/@mui/private-theming": { "node_modules/@mui/private-theming": {
"version": "5.11.7", "version": "5.11.9",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.7.tgz", "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.9.tgz",
"integrity": "sha512-XzRTSZdc8bhuUdjablTNv3kFkZ/XIMlKkOqqJCU0G8W3tWGXpau2DXkafPd1ddjPhF9zF3qLKNGgKCChYItjgA==", "integrity": "sha512-XMyVIFGomVCmCm92EvYlgq3zrC9K+J6r7IKl/rBJT2/xVYoRY6uM7jeB+Wxh7kXxnW9Dbqsr2yL3cx6wSD1sAg==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.7", "@babel/runtime": "^7.20.13",
"@mui/utils": "^5.11.7", "@mui/utils": "^5.11.9",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
}, },
"engines": { "engines": {
@ -3327,11 +3401,11 @@
} }
}, },
"node_modules/@mui/styled-engine": { "node_modules/@mui/styled-engine": {
"version": "5.11.8", "version": "5.11.9",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.8.tgz", "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.9.tgz",
"integrity": "sha512-iSpZp9AoeictsDi5xAQ4PGXu7mKtQyzMl7ZaWpHIGMFpsNnfY3NQNg+wkj/gpsAZ+Zg+IIyD+t+ig71Kr9fa0w==", "integrity": "sha512-bkh2CjHKOMy98HyOc8wQXEZvhOmDa/bhxMUekFX5IG0/w4f5HJ8R6+K6nakUUYNEgjOWPYzNPrvGB8EcGbhahQ==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.7", "@babel/runtime": "^7.20.13",
"@emotion/cache": "^11.10.5", "@emotion/cache": "^11.10.5",
"csstype": "^3.1.1", "csstype": "^3.1.1",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
@ -3358,15 +3432,15 @@
} }
}, },
"node_modules/@mui/system": { "node_modules/@mui/system": {
"version": "5.11.8", "version": "5.11.9",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.8.tgz", "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.9.tgz",
"integrity": "sha512-zhroUcxAw2x/dISBJKhGbD70DOYCwMFRo7o/LUYTiUfQkfmLhRfEf1bopWgY9nYstn7QOxOq9fA3aR3pHrUTbw==", "integrity": "sha512-h6uarf+l3FO6l75Nf7yO+qDGrIoa1DM9nAMCUFZQsNCDKOInRzcptnm8M1w/Z3gVetfeeGoIGAYuYKbft6KZZA==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.7", "@babel/runtime": "^7.20.13",
"@mui/private-theming": "^5.11.7", "@mui/private-theming": "^5.11.9",
"@mui/styled-engine": "^5.11.8", "@mui/styled-engine": "^5.11.9",
"@mui/types": "^7.2.3", "@mui/types": "^7.2.3",
"@mui/utils": "^5.11.7", "@mui/utils": "^5.11.9",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"csstype": "^3.1.1", "csstype": "^3.1.1",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
@ -3410,11 +3484,11 @@
} }
}, },
"node_modules/@mui/utils": { "node_modules/@mui/utils": {
"version": "5.11.7", "version": "5.11.9",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.7.tgz", "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.9.tgz",
"integrity": "sha512-8uyNDeVHZA804Ego20Erv8TpxlbqTe/EbhTI2H1UYr4/RiIbBprat8W4Qqr2UQIsC/b3DLz+0RQ6R/E5BxEcLA==", "integrity": "sha512-eOJaqzcEs4qEwolcvFAmXGpln+uvouvOS9FUX6Wkrte+4I8rZbjODOBDVNlK+V6/ziTfD4iNKC0G+KfOTApbqg==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.7", "@babel/runtime": "^7.20.13",
"@types/prop-types": "^15.7.5", "@types/prop-types": "^15.7.5",
"@types/react-is": "^16.7.1 || ^17.0.0", "@types/react-is": "^16.7.1 || ^17.0.0",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
@ -20422,6 +20496,38 @@
"@babel/runtime": "^7.20.6" "@babel/runtime": "^7.20.6"
} }
}, },
"@mui/lab": {
"version": "5.0.0-alpha.120",
"resolved": "https://registry.npmjs.org/@mui/lab/-/lab-5.0.0-alpha.120.tgz",
"integrity": "sha512-vjlF2jTKSZnNxtUO0xxHEDfpL5cG0LLNRsfKv8TYOiPs0Q1bbqO3YfqJsqxv8yh+wx7EFZc8lwJ4NSAQdenW3A==",
"requires": {
"@babel/runtime": "^7.20.13",
"@mui/base": "5.0.0-alpha.118",
"@mui/system": "^5.11.9",
"@mui/types": "^7.2.3",
"@mui/utils": "^5.11.9",
"clsx": "^1.2.1",
"prop-types": "^15.8.1",
"react-is": "^18.2.0"
},
"dependencies": {
"@mui/base": {
"version": "5.0.0-alpha.118",
"resolved": "https://registry.npmjs.org/@mui/base/-/base-5.0.0-alpha.118.tgz",
"integrity": "sha512-GAEpqhnuHjRaAZLdxFNuOf2GDTp9sUawM46oHZV4VnYPFjXJDkIYFWfIQLONb0nga92OiqS5DD/scGzVKCL0Mw==",
"requires": {
"@babel/runtime": "^7.20.13",
"@emotion/is-prop-valid": "^1.2.0",
"@mui/types": "^7.2.3",
"@mui/utils": "^5.11.9",
"@popperjs/core": "^2.11.6",
"clsx": "^1.2.1",
"prop-types": "^15.8.1",
"react-is": "^18.2.0"
}
}
}
},
"@mui/material": { "@mui/material": {
"version": "5.11.8", "version": "5.11.8",
"resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.8.tgz", "resolved": "https://registry.npmjs.org/@mui/material/-/material-5.11.8.tgz",
@ -20442,36 +20548,36 @@
} }
}, },
"@mui/private-theming": { "@mui/private-theming": {
"version": "5.11.7", "version": "5.11.9",
"resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.7.tgz", "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-5.11.9.tgz",
"integrity": "sha512-XzRTSZdc8bhuUdjablTNv3kFkZ/XIMlKkOqqJCU0G8W3tWGXpau2DXkafPd1ddjPhF9zF3qLKNGgKCChYItjgA==", "integrity": "sha512-XMyVIFGomVCmCm92EvYlgq3zrC9K+J6r7IKl/rBJT2/xVYoRY6uM7jeB+Wxh7kXxnW9Dbqsr2yL3cx6wSD1sAg==",
"requires": { "requires": {
"@babel/runtime": "^7.20.7", "@babel/runtime": "^7.20.13",
"@mui/utils": "^5.11.7", "@mui/utils": "^5.11.9",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
} }
}, },
"@mui/styled-engine": { "@mui/styled-engine": {
"version": "5.11.8", "version": "5.11.9",
"resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.8.tgz", "resolved": "https://registry.npmjs.org/@mui/styled-engine/-/styled-engine-5.11.9.tgz",
"integrity": "sha512-iSpZp9AoeictsDi5xAQ4PGXu7mKtQyzMl7ZaWpHIGMFpsNnfY3NQNg+wkj/gpsAZ+Zg+IIyD+t+ig71Kr9fa0w==", "integrity": "sha512-bkh2CjHKOMy98HyOc8wQXEZvhOmDa/bhxMUekFX5IG0/w4f5HJ8R6+K6nakUUYNEgjOWPYzNPrvGB8EcGbhahQ==",
"requires": { "requires": {
"@babel/runtime": "^7.20.7", "@babel/runtime": "^7.20.13",
"@emotion/cache": "^11.10.5", "@emotion/cache": "^11.10.5",
"csstype": "^3.1.1", "csstype": "^3.1.1",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
} }
}, },
"@mui/system": { "@mui/system": {
"version": "5.11.8", "version": "5.11.9",
"resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.8.tgz", "resolved": "https://registry.npmjs.org/@mui/system/-/system-5.11.9.tgz",
"integrity": "sha512-zhroUcxAw2x/dISBJKhGbD70DOYCwMFRo7o/LUYTiUfQkfmLhRfEf1bopWgY9nYstn7QOxOq9fA3aR3pHrUTbw==", "integrity": "sha512-h6uarf+l3FO6l75Nf7yO+qDGrIoa1DM9nAMCUFZQsNCDKOInRzcptnm8M1w/Z3gVetfeeGoIGAYuYKbft6KZZA==",
"requires": { "requires": {
"@babel/runtime": "^7.20.7", "@babel/runtime": "^7.20.13",
"@mui/private-theming": "^5.11.7", "@mui/private-theming": "^5.11.9",
"@mui/styled-engine": "^5.11.8", "@mui/styled-engine": "^5.11.9",
"@mui/types": "^7.2.3", "@mui/types": "^7.2.3",
"@mui/utils": "^5.11.7", "@mui/utils": "^5.11.9",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"csstype": "^3.1.1", "csstype": "^3.1.1",
"prop-types": "^15.8.1" "prop-types": "^15.8.1"
@ -20484,11 +20590,11 @@
"requires": {} "requires": {}
}, },
"@mui/utils": { "@mui/utils": {
"version": "5.11.7", "version": "5.11.9",
"resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.7.tgz", "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-5.11.9.tgz",
"integrity": "sha512-8uyNDeVHZA804Ego20Erv8TpxlbqTe/EbhTI2H1UYr4/RiIbBprat8W4Qqr2UQIsC/b3DLz+0RQ6R/E5BxEcLA==", "integrity": "sha512-eOJaqzcEs4qEwolcvFAmXGpln+uvouvOS9FUX6Wkrte+4I8rZbjODOBDVNlK+V6/ziTfD4iNKC0G+KfOTApbqg==",
"requires": { "requires": {
"@babel/runtime": "^7.20.7", "@babel/runtime": "^7.20.13",
"@types/prop-types": "^15.7.5", "@types/prop-types": "^15.7.5",
"@types/react-is": "^16.7.1 || ^17.0.0", "@types/react-is": "^16.7.1 || ^17.0.0",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",

View File

@ -6,6 +6,7 @@
"@emotion/react": "^11.10.5", "@emotion/react": "^11.10.5",
"@emotion/styled": "^11.10.5", "@emotion/styled": "^11.10.5",
"@mui/icons-material": "^5.11.0", "@mui/icons-material": "^5.11.0",
"@mui/lab": "^5.0.0-alpha.120",
"@mui/material": "^5.11.7", "@mui/material": "^5.11.7",
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^13.4.0",

View File

@ -1,8 +1,7 @@
import useToken from "./hooks/useToken"; import useToken from "./hooks/useToken";
import Login from "./Login"; import Login from "./Login";
import { BrowserRouter, Route, Routes } from "react-router-dom"; import { BrowserRouter, Route, Routes } from "react-router-dom";
import { Box, Grid, Divider, createTheme, ThemeProvider } from "@mui/material"; import { Box, Grid, Divider } from "@mui/material";
import InstallationList from "./components/InstallationList";
import BasicTable from "./components/Table"; import BasicTable from "./components/Table";
import InstallationTabs from "./components/InstallationTabs"; import InstallationTabs from "./components/InstallationTabs";
import Alarms from "./routes/Alarms"; import Alarms from "./routes/Alarms";
@ -17,20 +16,13 @@ import LanguageSelect from "./components/LanguageSelect";
import LogoutButton from "./components/LogoutButton"; import LogoutButton from "./components/LogoutButton";
import NavigationButtons from "./components/NavigationButtons"; import NavigationButtons from "./components/NavigationButtons";
import UserList from "./components/UserTree"; import UserList from "./components/UserTree";
import Sidebar from "./components/Sidebar";
const App = () => { const App = () => {
const { token, setToken, removeToken } = useToken(); const { token, setToken, removeToken } = useToken();
const [language, setLanguage] = useState("en"); const [language, setLanguage] = useState("en");
const [currentView, setCurrentView] = useState("installations"); const [currentView, setCurrentView] = useState("installations");
const theme = createTheme({
palette: {
primary: {
main: "#F59100",
},
},
});
const getTranslations = () => { const getTranslations = () => {
if (language === "de") { if (language === "de") {
return de; return de;
@ -44,62 +36,53 @@ const App = () => {
return ( return (
<BrowserRouter> <BrowserRouter>
<ThemeProvider theme={theme}> <IntlProvider
<IntlProvider messages={getTranslations()}
messages={getTranslations()} locale={language}
locale={language} defaultLocale="en"
defaultLocale="en" >
> <Grid container justifyContent="flex-end" sx={{ px: 1, pt: 1 }}>
<Grid container justifyContent="flex-end" sx={{ px: 1, pt: 1 }}> <LanguageSelect language={language} setLanguage={setLanguage} />
<LanguageSelect language={language} setLanguage={setLanguage} /> <LogoutButton removeToken={removeToken} />
<LogoutButton removeToken={removeToken} /> </Grid>
</Grid> <Box sx={{ p: 1 }}>
<Box sx={{ p: 1 }}> <Grid container spacing={2}>
<Grid container spacing={2}> <Grid item xs={3}>
<Grid item xs={3}> <NavigationButtons
<NavigationButtons currentView={currentView}
currentView={currentView} setCurrentView={setCurrentView}
setCurrentView={setCurrentView} />
/> {currentView === "installations" ? <Sidebar /> : <UserList />}
{currentView === "installations" ? (
<InstallationList />
) : (
<UserList />
)}
</Grid>
<Grid
item
xs={1}
container
direction="row"
justifyContent="center"
alignItems="center"
>
<Divider orientation="vertical" variant="middle" />
</Grid>
<Grid item xs={8}>
{currentView === "installations" && (
<>
<InstallationTabs />
<Routes>
<Route
path={routes.installationWithId}
element={<InstallationDetail />}
/>
<Route path={routes.alarmsWithId} element={<Alarms />} />
<Route
path={routes.usersWithId}
element={<BasicTable />}
/>
<Route path={routes.logWithId} element={<Log />} />
</Routes>
</>
)}
</Grid>
</Grid> </Grid>
</Box> <Grid
</IntlProvider> item
</ThemeProvider> xs={1}
container
direction="row"
justifyContent="center"
alignItems="center"
>
<Divider orientation="vertical" variant="middle" />
</Grid>
<Grid item xs={8}>
{currentView === "installations" && (
<>
<InstallationTabs />
<Routes>
<Route
path={routes.installationWithId}
element={<InstallationDetail />}
/>
<Route path={routes.alarmsWithId} element={<Alarms />} />
<Route path={routes.usersWithId} element={<BasicTable />} />
<Route path={routes.logWithId} element={<Log />} />
</Routes>
</>
)}
</Grid>
</Grid>
</Box>
</IntlProvider>
</BrowserRouter> </BrowserRouter>
); );
}; };

View File

@ -1,9 +1,9 @@
import { Alert, Button, Grid, InputLabel, Snackbar } from "@mui/material"; import { Alert, Button, Grid, Snackbar } from "@mui/material";
import { useFormik } from "formik"; import { useFormik } from "formik";
import { useState } from "react"; import { useState } from "react";
import { FormattedMessage, useIntl } from "react-intl"; import { FormattedMessage, useIntl } from "react-intl";
import axiosConfig from "../config/axiosConfig"; import axiosConfig from "../config/axiosConfig";
import { I_Installation } from "../util/installation.util"; import { I_Installation } from "../util/types";
import InnovenergyTextfield from "./InnovenergyTextfield"; import InnovenergyTextfield from "./InnovenergyTextfield";
interface I_CustomerFormProps { interface I_CustomerFormProps {

View File

@ -1,14 +1,17 @@
import List from "@mui/material/List"; import List from "@mui/material/List";
import ListItemButton from "@mui/material/ListItemButton"; import ListItemButton from "@mui/material/ListItemButton";
import ListItemText from "@mui/material/ListItemText"; import ListItemText from "@mui/material/ListItemText";
import { Divider, TextField } from "@mui/material"; import { CircularProgress, Divider, Grid } from "@mui/material";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import useRouteMatch from "../hooks/useRouteMatch"; import useRouteMatch from "../hooks/useRouteMatch";
import routes from "../routes.json"; import routes from "../routes.json";
import { Fragment, useEffect, useState } from "react"; import { Fragment, useEffect, useState } from "react";
import { I_Installation } from "../util/installation.util"; import { I_Installation } from "../util/types";
import axiosConfig from "../config/axiosConfig"; import axiosConfig from "../config/axiosConfig";
import { useIntl } from "react-intl";
interface InstallationListProps {
searchQuery: string;
}
const getPathWithoutId = (path?: string) => { const getPathWithoutId = (path?: string) => {
if (path) { if (path) {
@ -32,11 +35,10 @@ const filterData = (
return data; return data;
}; };
const InstallationList = () => { const InstallationList = (props: InstallationListProps) => {
const [data, setData] = useState<I_Installation[]>(); const [data, setData] = useState<I_Installation[]>();
const [searchQuery, setSearchQuery] = useState(""); const [loading, setLoading] = useState(false);
const intl = useIntl(); const filteredData = filterData(props.searchQuery, data);
const filteredData = filterData(searchQuery, data);
const routeMatch = useRouteMatch([ const routeMatch = useRouteMatch([
routes.installationWithId, routes.installationWithId,
@ -46,55 +48,55 @@ const InstallationList = () => {
]); ]);
useEffect(() => { useEffect(() => {
setLoading(true);
axiosConfig.get("/GetAllInstallations", {}).then((res) => { axiosConfig.get("/GetAllInstallations", {}).then((res) => {
setData(res.data); setData(res.data);
setLoading(false);
}); });
}, []); }, []);
return ( return (
<> <>
<TextField {loading && (
id="outlined-search" <Grid container justifyContent="center" width="100%">
label={intl.formatMessage({ <CircularProgress sx={{ m: 6 }} />
id: "search", </Grid>
defaultMessage: "Search", )}
})} {data && (
type="search" <List
fullWidth sx={{
value={searchQuery} width: "100%",
onChange={(e) => setSearchQuery(e.target.value)} bgcolor: "background.paper",
/> position: "relative",
<List overflow: "auto",
sx={{ maxHeight: 400,
width: "100%", py: 0,
bgcolor: "background.paper", mt: 1,
position: "relative", }}
overflow: "auto", component="nav"
maxHeight: 400, aria-labelledby="nested-list-subheader"
py: 0, >
mt: 1, {filteredData?.map((installation) => (
}} <Fragment key={installation.id}>
component="nav" <Link
aria-labelledby="nested-list-subheader" to={
> getPathWithoutId(routeMatch?.pattern?.path) + installation.id
{filteredData?.map((installation) => ( }
<Fragment key={installation.id}> style={{ textDecoration: "none", color: "black" }}
<Link
to={getPathWithoutId(routeMatch?.pattern?.path) + installation.id}
style={{ textDecoration: "none", color: "black" }}
>
<ListItemButton
selected={installation.id === Number(routeMatch?.params.id)}
> >
<ListItemText <ListItemButton
primary={installation.location + " | " + installation.name} selected={installation.id === Number(routeMatch?.params.id)}
/> >
</ListItemButton> <ListItemText
</Link> primary={installation.location + " | " + installation.name}
<Divider /> />
</Fragment> </ListItemButton>
))} </Link>
</List> <Divider />
</Fragment>
))}
</List>
)}
</> </>
); );
}; };

View File

@ -0,0 +1,28 @@
import { TextField } from "@mui/material";
import { useState } from "react";
import { useIntl } from "react-intl";
import InstallationList from "./InstallationList";
const Sidebar = () => {
const [searchQuery, setSearchQuery] = useState("");
const intl = useIntl();
return (
<>
<TextField
id="outlined-search"
label={intl.formatMessage({
id: "search",
defaultMessage: "Search",
})}
type="search"
fullWidth
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
/>
<InstallationList searchQuery={searchQuery} />
</>
);
};
export default Sidebar;

View File

@ -1,5 +1,137 @@
import TreeView from "@mui/lab/TreeView";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
import { ReactNode } from "react";
import { TreeItem } from "@mui/lab";
import { I_Folder, I_Installation } from "../util/types";
const UserList = () => { const UserList = () => {
return <div>Userlist</div>; const data: I_Folder[] = [
{
id: 107,
name: "Bruen-Tromp",
information: "05 Burrows Terrace",
parentId: 75,
type: "Folder",
children: [
{
id: 100,
name: "Sporer and Sons",
information: "820 Helena Terrace",
parentId: 107,
type: "Folder",
},
{
id: 101,
name: "Hahn-Heaney",
information: "144 Di Loreto Center",
parentId: 107,
type: "Folder",
},
],
},
{
id: 125,
name: "Sporer and Sons",
information: "820 Helena Terrace",
parentId: 107,
type: "Folder",
children: [
{
location: "Säffle",
region: "SG",
country: "SE",
orderNumbers: "1LWDGmdXCLmCRFJHTKwcmpoP7bcNeaWJuj",
lat: 0,
long: 0,
s3Bucket: "",
id: 632,
name: "Nikolas Scholz",
information: "",
parentId: 125,
type: "Installation",
},
{
location: "Krasnoye",
region: "ZH",
country: "RU",
orderNumbers: "1M4Rw8toMSJn3d8ULouDd1gYKzANFXeMWh",
lat: 0,
long: 0,
s3Bucket: "",
id: 248,
name: "Judye Goldson",
information: "",
parentId: 125,
type: "Installation",
},
{
id: 103,
name: "Bruen-Tromp",
information: "05 Burrows Terrace",
parentId: 75,
type: "Folder",
children: [
{
id: 100,
name: "Sporer and Sons",
information: "820 Helena Terrace",
parentId: 107,
type: "Folder",
},
{
id: 101,
name: "Hahn-Heaney",
information: "144 Di Loreto Center",
parentId: 107,
type: "Folder",
},
],
},
],
},
{
id: 135,
name: "Hahn-Heaney",
information: "144 Di Loreto Center",
parentId: 107,
type: "Folder",
},
];
const instanceOfFolder = (object: any): object is I_Folder => {
return "children" in object;
};
const getNodes = (element: I_Folder | I_Installation): null | ReactNode => {
if (instanceOfFolder(element)) {
return element.children ? renderTree(element.children) : null;
}
return null;
};
const renderTree = (data: (I_Folder | I_Installation)[]): ReactNode => {
return data.map((element) => {
return (
<TreeItem
key={element.id}
nodeId={element.id.toString()}
label={element.name}
>
{getNodes(element)}
</TreeItem>
);
});
};
return (
<TreeView
aria-label="rich object"
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
sx={{ height: 300, flexGrow: 1, maxWidth: 400 }}
>
{renderTree(data)}
</TreeView>
);
}; };
export default UserList; export default UserList;

View File

@ -1,16 +1,28 @@
import React from 'react'; import React from "react";
import ReactDOM from 'react-dom/client'; import ReactDOM from "react-dom/client";
import './index.css'; import "./index.css";
import App from './App'; import App from "./App";
import reportWebVitals from './reportWebVitals'; import reportWebVitals from "./reportWebVitals";
import { createTheme, ThemeProvider } from "@mui/material";
const root = ReactDOM.createRoot( const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement document.getElementById("root") as HTMLElement
); );
const theme = createTheme({
palette: {
primary: {
main: "#F59100",
},
},
});
root.render( root.render(
<React.StrictMode> <React.StrictMode>
<ThemeProvider theme={theme}>
<App /> <App />
</React.StrictMode>, </ThemeProvider>
</React.StrictMode>
); );
// If you want to start measuring performance in your app, pass a function // If you want to start measuring performance in your app, pass a function

View File

@ -1,10 +1,11 @@
{ {
"installationWithId": "/installation/:id", "installationWithId": "/installation/:id",
"installation": "/installation/", "installation": "/installation/",
"alarmsWithId": "/alarms/:id", "alarmsWithId": "/alarms/:id",
"alarms": "/alarms/", "alarms": "/alarms/",
"usersWithId":"/users/:id", "usersWithId": "/users/:id",
"users":"/users/", "users": "/users/",
"logWithId": "/log/:id", "logWithId": "/log/:id",
"log": "/log/" "log": "/log/",
} "installations": "/installations"
}

View File

@ -4,7 +4,7 @@ import { useEffect, useState } from "react";
import { useParams } from "react-router-dom"; import { useParams } from "react-router-dom";
import CustomerForm from "../components/CustomerForm"; import CustomerForm from "../components/CustomerForm";
import axiosConfig from "../config/axiosConfig"; import axiosConfig from "../config/axiosConfig";
import { I_Installation } from "../util/installation.util"; import { I_Installation } from "../util/types";
const InstallationDetail = () => { const InstallationDetail = () => {
const { id } = useParams(); const { id } = useParams();
@ -13,20 +13,17 @@ const InstallationDetail = () => {
const [error, setError] = useState<AxiosError>(); const [error, setError] = useState<AxiosError>();
useEffect(() => { useEffect(() => {
if (id !== "undefined") { setLoading(true);
console.log(id); axiosConfig
setLoading(true); .get("/GetInstallationById?id=" + id)
axiosConfig .then((res) => {
.get("/GetInstallationById?id=" + id) setValues(res.data);
.then((res) => { setLoading(false);
setValues(res.data); })
setLoading(false); .catch((err: AxiosError) => {
}) setError(err);
.catch((err: AxiosError) => { setLoading(false);
setError(err); });
setLoading(false);
});
}
}, [id]); }, [id]);
if (values && values.id && values.id.toString() === id) { if (values && values.id && values.id.toString() === id) {
@ -36,7 +33,13 @@ const InstallationDetail = () => {
</Box> </Box>
); );
} else if (loading) { } else if (loading) {
return <CircularProgress sx={{ m: 2 }} />; return (
<Box
sx={{ width: 1 / 2, justifyContent: "center", display: "flex", mt: 10 }}
>
<CircularProgress sx={{ m: 2 }} />
</Box>
);
} else if (error) { } else if (error) {
return ( return (
<Alert severity="error" sx={{ mt: 1 }}> <Alert severity="error" sx={{ mt: 1 }}>

View File

@ -1,19 +1,28 @@
// TODO add if required or not // TODO add if required or not
export interface I_Installation { export interface I_Installation {
type: string; type: string;
title: string; title: string;
status: number; status: number;
detail: string; detail: string;
instance: string; instance: string;
location: string; location: string;
region: string; region: string;
country: string; country: string;
orderNumbers: string; orderNumbers: string;
lat: number; lat: number;
long: number; long: number;
s3Bucket: string; s3Bucket: string;
id: number; id: number;
name: string; name: string;
information: string; information: string;
parentId: number; parentId: number;
} }
export interface I_Folder {
id: number;
name: string;
information: string;
parentId: number;
type: string;
children?: (I_Installation | I_Folder)[];
}