diff --git a/backend/app/src/test/java/com/ugent/pidgeon/util/TestRunnerTest.java b/backend/app/src/test/java/com/ugent/pidgeon/util/TestRunnerTest.java index 04a4a42f..c71c0bb5 100644 --- a/backend/app/src/test/java/com/ugent/pidgeon/util/TestRunnerTest.java +++ b/backend/app/src/test/java/com/ugent/pidgeon/util/TestRunnerTest.java @@ -119,7 +119,6 @@ public void testRunDockerTest() throws IOException { verify(dockerModel, times(1)).addZipInputFiles(file); verify(dockerModel, times(1)).cleanUp(); - verify(dockerModel, times(1)).addUtilFiles(extraFilesPathResolved); assertEquals(1, filehandlerCalled.get()); /* artifacts are empty */ @@ -128,7 +127,6 @@ public void testRunDockerTest() throws IOException { assertEquals(dockerTemplateTestOutput, result); verify(dockerModel, times(2)).addZipInputFiles(file); verify(dockerModel, times(2)).cleanUp(); - verify(dockerModel, times(2)).addUtilFiles(extraFilesPathResolved); assertEquals(1, filehandlerCalled.get()); /* aritifacts are null */ @@ -137,7 +135,6 @@ public void testRunDockerTest() throws IOException { assertEquals(dockerTemplateTestOutput, result); verify(dockerModel, times(3)).addZipInputFiles(file); verify(dockerModel, times(3)).cleanUp(); - verify(dockerModel, times(3)).addUtilFiles(extraFilesPathResolved); assertEquals(1, filehandlerCalled.get()); /* No template */ @@ -147,7 +144,6 @@ public void testRunDockerTest() throws IOException { assertEquals(dockerTestOutput, result); verify(dockerModel, times(4)).addZipInputFiles(file); verify(dockerModel, times(4)).cleanUp(); - verify(dockerModel, times(4)).addUtilFiles(extraFilesPathResolved); /* Error gets thrown */ when(dockerModel.runSubmission(testEntity.getDockerTestScript())).thenThrow(new RuntimeException("Error")); diff --git a/frontend/src/i18n/en/translation.json b/frontend/src/i18n/en/translation.json index 2104c4a9..54faddf6 100644 --- a/frontend/src/i18n/en/translation.json +++ b/frontend/src/i18n/en/translation.json @@ -86,8 +86,8 @@ "search": "Search", "emailError": "Please enter a valid email", "emailTooShort": "Email must be at least 3 characters long", - "nameError": "Name must be at least 3 characters long", - "surnameError": "Surname must be at least 3 characters long", + "nameError": "Name or surname must be at least 3 characters long", + "surnameError": "Name or surname must be at least 3 characters long", "searchTutorial": "Enter a name, surname, or email to find users.", "searchTooShort": "The search must be at least 3 characters long", "noUsersFound": "No users found", diff --git a/frontend/src/i18n/nl/translation.json b/frontend/src/i18n/nl/translation.json index e30e5e17..baadff8a 100644 --- a/frontend/src/i18n/nl/translation.json +++ b/frontend/src/i18n/nl/translation.json @@ -87,8 +87,8 @@ "search": "Zoeken", "emailError": "Vul een geldig email adres in", "emailTooShort": "Email moet minstens 3 karakters lang zijn", - "nameError": "Naam moet minstens 3 karakters lang zijn", - "surnameError": "Achternaam moet minstens 3 karakters lang zijn", + "nameError": "Naam of achternaam moet minstens 3 karakters lang zijn", + "surnameError": "Naam of achternaam moet minstens 3 karakters lang zijn", "searchTooShort": "Zoekopdracht moet minstens 3 karakters lang zijn", "searchTutorial": "Vul een email adres, naam of achternaam in om gebruikers op te zoeken.", "noUsersFound": "Geen gebruikers gevonden", diff --git a/frontend/src/pages/editRole/EditRole.tsx b/frontend/src/pages/editRole/EditRole.tsx index 948b189f..ce669205 100644 --- a/frontend/src/pages/editRole/EditRole.tsx +++ b/frontend/src/pages/editRole/EditRole.tsx @@ -1,5 +1,5 @@ import { useContext, useEffect, useState } from "react" -import { Form, Input, Spin, Select, Typography } from "antd" +import { Form, Input, Spin, Select, Typography, Space } from "antd" import UserList from "./components/UserList" import { ApiRoutes, GET_Responses, UserRole } from "../../@types/requests.d" import apiCall from "../../util/apiFetch" @@ -10,18 +10,22 @@ import { UserContext } from "../../providers/UserProvider" import useUser from "../../hooks/useUser" export type UsersType = GET_Responses[ApiRoutes.USERS] -type SearchType = "name" | "surname" | "email" +type SearchType = "name" | "email" const ProfileContent = () => { const [users, setUsers] = useState(null) const myself = useUser() const [loading, setLoading] = useState(false) const [form] = Form.useForm() - const searchValue = Form.useWatch("search", form) + const firstSearchValue = Form.useWatch("first", form) + const secondSearchValue = Form.useWatch("second", form) + const searchValue = `${firstSearchValue || ''} ${secondSearchValue || ''}`.trim(); const [debouncedSearchValue] = useDebounceValue(searchValue, 250) const [searchType, setSearchType] = useState("name") const { t } = useTranslation() + const emailRegex = /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/; + useEffect(() => { onSearch() }, [debouncedSearchValue]) @@ -43,14 +47,56 @@ const ProfileContent = () => { }) } + const [isError, setIsError] = useState(false) + + const checkValidate = () => { + if (searchType === "email") { + if (!emailRegex.test(form.getFieldValue("first"))) { + return false + } else { + return true + } + } else { + const firstValue = form.getFieldValue("first") + const secondValue = form.getFieldValue("second") + const firstValueLength = firstValue ? firstValue.length : 0 + const secondValueLength = secondValue ? secondValue.length : 0 + if (firstValueLength < 3 && secondValueLength < 3) { + console.log("error") + return false + } else { + console.log("no error") + return true + } + } + } + + const validate = () => { + if (!checkValidate()) { + setIsError(true) + } else { + setIsError(false) + } + } + const onSearch = async () => { - const value = form.getFieldValue("search") - if (!value || value.length < 3) return + //validation + if (!checkValidate()) { + return + } + + const firstValue = form.getFieldValue("first") setLoading(true) const params = new URLSearchParams() - params.append(searchType, form.getFieldValue("search")) + if (searchType === "email") { + params.append(searchType, form.getFieldValue("first")) + } else { + const secondValue = form.getFieldValue("second") + if (firstValue) params.append("name", firstValue) + if (secondValue) params.append("surname", secondValue) + } + console.log(params) apiCall.get((ApiRoutes.USERS + "?" + params.toString()) as ApiRoutes.USERS).then((res) => { - setUsers(res.data) setLoading(false) }) @@ -62,49 +108,63 @@ const ProfileContent = () => { form={form} name="search" onFinish={onSearch} + onChange={validate} + validateTrigger={[]} > - + + + setSearchType(value)} - style={{ width: 120 }} - options={[ - { label: t("editRole.email"), value: "email" }, - { label: t("editRole.name"), value: "name" }, - { label: t("editRole.surname"), value: "surname" }, - ]} - /> - } - /> + + {searchType === "name" && ( + + + + )} + + + {isError && {searchType === "email" ? t("editRole.emailError") : t("editRole.nameError")}} +
+ {users !== null ? ( <> {loading ? ( diff --git a/frontend/src/pages/editRole/components/UserList.tsx b/frontend/src/pages/editRole/components/UserList.tsx index ed4b77bf..c62e5c55 100644 --- a/frontend/src/pages/editRole/components/UserList.tsx +++ b/frontend/src/pages/editRole/components/UserList.tsx @@ -6,6 +6,7 @@ import { useState } from "react" import { UsersType } from "../EditRole" import { GET_Responses, ApiRoutes } from "../../../@types/requests.d" import { User } from "../../../providers/UserProvider" +import useUser from "../../../hooks/useUser" //this is ugly, but if I put this in GET_responses, it will be confused with the User type (and there's no GET request with this as a response). //this is also the only place this is used, so I think it's fine. @@ -16,9 +17,10 @@ const UserList: React.FC<{ users: UsersType; updateRole: (user: UsersListItem, r const [visible, setVisible] = useState(false) const [selectedUser, setSelectedUser] = useState(null) const [selectedRole, setSelectedRole] = useState(null) + const { user } = useUser() - const handleMenuClick = (user: UsersListItem, role: UserRole) => { - setSelectedUser(user) + const handleMenuClick = (listuser: UsersListItem, role: UserRole) => { + setSelectedUser(listuser) setSelectedRole(role) setVisible(true) } @@ -44,12 +46,13 @@ const UserList: React.FC<{ users: UsersType; updateRole: (user: UsersListItem, r return a.email.localeCompare(b.email); }); - const renderUserItem = (user: UsersListItem) => ( + const renderUserItem = (listuser: UsersListItem) => ( - + handleMenuClick(user, e.key as UserRole), + selectedKeys: [listuser.role], + onClick: (e) => handleMenuClick(listuser, e.key as UserRole), }} > e.preventDefault()}> - {t("editRole." + user.role)} + {t("editRole." + listuser.role)}