diff --git a/frontend/public/docker_langauges/bash.svg b/frontend/public/docker_langauges/bash.svg
new file mode 100644
index 00000000..890b5d92
--- /dev/null
+++ b/frontend/public/docker_langauges/bash.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/public/docker_langauges/custom.svg b/frontend/public/docker_langauges/custom.svg
new file mode 100644
index 00000000..c3416414
--- /dev/null
+++ b/frontend/public/docker_langauges/custom.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/public/docker_langauges/haskell.svg b/frontend/public/docker_langauges/haskell.svg
new file mode 100644
index 00000000..0c627ebd
--- /dev/null
+++ b/frontend/public/docker_langauges/haskell.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/public/docker_langauges/node-js.svg b/frontend/public/docker_langauges/node-js.svg
new file mode 100644
index 00000000..3e77c253
--- /dev/null
+++ b/frontend/public/docker_langauges/node-js.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/public/docker_langauges/python.svg b/frontend/public/docker_langauges/python.svg
new file mode 100644
index 00000000..bf2a1601
--- /dev/null
+++ b/frontend/public/docker_langauges/python.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/components/forms/projectFormTabs/DockerFormTab.tsx b/frontend/src/components/forms/projectFormTabs/DockerFormTab.tsx
index edd80af6..f09d02a6 100644
--- a/frontend/src/components/forms/projectFormTabs/DockerFormTab.tsx
+++ b/frontend/src/components/forms/projectFormTabs/DockerFormTab.tsx
@@ -1,18 +1,62 @@
-import { UploadOutlined } from "@ant-design/icons"
-import {Button, Form, Input, Switch, Upload} from "antd"
+import { CodepenCircleFilled, InboxOutlined, UploadOutlined } from "@ant-design/icons"
+import { Button, Dropdown, Form, Input, Menu, Select, SelectProps, Switch, Upload } from "antd"
+import { TextAreaProps } from "antd/es/input"
import { FormInstance } from "antd/lib"
-import {FC, useEffect} from "react"
+import React, { FC, useEffect, useLayoutEffect, useMemo, useState } from "react"
import { useTranslation } from "react-i18next"
import useAppApi from "../../../hooks/useAppApi"
import MarkdownTooltip from "../../common/MarkdownTooltip"
import MarkdownTextfield from "../../input/MarkdownTextfield"
+import TextArea from "antd/es/input/TextArea"
+
+import BashIcon from "../../../../public/docker_langauges/bash.svg"
+import PythonIcon from "../../../../public/docker_langauges/python.svg"
+import NodeIcon from "../../../../public/docker_langauges/node-js.svg"
+import HaskellIcon from "../../../../public/docker_langauges/haskell.svg"
+import Custom from "../../../../public/docker_langauges/custom.svg"
+
+
+type DockerLanguage = "bash" | "python" | "node" | "haskell" | "custom"
+const languageOptions: Record = {
+ bash: "fedora",
+ python: "python",
+ node: "node",
+ haskell: "haskell",
+ custom: ""
+}
+
+const imageToLanguage: Record = {
+ fedora: "bash",
+ python: "python",
+ node: "node",
+ haskell: "haskell",
+}
+
+
+const languagesSelectorItems:SelectProps["options"] = [
+ {
+ label: <>Bash>,
+ value: "bash",
+ },{
+ label: <>Python>,
+ value: "python",
+ }, {
+ label: <>NodeJS>,
+ value: "node",
+ }, {
+ label: <>Haskell>,
+ value: "haskell",
+ }, {
+ label: <>Custom>,
+ value: "custom",
+ }
+]
const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
const { t } = useTranslation()
- const {message} = useAppApi()
-
+ const { message } = useAppApi()
const dockerImage = Form.useWatch("dockerImage", form)
const dockerTemplate = Form.useWatch("dockerTemplate", form)
const dockerMode = Form.useWatch("dockerMode", form)
@@ -28,6 +72,8 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
form.validateFields(["dockerScript", "dockerTemplate"])
}, [dockerDisabled])
+
+ const dockerImageSelect= useMemo(()=> imageToLanguage[dockerImage] || "custom",[dockerImage])
function isValidTemplate(template: string): string {
if (template.length === 0) {
@@ -56,7 +102,7 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
const isDescription = line.length >= 13 && line.substring(0, 13).toLowerCase() === ">description="
// option lines
if (line.toLowerCase() !== ">required" && line.toLowerCase() !== ">optional" && !isDescription) {
- return t("project.tests.dockerTemplateValidation.inValidOptions", { line:lineNumber.toString() })
+ return t("project.tests.dockerTemplateValidation.inValidOptions", { line: lineNumber.toString() })
}
} else {
isConfigurationLine = false
@@ -69,31 +115,22 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
return ""
}
-
-
const normFile = (e: any) => {
if (Array.isArray(e)) {
- return e;
+ return e
}
- return e?.fileList;
- };
+ return e?.fileList
+ }
- let switchClassName = 'template-switch'
+ let switchClassName = "template-switch"
let scriptPlaceholder
-
+
if (withTemplate) {
- switchClassName += ' template-switch-active'
- scriptPlaceholder = "bash /shared/input/helloworld.sh > \"/shared/output/helloWorldTest\"\n"+
- "bash /shared/input/helloug.sh > \"/shared/output/helloUGent\"\n"
+ switchClassName += " template-switch-active"
+ scriptPlaceholder = 'bash /shared/input/helloworld.sh > "/shared/output/helloWorldTest"\n' + 'bash /shared/input/helloug.sh > "/shared/output/helloUGent"\n'
} else {
- switchClassName += ' template-switch-inactive'
- scriptPlaceholder = "output=$(bash /shared/input/helloworld.sh)\n"+
- "if [[ \"$output\" == \"Hello World\" ]]; then \n"+
- " echo 'Test one is successful\n"+
- " echo 'PUSH ALLOWED' > /shared/output/testOutput\n"+
- "else\n"+
- " echo 'Test one failed: script failed to print \"Hello World\"'\n"+
- "fi"
+ switchClassName += " template-switch-inactive"
+ scriptPlaceholder = "output=$(bash /shared/input/helloworld.sh)\n" + 'if [[ "$output" == "Hello World" ]]; then \n' + " echo 'Test one is successful\n" + " echo 'PUSH ALLOWED' > /shared/output/testOutput\n" + "else\n" + " echo 'Test one failed: script failed to print \"Hello World\"'\n" + "fi"
}
@@ -110,11 +147,16 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
name="dockerImage"
>
form.setFieldValue("dockerImage", languageOptions[val])}
+ options={languagesSelectorItems}
+ />}
placeholder={t("project.tests.dockerImagePlaceholder")}
/>
-
<>
= ({ form }) => {
}
name="dockerScript"
>
-
@@ -224,4 +266,4 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
)
}
-export default DockerFormTab
+export default DockerFormTab
\ No newline at end of file
diff --git a/frontend/src/components/forms/projectFormTabs/GeneralFormTab.tsx b/frontend/src/components/forms/projectFormTabs/GeneralFormTab.tsx
index 37d1357d..df5ca7c5 100644
--- a/frontend/src/components/forms/projectFormTabs/GeneralFormTab.tsx
+++ b/frontend/src/components/forms/projectFormTabs/GeneralFormTab.tsx
@@ -2,106 +2,88 @@ import { DatePicker, Form, FormInstance, Input, Switch, Typography } from "antd"
import { useTranslation } from "react-i18next"
import { FC } from "react"
import MarkdownEditor from "../../input/MarkdownEditor"
-import dayjs from 'dayjs';
+import dayjs from "dayjs"
const GeneralFormTab: FC<{ form: FormInstance }> = ({ form }) => {
- const { t } = useTranslation()
- const description = Form.useWatch("description", form)
- const visible = Form.useWatch("visible", form)
+ const { t } = useTranslation()
+ const description = Form.useWatch("description", form)
+ const visible = Form.useWatch("visible", form)
- return (
- <>
-
-
-
+ return (
+ <>
+
+
+
-
- {t("project.change.description")}
-
-
+ {t("project.change.description")}
+
-
-
-
+
+
+
- {!visible && (
-
- current && current.isBefore(dayjs().startOf('day'))}
- />
-
- )}
+ {!visible && (
+
+ current && current.isBefore(dayjs().startOf("day"))}
+ />
+
+ )}
-
-
-
+
+
+
-
- {
- const hours = [];
- for (let i = 0; i < dayjs().hour(); i++) {
- hours.push(i);
- }
- return hours;
- },
- disabledMinutes: (selectedHour) => {
- const minutes = [];
- if (selectedHour === dayjs().hour()) {
- for (let i = 0; i < dayjs().minute(); i++) {
- minutes.push(i);
- }
- }
- return minutes;
- },
- disabledSeconds: (selectedHour, selectedMinute) => {
- const seconds = [];
- if (selectedHour === dayjs().hour() && selectedMinute === dayjs().minute()) {
- for (let i = 0; i < dayjs().second(); i++) {
- seconds.push(i);
- }
- }
- return seconds;
- },
- }}
- format="YYYY-MM-DD HH:mm:ss"
- disabledDate={(current) => current && current.isBefore(dayjs().startOf('day'))}
-
- />
-
- >
- )
+
+ {
+ const hours = []
+ for (let i = 0; i < dayjs().hour(); i++) {
+ hours.push(i)
+ }
+ return hours
+ },
+ }}
+ format="YYYY-MM-DD HH:mm:ss"
+ disabledDate={(current) => current && current.isBefore(dayjs().startOf("day"))}
+ />
+
+ >
+ )
}
export default GeneralFormTab
diff --git a/frontend/src/i18n/en/translation.json b/frontend/src/i18n/en/translation.json
index 54faddf6..292d63ff 100644
--- a/frontend/src/i18n/en/translation.json
+++ b/frontend/src/i18n/en/translation.json
@@ -213,7 +213,7 @@
"simpleMode": "Without template",
"templateMode": "With template",
"fileStructureTooltip": "This templates specifies the file structure a submission has to follow.\nIt uses the following syntax:\n* Folders end on `'/'`\n* Use indents to specify files inside a folder\n* Regex can be used\n\t* `'.'` is still a normal `'.'`\n\t* `'\\.'` can be used as regex `'.'`\n* `'-'` at the start of a line specifies a file/folder that is not allowed",
- "dockerImageTooltip": "Specify a valid Docker-container from [Docker Hub](https://hub.docker.com/) on which the test script will be run.",
+ "dockerImageTooltip": "Specify a valid Docker container from [Docker Hub](https://hub.docker.com/) on which the test script will be run. You can also choose a language with a preselected container.",
"dockerScriptTooltip": "Bash-script that is executed.\n* The files of the student's submission can be found in `'/shared/input'`\n* Extra files uploaded below can be found in `'/shared/extra'`\n\n More information about the required output depends on the mode and can be found below.",
"dockerTemplateTooltip": "To specify specific tests, you need to provide a template. First, enter the test name with '@{test}'. Below this, you can use '>' to provide options such as ('>required', '>optional', '>description'). Everything under these options until the next test or the end of the file is the expected output.",
"dockerTestDirTooltip": "Upload additional files needed for the Docker test. These files are available in the folder `'/shared/extra'`.\n\nOnce uploaded u can click the filename to download them again. Uploading a new file will replace the old one.",
diff --git a/frontend/src/i18n/nl/translation.json b/frontend/src/i18n/nl/translation.json
index baadff8a..b5c963aa 100644
--- a/frontend/src/i18n/nl/translation.json
+++ b/frontend/src/i18n/nl/translation.json
@@ -215,7 +215,7 @@
"templateMode": "Met sjabloon",
"fileStructurePreview": "Voorbeeld van bestandsstructuur",
"fileStructureTooltip": "Dit sjabloon specificeert de bestandsstructuur die een indiening moet volgen.\nHet gebruikt de volgende syntax:\n* Mappen eindigen op `'/'`\n* Gebruik inspringing om bestanden binnen een map aan te geven\n* Regex kan worden gebruikt\n\t* `'.'` is nog steeds een normale `'.'`\n\t* `'\\.'` kan worden gebruikt als regex `'.'`\n* `'-'` aan het begin van een regel geeft aan dat een bestand/map niet is toegestaan",
- "dockerImageTooltip": "Specificeer een geldige Docker-container van [Docker Hub](https://hub.docker.com/) waarop het testscript zal worden uitgevoerd.",
+ "dockerImageTooltip": "Specificeer een geldige Docker-container van [Docker Hub](https://hub.docker.com/) waarop het testscript zal worden uitgevoerd. Je kan ook kiezen voor een voorgeconfigureerde programmeertaal met bijhorende container.",
"dockerScriptTooltip": "Bash-script dat wordt uitgevoerd.\n* De bestanden van de student zijn indieningen zijn te vinden in `'/shared/input'`\n* Extra bestanden die hieronder zijn geüpload, zijn te vinden in `'/shared/extra'`\n\nMeer informatie over de vereiste uitvoer is afhankelijk van de modus en is hieronder te vinden.",
"dockerTemplateTooltip": "Om specifieke tests te definiëren, moet je een sjabloon invoeren. Geef eerst de naam van de test in met '@{test}'. Hieronder kun je met een '>' opties geven zoals ('>required', '>optional', '>description'). Alles onder de opties tot de volgende test of het einde van het bestand is de verwachte output.",
"dockerTestDirTooltip": "Upload extra bestanden die nodig zijn voor de dockertest. Deze bestanden zijn beschikbaar in de map `'/shared/extra'`.\n\nAls je een file geüpload hebt kan je deze downloaden door op de bestandsnaam te klikken. Als je een nieuw bestand uploadt zal het oude bestand overschreven worden.",
@@ -250,7 +250,7 @@
"getStarted": "Aan de slag",
"docs": "Documentatie"
},
-
+
"submission": {
"submission": "Indiening",
"submittedFiles": "Ingediende bestanden:",
diff --git a/frontend/src/pages/editProject/EditProject.tsx b/frontend/src/pages/editProject/EditProject.tsx
index cfc75422..7098c253 100644
--- a/frontend/src/pages/editProject/EditProject.tsx
+++ b/frontend/src/pages/editProject/EditProject.tsx
@@ -43,10 +43,9 @@ const EditProject: React.FC = () => {
dockerImage: null,
dockerMode: false
}
+
if (response.success) {
const tests = response.response.data
- console.log(tests)
-
if (tests.extraFilesName) {
const downloadLink = AppRoutes.DOWNLOAD_PROJECT_TESTS.replace(":projectId", projectId).replace(":courseId", courseId!)
@@ -75,7 +74,6 @@ const EditProject: React.FC = () => {
}
form.setFieldsValue(formVals)
-
setInitialDockerValues(formVals)
}
@@ -88,6 +86,9 @@ const EditProject: React.FC = () => {
const handleCreation = async () => {
const values: ProjectFormData & DockerFormData = form.getFieldsValue()
+
+ console.log(values)
+
if (values.visible) {
values.visibleAfter = null
}
diff --git a/frontend/src/styles.css b/frontend/src/styles.css
index 8d61f9c2..9c426dcb 100644
--- a/frontend/src/styles.css
+++ b/frontend/src/styles.css
@@ -181,6 +181,13 @@ html {
}
+.select-icon {
+ width: 1em;
+ margin-right: 0.5rem;
+ position: relative;
+ top: 2px;
+}
+
/* *************************** Landing page *************************** */
.landing-page * {