Skip to content

Commit

Permalink
added container menu dropdown
Browse files Browse the repository at this point in the history
  • Loading branch information
Triver1 committed May 23, 2024
1 parent 35d3f62 commit 8e0f1f7
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 44 deletions.
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.
105 changes: 67 additions & 38 deletions frontend/src/components/forms/projectFormTabs/DockerFormTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import { classicNameResolver } from "typescript"
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"

const UploadBtn: React.FC<{ form: FormInstance; fieldName: string; textFieldProps?: TextAreaProps; disabled?: boolean }> = ({ form, fieldName, disabled }) => {
const handleFileUpload = (file: File) => {
const reader = new FileReader()
Expand Down Expand Up @@ -45,27 +51,41 @@ const UploadBtn: React.FC<{ form: FormInstance; fieldName: string; textFieldProp

interface Script {
displayName: string;
scriptGenerator: (script: string) => string;
image?: string;
image: string;
icon: string;
}

interface ScriptCollection {
[key: string]: Script;
}

export const languageOptions: ScriptCollection = {
"bash": { displayName: "Bash", image: "fedora", icon: BashIcon },
"python": { displayName: "Python", image: "python", icon: PythonIcon },
"javascript": { displayName: "Javascript (node)", image: "node", icon: NodeIcon },
"haskell": { displayName: "Haskell", image: "haskell", icon: HaskellIcon },
"custom": { displayName: "Custom", image: "", icon: Custom }
}

export function imageToLanguage(script: string): string {
for(const language in languageOptions) {
if(script === languageOptions[language].image) {
return language
}
}
return ""
}


const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
const { t } = useTranslation()
const {message} = useAppApi()
const [withTemplate, setWithTemplate] = useState<boolean>(true)
const [selectedLanguage, setSelectedLanguage] = useState<string>("bash")
const dockerImage = Form.useWatch("dockerImage", form)

const dockerDisabled = !dockerImage?.length
const languageOptions:ScriptCollection = {
"bash": {displayName:"Bash", scriptGenerator: (script: string) => script, image: "fedora"},
"python": {displayName:"Python", scriptGenerator: (script: string) => `python -c '${script}'`, image: "python"},
"javascript": {displayName:"Javascript (node)", scriptGenerator: (script: string) => `node -e '${script}', image: "node"`},
"haskell": {displayName:"Haskell", scriptGenerator: (script: string) => `runhaskell -e '${script}'`, image: "haskell"}
}


function isValidTemplate(template: string): string {
if (!template?.length) return "" // Template is optional
Expand Down Expand Up @@ -124,28 +144,46 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
return (
<>
<Form.Item
label={
<MarkdownTooltip
label={"Docker Image"}
tooltipContent={t("project.tests.dockerImageTooltip")}
placement="right"
/>
}

name="dockerImage"
label={
<MarkdownTooltip
label={"Docker Image"}
tooltipContent={t("project.tests.dockerImageTooltip")}
placement="right"
/>
}
name="dockerImage"
>
{ <Input
style={{ marginTop: "8px" }}
placeholder={t("project.tests.dockerImagePlaceholder")}
/>}
<Input.Group compact>
<Form.Item
name="languageSelect"
noStyle
>
<Select
defaultValue={Object.keys(languageOptions)[0]}
onChange={(val) => form.setFieldValue( "dockerImage", languageOptions[val].image)}
style={{ width: '30%' }}
>
{Object.keys(languageOptions).map((key) => (
<Select.Option key={key} value={key}>
<span style={{ marginRight: 8 }}>
<img src={languageOptions[key].icon} alt={languageOptions[key].displayName} style={{ height: '16px', verticalAlign: 'middle' }} />
</span>
{languageOptions[key].displayName}
</Select.Option>
))}
</Select>
</Form.Item>
<Form.Item
name="dockerImage"
noStyle
>
<Input
style={{ width: '70%' }}
placeholder={t("project.tests.dockerImagePlaceholder")}
/>
</Form.Item>
</Input.Group>
</Form.Item>

<Select defaultValue={Object.keys(languageOptions)[0]} onChange={(val) => form.setFieldValue( "dockerImage", val)}>
{Object.keys(languageOptions).map((key) => (
<Select.Option value={key}>{languageOptions[key].displayName}</Select.Option>
))}
</Select>

<>
<Form.Item
rules={[{ required: !dockerDisabled, message: "Docker script is required" }]}
Expand Down Expand Up @@ -193,11 +231,6 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
<Button disabled={dockerDisabled} icon={<UploadOutlined />}>Upload test directory (zip)</Button>
</Upload>
</Form.Item>
{/* <UploadBtn
form={form}
disabled={dockerDisabled}
fieldName="dockerScript"
/> */}
<div style={{ paddingBottom: '14px'}}>
<Switch
checked={withTemplate}
Expand All @@ -212,6 +245,7 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
<div>
<MarkdownTextfield content={t("project.tests.templateModeInfo")} />


<Form.Item
label={t("project.tests.dockerTemplate")}
name="dockerTemplate"
Expand All @@ -231,11 +265,6 @@ const DockerFormTab: FC<{ form: FormInstance }> = ({ form }) => {
style={{fontFamily: "monospace", whiteSpace: "pre", overflowX: "auto"}}
placeholder={"@helloWorldTest\n>required\n>description=\"This is a test\"\nExpected output 1\n\n@helloUGent\n>optional\nExpected output 2\n"}
/>
{/*<UploadBtn
form={form}
disabled={dockerDisabled}
fieldName="dockerTemplate"
/>*/}
</Form.Item> </div>: <Form.Item
name="simpleMode"
children={<MarkdownTextfield content={t("project.tests.simpleModeInfo")} />}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/i18n/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,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.\n\nThese files are available in the folder `'/shared/extra'`.",
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/i18n/nl/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,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.\n\nDeze bestanden zijn beschikbaar in de map `'/shared/extra'`.",
Expand Down Expand Up @@ -247,7 +247,7 @@
"getStarted": "Aan de slag",
"docs": "Documentatie"
},

"submission": {
"submission": "Indiening",
"submittedFiles": "Ingediende bestanden:",
Expand Down
11 changes: 8 additions & 3 deletions frontend/src/pages/editProject/EditProject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { AppRoutes } from "../../@types/routes"
import { ProjectContext } from "../../router/ProjectRoutes"
import useApi from "../../hooks/useApi"
import saveDockerForm, { DockerFormData } from "../../components/common/saveDockerForm"
import {imageToLanguage} from "../../components/forms/projectFormTabs/DockerFormTab";

const EditProject: React.FC = () => {
const [form] = Form.useForm<ProjectFormData & DockerFormData>()
Expand Down Expand Up @@ -40,10 +41,9 @@ const EditProject: React.FC = () => {
dockerScript: null,
dockerImage: null,
}

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!)

Expand All @@ -64,10 +64,12 @@ const EditProject: React.FC = () => {
dockerScript: tests.dockerScript ?? "",
dockerImage: tests.dockerImage ?? "",
}
const selectedLanguage = imageToLanguage(formVals.dockerImage ?? "")
formVals.dockerScript = selectedLanguage[1] // We only want the script, not the language
form.setFieldValue("languageSelect", selectedLanguage)
}

form.setFieldsValue(formVals)

setInitialDockerValues(formVals)
}

Expand All @@ -80,6 +82,9 @@ const EditProject: React.FC = () => {

const handleCreation = async () => {
const values: ProjectFormData & DockerFormData = form.getFieldsValue()

console.log(values)

if (values.visible) {
values.visibleAfter = null
}
Expand Down

0 comments on commit 8e0f1f7

Please sign in to comment.