[WIP] add drag handle to drag and drop, add error handling and user feedback
This commit is contained in:
parent
366e0af986
commit
3a6f4fc046
|
@ -26,6 +26,7 @@
|
||||||
"chart.js": "^4.2.1",
|
"chart.js": "^4.2.1",
|
||||||
"css-loader": "^6.7.3",
|
"css-loader": "^6.7.3",
|
||||||
"formik": "^2.2.9",
|
"formik": "^2.2.9",
|
||||||
|
"mobx-react-lite": "^3.4.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-chartjs-2": "^5.2.0",
|
"react-chartjs-2": "^5.2.0",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
|
@ -13218,6 +13219,37 @@
|
||||||
"mkdirp": "bin/cmd.js"
|
"mkdirp": "bin/cmd.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mobx": {
|
||||||
|
"version": "6.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mobx/-/mobx-6.8.0.tgz",
|
||||||
|
"integrity": "sha512-+o/DrHa4zykFMSKfS8Z+CPSEg5LW9tSNGTuN8o6MF1GKxlfkSHSeJn5UtgxvPkGgaouplnrLXCF+duAsmm6FHQ==",
|
||||||
|
"peer": true,
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mobx"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/mobx-react-lite": {
|
||||||
|
"version": "3.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.4.3.tgz",
|
||||||
|
"integrity": "sha512-NkJREyFTSUXR772Qaai51BnE1voWx56LOL80xG7qkZr6vo8vEaLF3sz1JNUVh+rxmUzxYaqOhfuxTfqUh0FXUg==",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/mobx"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"mobx": "^6.1.0",
|
||||||
|
"react": "^16.8.0 || ^17 || ^18"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"react-dom": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"react-native": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ms": {
|
"node_modules/ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
@ -28150,6 +28182,18 @@
|
||||||
"minimist": "^1.2.6"
|
"minimist": "^1.2.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mobx": {
|
||||||
|
"version": "6.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mobx/-/mobx-6.8.0.tgz",
|
||||||
|
"integrity": "sha512-+o/DrHa4zykFMSKfS8Z+CPSEg5LW9tSNGTuN8o6MF1GKxlfkSHSeJn5UtgxvPkGgaouplnrLXCF+duAsmm6FHQ==",
|
||||||
|
"peer": true
|
||||||
|
},
|
||||||
|
"mobx-react-lite": {
|
||||||
|
"version": "3.4.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/mobx-react-lite/-/mobx-react-lite-3.4.3.tgz",
|
||||||
|
"integrity": "sha512-NkJREyFTSUXR772Qaai51BnE1voWx56LOL80xG7qkZr6vo8vEaLF3sz1JNUVh+rxmUzxYaqOhfuxTfqUh0FXUg==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
"chart.js": "^4.2.1",
|
"chart.js": "^4.2.1",
|
||||||
"css-loader": "^6.7.3",
|
"css-loader": "^6.7.3",
|
||||||
"formik": "^2.2.9",
|
"formik": "^2.2.9",
|
||||||
|
"mobx-react-lite": "^3.4.3",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-chartjs-2": "^5.2.0",
|
"react-chartjs-2": "^5.2.0",
|
||||||
"react-dnd": "^16.0.1",
|
"react-dnd": "^16.0.1",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { Alert, Button, CircularProgress, Grid } from "@mui/material";
|
import { Alert, Button, CircularProgress, Grid } from "@mui/material";
|
||||||
import Container from "@mui/material/Container";
|
import Container from "@mui/material/Container";
|
||||||
import axiosConfig, { axiosConfigWithoutToken } from "./config/axiosConfig";
|
import { axiosConfigWithoutToken } from "./config/axiosConfig";
|
||||||
import InnovenergyTextfield from "./components/Layout/InnovenergyTextfield";
|
import InnovenergyTextfield from "./components/Layout/InnovenergyTextfield";
|
||||||
|
|
||||||
const loginUser = async (username: string, password: string) => {
|
const loginUser = async (username: string, password: string) => {
|
||||||
|
@ -17,18 +17,20 @@ const Login = ({ setToken }: { setToken: (value: string) => void }) => {
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState();
|
const [error, setError] = useState();
|
||||||
|
|
||||||
const verifyToken = async () => {
|
const verifyToken = async (token: string) => {
|
||||||
axiosConfig.get("/GetAllInstallations");
|
axiosConfigWithoutToken.get("/GetAllInstallations", {
|
||||||
|
headers: { auth: token },
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = () => {
|
const handleSubmit = () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
loginUser(username, password).then(({ data }) => {
|
loginUser(username, password).then(({ data }) => {
|
||||||
// TODO change this if they return err codes from backend
|
// TODO change this if they return err codes from backend
|
||||||
if (typeof data === "string") {
|
if (data && data.token) {
|
||||||
verifyToken()
|
verifyToken(data.token)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToken(data);
|
setToken(data.token);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
import { Box, CircularProgress, Alert } from "@mui/material";
|
import { Box, CircularProgress, Alert } from "@mui/material";
|
||||||
import { AxiosError } from "axios";
|
import { AxiosError } from "axios";
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect, useContext } from "react";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import axiosConfig from "../../config/axiosConfig";
|
import axiosConfig from "../../config/axiosConfig";
|
||||||
import { I_Installation } from "../../util/types";
|
import { I_Installation } from "../../util/types";
|
||||||
import FolderForm from "./FolderForm";
|
import FolderForm from "./FolderForm";
|
||||||
|
import GroupDataContext from "./Tree/GroupDataContext";
|
||||||
|
|
||||||
const Folder = () => {
|
const Folder = () => {
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import { Alert, Button, Grid, Snackbar } from "@mui/material";
|
import { Button, CircularProgress, Grid } 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_Folder } from "../../util/types";
|
import { I_Folder } from "../../util/types";
|
||||||
|
import InnovenergySnackbar from "../InnovenergySnackbar";
|
||||||
import InnovenergyTextfield from "../Layout/InnovenergyTextfield";
|
import InnovenergyTextfield from "../Layout/InnovenergyTextfield";
|
||||||
|
|
||||||
interface I_CustomerFormProps {
|
interface I_CustomerFormProps {
|
||||||
|
@ -19,6 +20,8 @@ const FolderForm = (props: I_CustomerFormProps) => {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
const [snackbarOpen, setSnackbarOpen] = useState(false);
|
const [snackbarOpen, setSnackbarOpen] = useState(false);
|
||||||
|
const [error, setError] = useState();
|
||||||
|
const [loading, setLoading] = useState(false);
|
||||||
|
|
||||||
const formik = useFormik({
|
const formik = useFormik({
|
||||||
initialValues: {
|
initialValues: {
|
||||||
|
@ -26,21 +29,25 @@ const FolderForm = (props: I_CustomerFormProps) => {
|
||||||
information: values.information,
|
information: values.information,
|
||||||
},
|
},
|
||||||
onSubmit: (formikValues) => {
|
onSubmit: (formikValues) => {
|
||||||
|
setLoading(true);
|
||||||
const idAsNumber = parseInt(id, 10);
|
const idAsNumber = parseInt(id, 10);
|
||||||
updateFolder({
|
updateFolder({
|
||||||
...values,
|
...values,
|
||||||
...formikValues,
|
...formikValues,
|
||||||
id: idAsNumber,
|
id: idAsNumber,
|
||||||
}).then((res) => {
|
})
|
||||||
setSnackbarOpen(true);
|
.then((res) => {
|
||||||
});
|
setSnackbarOpen(true);
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
setSnackbarOpen(true);
|
||||||
|
setError(err);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const handleClose = () => {
|
|
||||||
setSnackbarOpen(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form onSubmit={formik.handleSubmit}>
|
<form onSubmit={formik.handleSubmit}>
|
||||||
<InnovenergyTextfield
|
<InnovenergyTextfield
|
||||||
|
@ -64,26 +71,16 @@ const FolderForm = (props: I_CustomerFormProps) => {
|
||||||
handleChange={formik.handleChange}
|
handleChange={formik.handleChange}
|
||||||
/>
|
/>
|
||||||
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
|
<Grid container justifyContent="flex-end" sx={{ pt: 1 }}>
|
||||||
<Button variant="outlined" type="submit">
|
{loading && <CircularProgress />}
|
||||||
|
<Button variant="outlined" type="submit" sx={{ height: 40, ml: 2 }}>
|
||||||
<FormattedMessage id="applyChanges" defaultMessage="Apply changes" />
|
<FormattedMessage id="applyChanges" defaultMessage="Apply changes" />
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
<Snackbar
|
<InnovenergySnackbar
|
||||||
|
error={error}
|
||||||
|
setOpen={setSnackbarOpen}
|
||||||
open={snackbarOpen}
|
open={snackbarOpen}
|
||||||
anchorOrigin={{
|
/>
|
||||||
vertical: "top",
|
|
||||||
horizontal: "center",
|
|
||||||
}}
|
|
||||||
autoHideDuration={6000}
|
|
||||||
onClose={handleClose}
|
|
||||||
>
|
|
||||||
<Alert onClose={handleClose} severity="success" sx={{ width: "100%" }}>
|
|
||||||
<FormattedMessage
|
|
||||||
id="updatedSuccessfully"
|
|
||||||
defaultMessage="Updated successfully"
|
|
||||||
/>
|
|
||||||
</Alert>
|
|
||||||
</Snackbar>
|
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -17,45 +17,51 @@ const GroupTabs = () => {
|
||||||
const id = routeMatch?.params?.id;
|
const id = routeMatch?.params?.id;
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
|
|
||||||
return (
|
if (id) {
|
||||||
<Box sx={{ width: "100%" }}>
|
return (
|
||||||
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
|
<Box sx={{ width: "100%" }}>
|
||||||
<Tabs value={routeMatch?.pattern?.path} aria-label="basic tabs example">
|
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
|
||||||
{routeMatch?.pathname.includes("folder") ? (
|
<Tabs
|
||||||
<Tab
|
value={routeMatch?.pattern?.path}
|
||||||
label={intl.formatMessage({
|
aria-label="basic tabs example"
|
||||||
id: "folder",
|
>
|
||||||
defaultMessage: "Folder",
|
{routeMatch?.pathname.includes("folder") ? (
|
||||||
})}
|
<Tab
|
||||||
value={routes.groups + routes.folder + ":id"}
|
label={intl.formatMessage({
|
||||||
component={Link}
|
id: "folder",
|
||||||
to={routes.folder + id}
|
defaultMessage: "Folder",
|
||||||
/>
|
})}
|
||||||
) : (
|
value={routes.groups + routes.folder + ":id"}
|
||||||
<Tab
|
component={Link}
|
||||||
label={intl.formatMessage({
|
to={routes.folder + id}
|
||||||
id: "installation",
|
/>
|
||||||
defaultMessage: "Installation",
|
) : (
|
||||||
})}
|
<Tab
|
||||||
value={routes.groups + routes.installation + ":id"}
|
label={intl.formatMessage({
|
||||||
component={Link}
|
id: "installation",
|
||||||
to={routes.installation + id}
|
defaultMessage: "Installation",
|
||||||
/>
|
})}
|
||||||
)}
|
value={routes.groups + routes.installation + ":id"}
|
||||||
|
component={Link}
|
||||||
|
to={routes.installation + id}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
<Tab
|
<Tab
|
||||||
label={intl.formatMessage({
|
label={intl.formatMessage({
|
||||||
id: "users",
|
id: "users",
|
||||||
defaultMessage: "Users",
|
defaultMessage: "Users",
|
||||||
})}
|
})}
|
||||||
value={routes.groups + routes.users + ":id"}
|
value={routes.groups + routes.users + ":id"}
|
||||||
component={Link}
|
component={Link}
|
||||||
to={routes.users + id}
|
to={routes.users + id}
|
||||||
/>
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
);
|
||||||
);
|
}
|
||||||
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default GroupTabs;
|
export default GroupTabs;
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { Grid } from "@mui/material";
|
import { Grid } from "@mui/material";
|
||||||
import { Container } from "@mui/system";
|
import { Container } from "@mui/system";
|
||||||
|
import { useState } from "react";
|
||||||
import { Routes, Route } from "react-router";
|
import { Routes, Route } from "react-router";
|
||||||
import routes from "../../routes.json";
|
import routes from "../../routes.json";
|
||||||
|
import { I_Folder, I_Installation } from "../../util/types";
|
||||||
import InstallationDetail from "../Installations/Installation";
|
import InstallationDetail from "../Installations/Installation";
|
||||||
import NavigationButtons from "../Layout/NavigationButtons";
|
import NavigationButtons from "../Layout/NavigationButtons";
|
||||||
import Folder from "./Folder";
|
import Folder from "./Folder";
|
||||||
|
@ -9,12 +11,14 @@ import GroupTabs from "./GroupTabs";
|
||||||
import GroupTree from "./Tree/GroupTree";
|
import GroupTree from "./Tree/GroupTree";
|
||||||
|
|
||||||
const Groups = () => {
|
const Groups = () => {
|
||||||
|
const [data, setData] = useState<(I_Folder | I_Installation)[]>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container maxWidth="xl">
|
<Container maxWidth="xl">
|
||||||
<Grid container spacing={2}>
|
<Grid container spacing={2}>
|
||||||
<Grid item xs={3}>
|
<Grid item xs={3}>
|
||||||
<NavigationButtons />
|
<NavigationButtons />
|
||||||
<GroupTree />
|
<GroupTree data={data} setData={setData} />
|
||||||
</Grid>
|
</Grid>
|
||||||
<Grid item xs={9}>
|
<Grid item xs={9}>
|
||||||
<GroupTabs />
|
<GroupTabs />
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { DragLayerMonitorProps } from "@minoru/react-dnd-treeview";
|
import { DragLayerMonitorProps } from "@minoru/react-dnd-treeview";
|
||||||
import { I_Installation, I_Folder } from "../../../util/types";
|
import { I_Installation, I_Folder } from "../../../util/types";
|
||||||
import styles from "./DragPreview.module.scss";
|
import styles from "./DragPreview.module.scss";
|
||||||
import TypeIcon from "./TypeIcon";
|
import TypeIcon from "../TypeIcon";
|
||||||
|
|
||||||
interface DragPreviewProps {
|
interface DragPreviewProps {
|
||||||
monitorProps: DragLayerMonitorProps<I_Installation | I_Folder>;
|
monitorProps: DragLayerMonitorProps<I_Installation | I_Folder>;
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
import { createContext } from "react";
|
||||||
|
import { I_Folder, I_Installation } from "../../../util/types";
|
||||||
|
|
||||||
|
interface GroupData {
|
||||||
|
data: (I_Folder | I_Installation)[] | undefined;
|
||||||
|
setData: (value: (I_Folder | I_Installation)[]) => void;
|
||||||
|
}
|
||||||
|
const GroupDataContext = createContext<GroupData>({
|
||||||
|
setData: (value) => {},
|
||||||
|
data: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
export default GroupDataContext;
|
|
@ -20,6 +20,6 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.treeContainer {
|
.treeContainer {
|
||||||
height: 500px;
|
max-height: 500px;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useCallback, useEffect, useState } from "react";
|
||||||
import axiosConfig from "../../../config/axiosConfig";
|
import axiosConfig from "../../../config/axiosConfig";
|
||||||
import { I_Folder, I_Installation } from "../../../util/types";
|
import { I_Folder, I_Installation } from "../../../util/types";
|
||||||
import { CircularProgress, Grid } from "@mui/material";
|
import { Alert, CircularProgress, Grid } from "@mui/material";
|
||||||
import { DndProvider } from "react-dnd";
|
import { DndProvider } from "react-dnd";
|
||||||
import {
|
import {
|
||||||
MultiBackend,
|
MultiBackend,
|
||||||
|
@ -14,6 +14,7 @@ import TreeNode from "./TreeNode";
|
||||||
import styles from "./GroupTree.module.scss";
|
import styles from "./GroupTree.module.scss";
|
||||||
import withScrolling from "react-dnd-scrolling";
|
import withScrolling from "react-dnd-scrolling";
|
||||||
import DragPreview from "./DragPreview";
|
import DragPreview from "./DragPreview";
|
||||||
|
import InnovenergySnackbar from "../../InnovenergySnackbar";
|
||||||
|
|
||||||
const getTreeData = (
|
const getTreeData = (
|
||||||
data: (I_Folder | I_Installation)[]
|
data: (I_Folder | I_Installation)[]
|
||||||
|
@ -30,21 +31,49 @@ const getTreeData = (
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const GroupTree = () => {
|
interface GroupTreeProps {
|
||||||
const [data, setData] = useState<(I_Folder | I_Installation)[]>();
|
data: (I_Folder | I_Installation)[] | undefined;
|
||||||
|
setData: (value: (I_Folder | I_Installation)[]) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GroupTree = (props: GroupTreeProps) => {
|
||||||
|
const { data, setData } = props;
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [getError, setGetError] = useState(false);
|
||||||
|
const [putError, setPutError] = useState(false);
|
||||||
|
|
||||||
|
const [snackbarOpen, setSnackbarOpen] = useState(false);
|
||||||
|
|
||||||
const ScrollingComponent = withScrolling("div");
|
const ScrollingComponent = withScrolling("div");
|
||||||
|
|
||||||
|
const getData = useCallback(async () => {
|
||||||
|
setLoading(true);
|
||||||
|
return axiosConfig
|
||||||
|
.get("/GetAllFoldersAndInstallations")
|
||||||
|
.then((res) => {
|
||||||
|
setData(res.data);
|
||||||
|
setLoading(false);
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
setGetError(err);
|
||||||
|
setLoading(false);
|
||||||
|
});
|
||||||
|
}, [setData]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getData();
|
getData();
|
||||||
}, []);
|
}, [getData]);
|
||||||
|
|
||||||
const getData = async () => {
|
const findParent = (element: I_Folder | I_Installation): any => {
|
||||||
setLoading(true);
|
if (data) {
|
||||||
return axiosConfig.get("/GetAllFoldersAndInstallations").then((res) => {
|
const parent = data.find(
|
||||||
setData(res.data);
|
(el) => el.type === "Folder" && el.id === element.parentId
|
||||||
setLoading(false);
|
);
|
||||||
});
|
if (parent) {
|
||||||
|
return findParent(parent);
|
||||||
|
}
|
||||||
|
return element.parentId;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDrop = (
|
const handleDrop = (
|
||||||
|
@ -62,7 +91,13 @@ const GroupTree = () => {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
setSnackbarOpen(true);
|
||||||
getData();
|
getData();
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
setPutError(err);
|
||||||
|
setLoading(false);
|
||||||
|
setSnackbarOpen(true);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,8 +142,19 @@ const GroupTree = () => {
|
||||||
) => handleDrop(tree, options)}
|
) => handleDrop(tree, options)}
|
||||||
/>
|
/>
|
||||||
</ScrollingComponent>
|
</ScrollingComponent>
|
||||||
|
<InnovenergySnackbar
|
||||||
|
error={putError}
|
||||||
|
open={snackbarOpen}
|
||||||
|
setOpen={setSnackbarOpen}
|
||||||
|
/>
|
||||||
</DndProvider>
|
</DndProvider>
|
||||||
);
|
);
|
||||||
|
} else if (getError) {
|
||||||
|
return (
|
||||||
|
<Alert severity="error" sx={{ mt: 1 }}>
|
||||||
|
Couldn't load data
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,7 +6,7 @@ import styles from "./TreeNode.module.scss";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import routes from "../../../routes.json";
|
import routes from "../../../routes.json";
|
||||||
import { I_Folder, I_Installation } from "../../../util/types";
|
import { I_Folder, I_Installation } from "../../../util/types";
|
||||||
import TypeIcon from "./TypeIcon";
|
import TypeIcon from "../TypeIcon";
|
||||||
import DragHandleIcon from "@mui/icons-material/DragHandle";
|
import DragHandleIcon from "@mui/icons-material/DragHandle";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -52,6 +52,7 @@ const TreeNode: React.FC<Props> = (props) => {
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
color: "black",
|
color: "black",
|
||||||
}}
|
}}
|
||||||
|
draggable={false}
|
||||||
>
|
>
|
||||||
<div className={styles.labelGridItem}>
|
<div className={styles.labelGridItem}>
|
||||||
<Typography variant="body2">{node.text}</Typography>
|
<Typography variant="body2">{node.text}</Typography>
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
import { Alert, Snackbar } from "@mui/material";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
|
interface InnovenergySnackbarProps {
|
||||||
|
open: boolean;
|
||||||
|
setOpen: (value: boolean) => void;
|
||||||
|
error?: any;
|
||||||
|
}
|
||||||
|
const InnovenergySnackbar = (props: InnovenergySnackbarProps) => {
|
||||||
|
const { open, setOpen, error } = props;
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Snackbar
|
||||||
|
open={open}
|
||||||
|
anchorOrigin={{
|
||||||
|
vertical: "top",
|
||||||
|
horizontal: "center",
|
||||||
|
}}
|
||||||
|
autoHideDuration={6000}
|
||||||
|
onClose={handleClose}
|
||||||
|
>
|
||||||
|
<Alert
|
||||||
|
onClose={handleClose}
|
||||||
|
severity={error ? "error" : "success"}
|
||||||
|
sx={{ width: "100%" }}
|
||||||
|
>
|
||||||
|
{error ? (
|
||||||
|
<FormattedMessage
|
||||||
|
id="updateFolderErrorMessage"
|
||||||
|
defaultMessage="Couldn't update folder, an error occured"
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id="updatedSuccessfully"
|
||||||
|
defaultMessage="Updated successfully"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</Alert>
|
||||||
|
</Snackbar>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default InnovenergySnackbar;
|
|
@ -16,6 +16,7 @@
|
||||||
"logout": "Logout",
|
"logout": "Logout",
|
||||||
"updatedSuccessfully": "Erfolgreich aktualisiert",
|
"updatedSuccessfully": "Erfolgreich aktualisiert",
|
||||||
"groups": "Gruppen",
|
"groups": "Gruppen",
|
||||||
"group": "Gruppe",
|
"group": "Gruppe",
|
||||||
"folder": "Ordner"
|
"folder": "Ordner",
|
||||||
|
"updateFolderErrorMessage": "Der Ordner konnte nicht aktualisiert werden, ein Fehler ist aufgetreten"
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,6 @@
|
||||||
"updatedSuccessfully": "Updated successfully",
|
"updatedSuccessfully": "Updated successfully",
|
||||||
"groups": "Groups",
|
"groups": "Groups",
|
||||||
"group": "Group",
|
"group": "Group",
|
||||||
"folder": "folder"
|
"folder": "folder",
|
||||||
|
"updateFolderErrorMessage": "Couldn't update folder, an error occured"
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue