Skip to content

Commit

Permalink
Merge pull request #293 from SELab-2/test_page_update
Browse files Browse the repository at this point in the history
Added dropdown and updates to the testpage
  • Loading branch information
Aqua-sc authored May 23, 2024
2 parents caea261 + b145026 commit 90642fc
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 127 deletions.
1 change: 1 addition & 0 deletions frontend/public/docker_langauges/bash.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/public/docker_langauges/custom.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/public/docker_langauges/haskell.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/public/docker_langauges/node-js.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions frontend/public/docker_langauges/python.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
100 changes: 71 additions & 29 deletions frontend/src/components/forms/projectFormTabs/DockerFormTab.tsx
Original file line number Diff line number Diff line change
@@ -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<DockerLanguage, string> = {
bash: "fedora",
python: "python",
node: "node",
haskell: "haskell",
custom: ""
}

const imageToLanguage: Record<string, DockerLanguage> = {
fedora: "bash",
python: "python",
node: "node",
haskell: "haskell",
}


const languagesSelectorItems:SelectProps["options"] = [
{
label: <><img src={BashIcon} className="select-icon" />Bash</>,
value: "bash",
},{
label: <><img src={PythonIcon} className="select-icon" />Python</>,
value: "python",
}, {
label: <><img src={NodeIcon} className="select-icon" />NodeJS</>,
value: "node",
}, {
label: <><img src={HaskellIcon} className="select-icon" />Haskell</>,
value: "haskell",
}, {
label: <><img src={Custom} className="select-icon" />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)
Expand All @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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"
}


Expand All @@ -110,11 +147,16 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
name="dockerImage"
>
<Input
style={{ marginTop: "8px" }}
addonBefore={
<Select
style={{ width: 150 }}
value={dockerImageSelect}
onChange={(val:DockerLanguage) => form.setFieldValue("dockerImage", languageOptions[val])}
options={languagesSelectorItems}
/>}
placeholder={t("project.tests.dockerImagePlaceholder")}
/>
</Form.Item>

<>
<Form.Item
rules={[{ required: !dockerDisabled, message: t("project.tests.dockerScriptRequired") }]}
Expand All @@ -127,10 +169,10 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
}
name="dockerScript"
>
<Input.TextArea
<TextArea
disabled={dockerDisabled}
autoSize={{ minRows: 8 }}
style={{ fontFamily: "monospace", whiteSpace: "pre", overflowX: "auto"}}
style={{ fontFamily: "monospace", whiteSpace: "pre", overflowX: "auto" }}
placeholder={scriptPlaceholder}
/>
</Form.Item>
Expand Down Expand Up @@ -224,4 +266,4 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
)
}

export default DockerFormTab
export default DockerFormTab
166 changes: 74 additions & 92 deletions frontend/src/components/forms/projectFormTabs/GeneralFormTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<>
<Form.Item
label={t("project.change.name")}
name="name"
rules={[{ required: true, message: t("project.change.nameMessage") }]}
>
<Input />
</Form.Item>
return (
<>
<Form.Item
label={t("project.change.name")}
name="name"
rules={[{ required: true, message: t("project.change.nameMessage") }]}
>
<Input />
</Form.Item>

<Typography.Text>
{t("project.change.description")}
</Typography.Text>
<MarkdownEditor value={description} maxLength={5000} />
<Typography.Text>{t("project.change.description")}</Typography.Text>
<MarkdownEditor
value={description}
maxLength={5000}
/>

<Form.Item
label={t("project.change.visible")}
required
name="visible"
valuePropName="checked"
>
<Switch />
</Form.Item>
<Form.Item
label={t("project.change.visible")}
required
name="visible"
valuePropName="checked"
>
<Switch />
</Form.Item>

{!visible && (
<Form.Item
label={t("project.change.visibleAfter")}
tooltip={t("project.change.visibleAfterTooltip")}
name="visibleAfter"
>
<DatePicker
showTime
format="YYYY-MM-DD HH:mm:ss"
allowClear={true}
disabledDate={(current) => current && current.isBefore(dayjs().startOf('day'))}
/>
</Form.Item>
)}
{!visible && (
<Form.Item
label={t("project.change.visibleAfter")}
tooltip={t("project.change.visibleAfterTooltip")}
name="visibleAfter"
>
<DatePicker
showTime
format="YYYY-MM-DD HH:mm:ss"
allowClear={true}
disabledDate={(current) => current && current.isBefore(dayjs().startOf("day"))}
/>
</Form.Item>
)}

<Form.Item
label={t("project.change.maxScore")}
name="maxScore"
tooltip={t("project.change.maxScoreHelp")}
rules={[{ required: false, message: t("project.change.maxScoreMessage") }]}
>
<Input
min={1}
max={1000}
type="number"
/>
</Form.Item>
<Form.Item
label={t("project.change.maxScore")}
name="maxScore"
tooltip={t("project.change.maxScoreHelp")}
rules={[{ required: false, message: t("project.change.maxScoreMessage") }]}
>
<Input
min={1}
max={1000}
type="number"
/>
</Form.Item>

<Form.Item
label={t("project.change.deadline")}
name="deadline"
rules={[{ required: true }]}
>
<DatePicker
showTime={{
format: "HH:mm:ss",
disabledHours: () => {
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'))}

/>
</Form.Item>
</>
)
<Form.Item
label={t("project.change.deadline")}
name="deadline"
rules={[{ required: true }]}
>
<DatePicker
showTime={{
format: "HH:mm:ss",
disabledHours: () => {
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"))}
/>
</Form.Item>
</>
)
}

export default GeneralFormTab
2 changes: 1 addition & 1 deletion frontend/src/i18n/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -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.",
Expand Down
Loading

0 comments on commit 90642fc

Please sign in to comment.