Skip to content

Commit

Permalink
fix: fixed validation issue in maintenance form fields (#363)
Browse files Browse the repository at this point in the history
  • Loading branch information
valeriocomo authored Dec 12, 2024
1 parent 10afa3b commit d9b642e
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 127 deletions.
39 changes: 36 additions & 3 deletions src/app/components/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import PubliccodeYmlLanguages from "./PubliccodeYmlLanguages";

import { Col, Container, notify, Row } from "design-react-kit";
import { set } from "lodash";
import { useCallback, useState } from "react";
import { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import YAML from "yaml";
import licenses from "../../generated/licenses.json";
Expand Down Expand Up @@ -104,6 +104,7 @@ export default function Editor() {
const configCountrySections = countrySection.parse(DEFAULT_COUNTRY_SECTIONS);
const [currentPublicodeYmlVersion, setCurrentPubliccodeYmlVersion] = useState('');
const [isYamlModalVisible, setYamlModalVisibility] = useState(false);
const [isPublicCodeImported, setPublicCodeImported] = useState(false);

const getNestedValue = (obj: PublicCodeWithDeprecatedFields, path: string) => {
return path.split('.').reduce((acc, key) => (acc as never)?.[key], obj);
Expand Down Expand Up @@ -140,6 +141,8 @@ export default function Editor() {
const methods = useForm<PublicCode | PublicCodeWithDeprecatedFields>({
defaultValues,
resolver,
mode: 'onTouched',
reValidateMode: 'onChange'
});
const { getValues, handleSubmit, watch, setValue, reset } = methods;

Expand Down Expand Up @@ -167,6 +170,33 @@ export default function Editor() {
storage: window?.localStorage, // default window.sessionStorage
exclude: [],
});

const resetMaintenance = useCallback((value: Partial<PublicCode>) => {
const maintenanceType = (value as PublicCode).maintenance.type;

if (maintenanceType === "none") {
setValue('maintenance.contacts', [])
setValue('maintenance.contractors', [])
}

if (maintenanceType === "community" || maintenanceType === "internal") {
setValue('maintenance.contractors', [])
}

if (maintenanceType === "contract") {
setValue('maintenance.contacts', [])
}
}, [setValue])

useEffect(() => {
const subscription = watch((value, { name }) => {
if (name === 'maintenance.type') {
resetMaintenance(value as PublicCode);
}
}
)
return () => subscription.unsubscribe()
}, [watch, resetMaintenance])
//#endregion

//#region form action handlers
Expand All @@ -191,6 +221,7 @@ export default function Editor() {
dispatch(resetPubliccodeYmlLanguages());
reset({ ...defaultValues });
checkPubliccodeYmlVersion(getValues() as PublicCode);
setPublicCodeImported(false);
};

const setFormDataAfterImport = async (
Expand All @@ -210,6 +241,8 @@ export default function Editor() {

checkPubliccodeYmlVersion(publicCode);

setPublicCodeImported(true);

const res = await checkWarnings(values)

if (res.warnings.size) {
Expand Down Expand Up @@ -252,7 +285,7 @@ export default function Editor() {
<div className='mt-3'></div>
<FormProvider {...methods}>
<form>
{currentPublicodeYmlVersion &&
{isPublicCodeImported && currentPublicodeYmlVersion &&
<Row xs="1" md="1">
<Col>
<EditorSelect<"publiccodeYmlVersion">
Expand Down Expand Up @@ -455,7 +488,7 @@ export default function Editor() {
loadFileYaml={(file) => loadFileYamlHandler(file)}
trigger={() => submitHandler()}
languages={languages}
yamlLoaded
yamlLoaded={isPublicCodeImported}
/>
<InfoBox />
<YamlModal
Expand Down
124 changes: 63 additions & 61 deletions src/app/components/EditorContacts.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,68 +29,70 @@ export default function EditorContacts(): JSX.Element {
return (
<fieldset>
<legend>{t(`publiccodeyml.${fieldName}.label`)}</legend>
{field.value?.length === 0 ? null : (
<Table responsive>
<caption><small>{t(`publiccodeyml.${fieldName}.affiliation.description`)}</small></caption>
<thead>
<tr>
<th className="align-top">#</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.name.label`)} *
</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.email.label`)}
</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.phone.label`)}
</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.affiliation.label`)}
</th>
<th></th>
</tr>
</thead>
<tbody>
{fields.map(({ id }, index) => (
<tr key={id}>
<th scope="row">{index + 1}</th>
{subfields.map((subfield) => {
const { ref, ...reg } = register(
`${fieldName}.${index}.${subfield}`
);

return (
<td key={subfield}>
<Input
{...reg}
innerRef={ref}
valid={
get(errors, `${fieldName}.${index}.${subfield}`) &&
false
}
validationText={get(
errors,
`${fieldName}.${index}.${subfield}.message`
)}
/>
</td>
);
})}
<td>
<Button
color="link"
icon
onClick={() => remove(index)}
size="xs"
>
<Icon icon="it-delete" size="sm" title="Remove feature" />
</Button>
</td>
{field.value?.length === 0
? (<p><small>Nessun contatto presente</small></p>)
: (
<Table responsive>
<caption><small>{t(`publiccodeyml.${fieldName}.affiliation.description`)}</small></caption>
<thead>
<tr>
<th className="align-top">#</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.name.label`)} *
</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.email.label`)}
</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.phone.label`)}
</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.affiliation.label`)}
</th>
<th></th>
</tr>
))}
</tbody>
</Table>
)}
</thead>
<tbody>
{fields.map(({ id }, index) => (
<tr key={id}>
<th scope="row">{index + 1}</th>
{subfields.map((subfield) => {
const { ref, ...reg } = register(
`${fieldName}.${index}.${subfield}`
);

return (
<td key={subfield}>
<Input
{...reg}
innerRef={ref}
valid={
get(errors, `${fieldName}.${index}.${subfield}`) &&
false
}
validationText={get(
errors,
`${fieldName}.${index}.${subfield}.message`
)}
/>
</td>
);
})}
<td>
<Button
color="link"
icon
onClick={() => remove(index)}
size="xs"
>
<Icon icon="it-delete" size="sm" title="Remove feature" />
</Button>
</td>
</tr>
))}
</tbody>
</Table>
)}
<Button
color="primary"
onClick={() =>
Expand Down
120 changes: 61 additions & 59 deletions src/app/components/EditorContractors.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,66 +29,68 @@ export default function EditorContractors(): JSX.Element {
return (
<fieldset>
<legend>{t(`publiccodeyml.${fieldName}.label`)}</legend>
{field.value?.length === 0 ? null : (
<Table responsive>
<thead>
<tr>
<th className="align-top">#</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.name.label`)} *
</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.until.label`)} *
</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.email.label`)}
</th>
<th>{t(`publiccodeyml.${fieldName}.website.label`)}</th>
<th></th>
</tr>
</thead>
<tbody>
{fields.map(({ id }, index) => (
<tr key={id}>
<th scope="row">{index + 1}</th>
{subfields.map((subfield) => {
const { ref, ...reg } = register(
`${fieldName}.${index}.${subfield}`
);

return (
<td key={subfield}>
<Input
{...reg}
innerRef={ref}
type={subfield === "until" ? "date" : "text"}
valid={
get(errors, `${fieldName}.${index}.${subfield}`) &&
false
}
validationText={get(
errors,
`${fieldName}.${index}.${subfield}.message`
)}
/>
</td>
);
})}
<td>
<Button
color="link"
icon
onClick={() => remove(index)}
size="xs"
>
<Icon icon="it-delete" size="sm" title="Remove feature" />
</Button>
</td>
{field.value?.length === 0
? (<p><small>Nessun riferimento presente</small></p>)
: (
<Table responsive>
<thead>
<tr>
<th className="align-top">#</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.name.label`)} *
</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.until.label`)} *
</th>
<th className="align-top">
{t(`publiccodeyml.${fieldName}.email.label`)}
</th>
<th>{t(`publiccodeyml.${fieldName}.website.label`)}</th>
<th></th>
</tr>
))}
</tbody>
</Table>
)}
</thead>
<tbody>
{fields.map(({ id }, index) => (
<tr key={id}>
<th scope="row">{index + 1}</th>
{subfields.map((subfield) => {
const { ref, ...reg } = register(
`${fieldName}.${index}.${subfield}`
);

return (
<td key={subfield}>
<Input
{...reg}
innerRef={ref}
type={subfield === "until" ? "date" : "text"}
valid={
get(errors, `${fieldName}.${index}.${subfield}`) &&
false
}
validationText={get(
errors,
`${fieldName}.${index}.${subfield}.message`
)}
/>
</td>
);
})}
<td>
<Button
color="link"
icon
onClick={() => remove(index)}
size="xs"
>
<Icon icon="it-delete" size="sm" title="Remove feature" />
</Button>
</td>
</tr>
))}
</tbody>
</Table>
)}
<Button
color="primary"
onClick={() => append({ name: "", until: "", email: "", website: "" })}
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/EditorScreenshots.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function EditorScreenshots({ lang }: Props): JSX.Element {

const label = t(`publiccodeyml.description.screenshots.label`);
const description = t(`publiccodeyml.description.screenshots.description`);

const errorMessages = control.getFieldState(`description.${lang}.screenshots`).error as unknown as FieldError[]

const add = () => {
Expand All @@ -44,7 +44,7 @@ export default function EditorScreenshots({ lang }: Props): JSX.Element {
<label
className="active"
htmlFor={`description.${lang}.screenshots`}
>{`${label} *`}</label>
>{`${label}`}</label>
<ul className="list-group list-group-flush">
{screenshots.map((screenshot, index) => (
<li
Expand Down
2 changes: 1 addition & 1 deletion src/app/components/EditorUsedBy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export default function EditorUsedBy(): JSX.Element {
<label
className="active"
htmlFor={`usedby`}
>{`${label} *`}</label>
>{`${label}`}</label>
<ul className="list-group list-group-flush">
{usedBy.map((feat) => (
<li
Expand Down
10 changes: 9 additions & 1 deletion src/app/validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,16 @@ export const validator = async (
baseURL = ''
}: ValidatorParams): Promise<Result> => {
if (!IsPublicCodeYmlValid) throw new Error("Validator not ready");

let url = ''
try {
url = new URL(baseURL).href
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (_: unknown) {
console.warn('invalid URL')
}

const res = await IsPublicCodeYmlValid(publiccode, branch, baseURL);
const res = await IsPublicCodeYmlValid(publiccode, branch, url);

const {
publicCode,
Expand Down

0 comments on commit d9b642e

Please sign in to comment.