Skip to content

Commit

Permalink
✨ Add form for questionnaire import
Browse files Browse the repository at this point in the history
Signed-off-by: ibolton336 <[email protected]>
  • Loading branch information
ibolton336 committed Aug 16, 2023
1 parent a9f64a7 commit 9863525
Show file tree
Hide file tree
Showing 3 changed files with 182 additions and 1 deletion.
1 change: 1 addition & 0 deletions client/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@
"unknown": "Unknown",
"unsuitableForContainers": "Unsuitable for containers",
"uploadApplicationFile": "Upload your application file",
"uploadYamlFile": "Upload your YAML file",
"url": "URL",
"user": "User",
"version": "Version",
Expand Down
5 changes: 4 additions & 1 deletion client/src/app/pages/assessment/AssessmentSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import { useLocalTableControls } from "@app/hooks/table-controls";
import { NotificationsContext } from "@app/components/NotificationsContext";
import { getAxiosErrorMessage } from "@app/utils/utils";
import { Questionnaire } from "@app/api/models";
import { ImportQuestionnaireForm } from "./import-questionnaire-form/import-questionnaire-form";

export const AssessmentSettings: React.FC = () => {
const { t } = useTranslation();
Expand Down Expand Up @@ -373,7 +374,9 @@ export const AssessmentSettings: React.FC = () => {
isOpen={isImportModal}
onClose={() => setIsImportModal(false)}
>
<Text>TODO Import questionnaire component</Text>
<ImportQuestionnaireForm
onSaved={() => setIsImportModal(false)}
></ImportQuestionnaireForm>
</Modal>
<Modal
id="download.template.modal"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
import React, { useState } from "react";
import axios, { AxiosResponse } from "axios";
import { useTranslation } from "react-i18next";
import * as yup from "yup";

import {
ActionGroup,
Button,
ButtonVariant,
Checkbox,
FileUpload,
Form,
FormGroup,
FormHelperText,
HelperText,
HelperTextItem,
} from "@patternfly/react-core";

import { UPLOAD_FILE } from "@app/api/rest";
import { getAxiosErrorMessage } from "@app/utils/utils";
import { NotificationsContext } from "@app/components/NotificationsContext";
import { HookFormPFGroupController } from "@app/components/HookFormPFFields";
import { useForm } from "react-hook-form";
import { FileLoadError, IReadFile } from "@app/api/models";
import { yupResolver } from "@hookform/resolvers/yup";
import { useCreateFileMutation } from "@app/queries/targets";

export interface ImportQuestionnaireFormProps {
onSaved: (response: AxiosResponse) => void;
}
export interface ImportQuestionnaireFormValues {
yamlFile: IReadFile;
}

export const yamlFileSchema: yup.SchemaOf<IReadFile> = yup.object({
fileName: yup.string().required(),
fullFile: yup.mixed<File>(),
loadError: yup.mixed<FileLoadError>(),
loadPercentage: yup.number(),
loadResult: yup.mixed<"danger" | "success" | undefined>(),
data: yup.string(),
responseID: yup.number(),
});

export const ImportQuestionnaireForm: React.FC<
ImportQuestionnaireFormProps
> = ({ onSaved }) => {
const { t } = useTranslation();
const { pushNotification } = React.useContext(NotificationsContext);

const [filename, setFilename] = React.useState<string>();
const [isFileRejected, setIsFileRejected] = useState(false);
const validationSchema: yup.SchemaOf<ImportQuestionnaireFormValues> = yup
.object()
.shape({
yamlFile: yamlFileSchema,
});
const methods = useForm<ImportQuestionnaireFormValues>({
resolver: yupResolver(validationSchema),
mode: "onChange",
});

const {
handleSubmit,
formState: { isSubmitting, isValidating, isValid, isDirty },
getValues,
setValue,
control,
watch,
setFocus,
clearErrors,
trigger,
reset,
} = methods;

const { mutateAsync: createYamlFileAsync } = useCreateFileMutation();

const handleFileUpload = async (file: File) => {
setFilename(file.name);
const formFile = new FormData();
formFile.append("file", file);

const newYamlFile: IReadFile = {
fileName: file.name,
fullFile: file,
};

return createYamlFileAsync({
formData: formFile,
file: newYamlFile,
});
};

const onSubmit = (values: ImportQuestionnaireFormValues) => {
console.log("values", values);
};
return (
<Form onSubmit={handleSubmit(onSubmit)}>
<HookFormPFGroupController
control={control}
name="yamlFile"
label={t("terms.uploadYamlFile")}
fieldId="yamlFile"
helperText="Upload a YAML file"
renderInput={({ field: { onChange, name }, fieldState: { error } }) => (
<FileUpload
id="yamlFile"
name={name}
value={filename}
filename={filename}
filenamePlaceholder="Drag and drop a file or upload one"
dropzoneProps={{
accept: {
"text/yaml": [".yml", ".yaml"],
// "text/xml": [".xml"],
},
maxSize: 1000000,
onDropRejected: (event) => {
const currentFile = event[0];
if (currentFile.file.size > 1000000) {
methods.setError("yamlFile", {
type: "custom",
message: "Max file size of 1 MB exceeded.",
});
}
setIsFileRejected(true);
},
}}
validated={isFileRejected || error ? "error" : "default"}
onFileInputChange={async (_, file) => {
console.log("uploading file", file);
handleFileUpload(file)
.then((res) => {
// setValue("yamlFile", res);
setFocus("yamlFile");
clearErrors("yamlFile");
trigger("yamlFile");
})
.catch((err) => {
// setValue("yamlFile", null);
});
}}
onClearClick={() => {
console.log("clearing file");
// onChange(0);
// setFilename("default.png");
// setValue("imageID", null);
// setIsImageFileRejected(false);
}}
browseButtonText="Upload"
/>
)}
/>

{isFileRejected && (
<FormHelperText>
<HelperText>
<HelperTextItem variant="error">
You should select a YAML file.
</HelperTextItem>
</HelperText>
</FormHelperText>
)}
<ActionGroup>
<Button
type="submit"
aria-label="submit"
id="import-questionnaire-submit-button"
variant={ButtonVariant.primary}
isDisabled={!isValid || isSubmitting || isValidating || !isDirty}
>
{t("actions.import")}
</Button>
</ActionGroup>
</Form>
);
};

0 comments on commit 9863525

Please sign in to comment.