diff --git a/backend/pigeonhole/tests/test_views/test_submission/test_student.py b/backend/pigeonhole/tests/test_views/test_submission/test_student.py index ad75a845..34cf41e0 100644 --- a/backend/pigeonhole/tests/test_views/test_submission/test_student.py +++ b/backend/pigeonhole/tests/test_views/test_submission/test_student.py @@ -121,6 +121,7 @@ def test_can_create_submission_without_forbidden_wildcard(self): "file_urls": "src/main.jar, src/test.dockerfile"}) self.assertEqual(0, response.data['success']) self.assertEqual(response.status_code, status.HTTP_201_CREATED) + # def test_can_create_submission_with_forbidden_wildcard(self): response = self.client.post(API_ENDPOINT, {"group_id": self.group_4.group_id, "file_urls": "src/main.py"}) diff --git a/frontend/app/[locale]/components/ProjectDetailsPage.tsx b/frontend/app/[locale]/components/ProjectDetailsPage.tsx index 974b5d53..cbd9aba1 100644 --- a/frontend/app/[locale]/components/ProjectDetailsPage.tsx +++ b/frontend/app/[locale]/components/ProjectDetailsPage.tsx @@ -152,7 +152,16 @@ const ProjectDetailsPage: React.FC = ({ )} {t("required_files")} - {project?.file_structure} + +
+                    {generateDirectoryTree(project?.file_structure).split('\n').map((line: string, index: number) => (
+                            
+                                {line}
+                                
+
+ ))} +
+
{t("conditions")} {project?.conditions} @@ -220,4 +229,44 @@ const ProjectDetailsPage: React.FC = ({ ); }; -export default ProjectDetailsPage; +function buildTree(paths) { + const tree = {}; + const paths_list = paths.split(','); + paths_list.forEach(path => { + const parts = path.split('/'); + let current = tree; + + parts.forEach((part, index) => { + if (!current[part]) { + if (index === parts.length - 1) { + current[part] = {}; + } else { + current[part] = current[part] || {}; + } + } + current = current[part]; + }); + }); + + return tree; +} + +function buildTreeString(tree, indent = '') { + let treeString = ''; + + const keys = Object.keys(tree); + keys.forEach((key, index) => { + const isLast = index === keys.length - 1; + treeString += `${indent}${isLast ? '└── ' : '├── '}${key}\n`; + treeString += buildTreeString(tree[key], indent + (isLast ? ' ' : '│ ')); + }); + + return treeString; +} + +function generateDirectoryTree(filePaths) { + const tree = buildTree(filePaths); + return `.\n${buildTreeString(tree)}`; +} + +export default ProjectDetailsPage; \ No newline at end of file diff --git a/frontend/app/[locale]/components/general/RequiredFilesList.tsx b/frontend/app/[locale]/components/general/RequiredFilesList.tsx new file mode 100644 index 00000000..e2564ed1 --- /dev/null +++ b/frontend/app/[locale]/components/general/RequiredFilesList.tsx @@ -0,0 +1,107 @@ +"use client" + +import {IconButton, List, ListItem, ListItemText, TextField, Typography, Button} from "@mui/material"; +import DeleteIcon from "@mui/icons-material/Delete"; +import React, {useState} from "react"; +import Box from "@mui/material/Box"; + +interface ItemsListProps { + items: string[], + setItems: (value: (((prevState: any[]) => any[]) | any[])) => void, + input_placeholder: string, + empty_list_placeholder:string, + button_text: string +} + +const ItemsList = ({items, setItems, input_placeholder, empty_list_placeholder, button_text}: ItemsListProps) => { + const [newItem, setNewItem] = useState('') + const [noInput, setNoInput] = useState(false) + + const handleDelete = (index: number) => { + const newFields = [...items]; + newFields.splice(index, 1); + setItems(newFields); + } + + const addNewFile = () => { + if (newItem !== '') { + const newItems = [...items]; + newItems.push(newItem) + setItems(newItems); + setNewItem(''); + setNoInput(false); + console.log(items); + } else { + setNoInput(true); + } + } + + return ( + + {items.length === 0 ? ( + {empty_list_placeholder} + ) : ( + + {items.map((field, index) => ( + handleDelete(index)} + > + + + } + > + + + ))} + + ) + } + + setNewItem(event.target.value)} + variant="outlined" + size="small" + error={noInput} + placeholder={input_placeholder} + sx={{ + width: 'fit-content', + }} + /> + + + + ); +} + +export default ItemsList \ No newline at end of file diff --git a/frontend/app/[locale]/project/[project_id]/edit/projectEditForm.tsx b/frontend/app/[locale]/project/[project_id]/edit/projectEditForm.tsx index 49418277..79cd926a 100644 --- a/frontend/app/[locale]/project/[project_id]/edit/projectEditForm.tsx +++ b/frontend/app/[locale]/project/[project_id]/edit/projectEditForm.tsx @@ -273,7 +273,7 @@ function ProjectEditForm({project_id, add_course_id}: ProjectEditFormProps) { ) : (