From f42bc99a9d5d7d50b064609e6c78e3aa0e6c018e Mon Sep 17 00:00:00 2001 From: Malo BEAUCHAMPS Date: Thu, 17 Oct 2024 17:58:02 +0200 Subject: [PATCH] feat: start notify + perms --- package-lock.json | 25 ++- package.json | 3 +- src/App.tsx | 60 +++--- src/component/Navigation/Navigation.tsx | 273 +++++++++++++----------- src/pages/Login.tsx | 6 + src/pages/Practical.tsx | 34 ++- src/pages/admin/BulkCreateUser.tsx | 189 ++++++++-------- src/pages/admin/Users.tsx | 63 ++++++ 8 files changed, 400 insertions(+), 253 deletions(-) create mode 100644 src/pages/admin/Users.tsx diff --git a/package-lock.json b/package-lock.json index b91a16f..9bd4ca4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,8 @@ "axios": "^1.7.7", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-router-dom": "^6.26.1" + "react-router-dom": "^6.26.1", + "react-toastify": "^10.0.6" }, "devDependencies": { "@eslint/js": "^9.9.0", @@ -1811,6 +1812,15 @@ "node": ">= 6" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -3425,6 +3435,19 @@ "react-dom": ">=16.8" } }, + "node_modules/react-toastify": { + "version": "10.0.6", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.6.tgz", + "integrity": "sha512-yYjp+omCDf9lhZcrZHKbSq7YMuK0zcYkDFTzfRFgTXkTFHZ1ToxwAonzA4JI5CxA91JpjFLmwEsZEgfYfOqI1A==", + "license": "MIT", + "dependencies": { + "clsx": "^2.1.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", diff --git a/package.json b/package.json index 0cbd6ca..5d9c6dd 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "axios": "^1.7.7", "react": "^18.3.1", "react-dom": "^18.3.1", - "react-router-dom": "^6.26.1" + "react-router-dom": "^6.26.1", + "react-toastify": "^10.0.6" }, "devDependencies": { "@eslint/js": "^9.9.0", diff --git a/src/App.tsx b/src/App.tsx index 5585120..e3b200f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,37 +10,41 @@ import LoginPage from "./pages/Login"; import PageTest from "./pages/PageTest"; import CreateTp from "./pages/admin/CreateTp"; import BulkUsers from "./pages/admin/BulkCreateUser"; +import Users from "./pages/admin/Users"; +import { ToastContainer } from "react-toastify"; function App() { - const [showNotif, setShowNotif] = useState(false); - return ( - - - - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - - + const [showNotif, setShowNotif] = useState(false); + return ( + + + + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + + - {showNotif && ( -
-
- Message sent successfully. - -
-
- )} -
- ); + + {showNotif && ( +
+
+ Message sent successfully. + +
+
+ )} +
+ ); } export default App; diff --git a/src/component/Navigation/Navigation.tsx b/src/component/Navigation/Navigation.tsx index af12c19..2bc2c38 100644 --- a/src/component/Navigation/Navigation.tsx +++ b/src/component/Navigation/Navigation.tsx @@ -27,6 +27,13 @@ const Navigation: React.FC = ({ localStorage.getItem("theme") ? localStorage.getItem("theme") : "dark", ); + const logout = () => { + setIsDrawerOpen(!isDrawerOpen); + const removeCookie = `quarkus-credential=; Max-Age=0;path=/`; + document.cookie = removeCookie; + localStorage.removeItem("root"); + }; + const handleToggle = (e) => { if (theme === "light") { setTheme("dark"); @@ -49,48 +56,50 @@ const Navigation: React.FC = ({ return ( <> - {user && ( - <> -
-
- -
-
-
- -
- +
+
+ +
+ {location.pathname !== "/login" && ( +
+
+
- {children} -
+
-
- - )} + )} +
+
); }; diff --git a/src/pages/Login.tsx b/src/pages/Login.tsx index 9607a1a..06566bd 100644 --- a/src/pages/Login.tsx +++ b/src/pages/Login.tsx @@ -22,6 +22,12 @@ const LoginPage: React.FC = () => { }) .then((response) => { if (response.status === 200) { + axios.get("/api/users/me").then((res) => { + localStorage.setItem("username", res.data.username); + if (res.data.roles.includes("root")) { + localStorage.setItem("root", true); + } + }); navigate(from); } }) diff --git a/src/pages/Practical.tsx b/src/pages/Practical.tsx index 03de6cb..bf859a1 100644 --- a/src/pages/Practical.tsx +++ b/src/pages/Practical.tsx @@ -1,12 +1,18 @@ -import { ArrowDownTrayIcon } from "@heroicons/react/24/outline"; +import { ArrowDownTrayIcon, ClipboardIcon } from "@heroicons/react/24/outline"; import axios from "axios"; import { useEffect, useState } from "react"; import { useParams } from "react-router-dom"; +import { toast } from "react-toastify"; function Practical() { const { id } = useParams(); const [tp, setTp] = useState(null); + const copyText = (copy: string) => { + navigator.clipboard.writeText(copy); + toast("Copied!"); + }; + useEffect(() => { console.log("akljsbcascb"); axios.get(`/api/tps/${id}`).then((res) => { @@ -60,14 +66,30 @@ function Practical() {

Resources

-
    -
  • +
      +
    • SSH: - {tp.ssh} +
      copyText(tp.ssh)} + > + {tp.ssh} +
      + +
      +
    • -
    • +
    • Password: - {tp.pwd} +
      navigator.clipboard.writeText(tp.pwd)} + > + {tp.pwd} +
      + +
      +
diff --git a/src/pages/admin/BulkCreateUser.tsx b/src/pages/admin/BulkCreateUser.tsx index f919401..0be3b64 100644 --- a/src/pages/admin/BulkCreateUser.tsx +++ b/src/pages/admin/BulkCreateUser.tsx @@ -1,101 +1,114 @@ import axios from "axios"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; function BulkUsers() { - const [file, setFile] = useState(null); - const [userData, setUserData] = useState([]); - const [practical, setPractical] = useState("0"); - const navigate = useNavigate(); + const [file, setFile] = useState(null); + const [userData, setUserData] = useState([]); + const [practical, setPractical] = useState("0"); + const navigate = useNavigate(); + const [tps, setTps] = useState([]); - const handlePracticalChange = (e) => { - setPractical(e.target.value); - } + const handlePracticalChange = (e) => { + setPractical(e.target.value); + }; - const handleFileChange = (event) => { - const selectedFile = event.target.files[0]; - if (selectedFile && selectedFile.type === 'text/csv') { - setFile(selectedFile); - parseCSV(selectedFile); - } else { - alert('Please upload a valid CSV file.'); - } + useEffect(() => { + axios.get("/api/tps").then((res) => { + setTps(res.data); + }); + }, []); + + const handleFileChange = (event) => { + const selectedFile = event.target.files[0]; + // if (selectedFile && selectedFile.type === "text/csv") { + setFile(selectedFile); + parseCSV(selectedFile); + // } else { + // alert("Please upload a valid CSV file."); + // } + }; + + const parseCSV = (file) => { + const reader = new FileReader(); + reader.onload = (event) => { + const text = event.target.result; + const rows = text.split("\n").map((row) => row.split(",")); + const formattedData = rows.map((row) => ({ + name: row[0], + email: row[1], + // Add other fields as necessary + })); + setUserData(formattedData); }; + reader.readAsText(file); + }; - const parseCSV = (file) => { - const reader = new FileReader(); - reader.onload = (event) => { - const text = event.target.result; - const rows = text.split('\n').map((row) => row.split(',')); - const formattedData = rows.map((row) => ({ - name: row[0], - email: row[1], - // Add other fields as necessary - })); - setUserData(formattedData); - }; - reader.readAsText(file); - }; + const handleSubmit = () => { + // Handle submission logic (e.g., sending data to the backend) + console.log(practical); + axios + .post("/api/users/jdmi", { + users: userData.filter((user) => user.name !== ""), + tpId: practical, + }) + .then(() => navigate(`/admin/users`)); + }; - const handleSubmit = () => { - // Handle submission logic (e.g., sending data to the backend) - axios.post("/api/users/jdmi", userData.filter(user => user.name !== "")).then(res => navigate(`/tps/${res.data.id}`)); - }; - - return ( -
-

Bulk User Creation

- - {userData.length > 0 && ( -
- - - - - - {/* Add other headers as necessary */} - - - - {userData.map((user, index) => ( - - - - - ))} - -
NameEmail
{user.name}{user.email}
-
- )} - -
- - -
- + return ( +
+

Bulk User Creation

+ + {userData.length > 0 && ( +
+ + + + + + {/* Add other headers as necessary */} + + + + {userData.map((user, index) => ( + + + + + ))} + +
NameEmail
{user.name}{user.email}
- ); + )} + +
+ + +
+ +
+ ); } export default BulkUsers; diff --git a/src/pages/admin/Users.tsx b/src/pages/admin/Users.tsx new file mode 100644 index 0000000..06fe1ee --- /dev/null +++ b/src/pages/admin/Users.tsx @@ -0,0 +1,63 @@ +import axios from "axios"; +import { useEffect, useState } from "react"; + +function Users() { + const [users, setUsers] = useState([]); + + useEffect(() => { + axios.get("/api/users").then((res) => { + setUsers(res.data); + console.log(res.data) + }); + }, []); + + const handleEditUser = (userId) => { + // Logic for editing the user (e.g., opening a modal) + alert(`Edit user with ID: ${userId}`); + }; + + return ( +
+
+

Manage Users

+ + {/* Users Table */} +
+ + + + + + + + + + + + + {users.map((user, index) => ( + + + + + + + + + ))} + +
#NameEmailRolesInstancesActions
{index + 1}{user.name}{user.email}{user.roles}{user.instances.length} + +
+
+
+
+ ); +} + +export default Users;