From f5f17bc9d5dd3b660a3f12db539c9db6d6396368 Mon Sep 17 00:00:00 2001 From: hegeaal Date: Tue, 10 Dec 2024 09:10:10 +0100 Subject: [PATCH 1/3] feat: move title/uri fieldsets to table dataset from --- .../dataset-form-access-rights-section.tsx | 150 ++----------- .../dataset-form-content-section.tsx | 53 ++--- ...dataset-form-information-model-section.tsx | 43 +--- .../dataset-form-relations-section.tsx | 203 +++++++----------- .../uri-with-label-field-set-table.tsx | 158 ++++++++++++++ .../utils/dataset-initial-values.tsx | 12 +- .../dataset-form/utils/validation-schema.tsx | 6 + libs/ui/src/lib/button/add.tsx | 6 +- libs/ui/src/lib/button/button.module.css | 12 +- libs/ui/src/lib/button/delete.tsx | 8 +- libs/ui/src/lib/button/edit.tsx | 19 ++ libs/ui/src/lib/button/index.tsx | 1 + .../utils/src/lib/language/dataset.form.nb.ts | 9 +- 13 files changed, 325 insertions(+), 355 deletions(-) create mode 100644 apps/dataset-catalog/components/dataset-form/components/uri-with-label-field-set-table.tsx create mode 100644 libs/ui/src/lib/button/edit.tsx diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-form-access-rights-section.tsx b/apps/dataset-catalog/components/dataset-form/components/dataset-form-access-rights-section.tsx index fa3770fcb..70a31736e 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-form-access-rights-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/dataset-form-access-rights-section.tsx @@ -1,17 +1,12 @@ import { AccessRights, Dataset } from '@catalog-frontend/types'; -import { AddButton, FormContainer, FormikLanguageFieldset, TitleWithTag } from '@catalog-frontend/ui'; +import { TitleWithTag } from '@catalog-frontend/ui'; import { localization } from '@catalog-frontend/utils'; -import { Button, Heading, NativeSelect, Textfield } from '@digdir/designsystemet-react'; -import { MinusCircleIcon, PlusCircleIcon } from '@navikt/aksel-icons'; -import { Field, FieldArray, FormikErrors, FormikHelpers } from 'formik'; -import FieldsetWithDelete from '../../fieldset-with-delete'; +import { Divider, NativeSelect } from '@digdir/designsystemet-react'; +import { Field, FormikHelpers, useFormikContext } from 'formik'; +import { UriWithLabelFieldsetTable } from './uri-with-label-field-set-table'; -type AccessRightsSectionProps = { - errors: FormikErrors; - values: Dataset; -}; - -export const AccessRightsSection = ({ errors, values }: AccessRightsSectionProps) => { +export const AccessRightsSection = () => { + const { values } = useFormikContext(); return ( <> @@ -37,128 +32,27 @@ export const AccessRightsSection = ({ errors, values }: AccessRightsSectionProps {(values.accessRights?.uri === AccessRights.RESTRICTED || values.accessRights?.uri === AccessRights.NON_PUBLIC) && ( <> - - - {({ remove, push }) => ( - <> - {values.legalBasisForRestriction?.map((_, index) => ( -
- - remove(index)}> - - -
- ))} - push({ prefLabel: { nb: '' }, uri: '' })} /> - - )} -
- +
+ +
- - {({ remove, push }) => ( - <> - {values.legalBasisForProcessing?.map((_, index) => ( -
- - - -
- ))} -
- -
- - )} -
- - +
+ +
- - {({ remove, push }) => ( - <> - {values.legalBasisForAccess?.map((_, index) => ( -
- - - -
- ))} -
- -
- - )} -
+ )} diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-form-content-section.tsx b/apps/dataset-catalog/components/dataset-form/components/dataset-form-content-section.tsx index d741beee8..9b6a8f60b 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-form-content-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/dataset-form-content-section.tsx @@ -1,49 +1,20 @@ 'use client'; import { Dataset } from '@catalog-frontend/types'; -import { AddButton, FormContainer, FormikLanguageFieldset, TextareaWithPrefix } from '@catalog-frontend/ui'; +import { FormikLanguageFieldset, TextareaWithPrefix } from '@catalog-frontend/ui'; import { localization } from '@catalog-frontend/utils'; -import { Heading, Textfield, Textarea, Button, Label, HelpText, Fieldset } from '@digdir/designsystemet-react'; -import { MinusCircleIcon, PlusCircleIcon } from '@navikt/aksel-icons'; -import { Field, FieldArray, useFormikContext } from 'formik'; -import FieldsetWithDelete from '../../fieldset-with-delete'; -import styles from '../dataset-form.module.css'; +import { useFormikContext } from 'formik'; +import { UriWithLabelFieldsetTable } from './uri-with-label-field-set-table'; export const ContentSection = () => { - const { errors, values } = useFormikContext(); - + const { values } = useFormikContext(); return ( -
- - {({ push, remove }) => ( - <> -
- {values.conformsTo && - values.conformsTo.map((_, index) => ( -
- remove(index)}> - - - -
- ))} - - push({ prefLabel: { nb: '' }, uri: '' })}> - {localization.button.addUrl} - -
- - )} -
+ <> +
+ +
{ legend={localization.datasetForm.heading.availability} requiredLanguages={['nb']} /> -
+ ); }; diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-form-information-model-section.tsx b/apps/dataset-catalog/components/dataset-form/components/dataset-form-information-model-section.tsx index 16772e9cf..040d544cc 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-form-information-model-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/dataset-form-information-model-section.tsx @@ -2,16 +2,16 @@ import { Dataset } from '@catalog-frontend/types'; import { AddButton } from '@catalog-frontend/ui'; import { capitalizeFirstLetter, getTranslateText, localization } from '@catalog-frontend/utils'; -import { Combobox, Textfield, Fieldset } from '@digdir/designsystemet-react'; +import { Combobox } from '@digdir/designsystemet-react'; import { useSearchInformationModelsByUri, useSearchInformationModelsSuggestions, } from '../../../hooks/useSearchService'; -import { Field, FieldArray, useFormikContext } from 'formik'; +import { useFormikContext } from 'formik'; import { debounce } from 'lodash'; import { useCallback, useState } from 'react'; import styles from '../dataset-form.module.css'; -import FieldsetWithDelete from '../../fieldset-with-delete'; +import { UriWithLabelFieldsetTable } from './uri-with-label-field-set-table'; interface Props { searchEnv: string; @@ -90,40 +90,9 @@ export const InformationModelSection = ({ searchEnv }: Props) => { )} - ( -
- {values.informationModel && - values.informationModel.map((_, index) => ( -
-
- remove(index)} - > - - - -
-
- ))} - - push('informationModel')}> - {localization.datasetForm.button.addInformationModel} - -
- )} + ); diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-form-relations-section.tsx b/apps/dataset-catalog/components/dataset-form/components/dataset-form-relations-section.tsx index 03b2ba1e1..fd5244e7a 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-form-relations-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/dataset-form-relations-section.tsx @@ -1,11 +1,12 @@ import { useState } from 'react'; import { Dataset, DatasetSeries } from '@catalog-frontend/types'; -import { AddButton, DeleteButton, FormContainer } from '@catalog-frontend/ui'; +import { AddButton, DeleteButton } from '@catalog-frontend/ui'; import { getTranslateText, localization } from '@catalog-frontend/utils'; -import { Heading, Combobox, Textfield } from '@digdir/designsystemet-react'; +import { Heading, Combobox, Label, Divider } from '@digdir/designsystemet-react'; import { Field, FieldArray, useFormikContext } from 'formik'; import relations from '../utils/relations.json'; import { useSearchDatasetsByUri, useSearchDatasetSuggestions } from '../../../hooks/useSearchService'; +import { UriWithLabelFieldsetTable } from './uri-with-label-field-set-table'; type TitleSectionProps = { searchEnv: string; @@ -42,140 +43,94 @@ export const RelationsSection = ({ searchEnv, datasetSeries }: TitleSectionProps ]; return ( -
- - {localization.datasetForm.heading.relations} - - - + <> + + {({ remove, push }) => ( +
+ {values.references?.map((_, index) => ( +
+ setFieldValue(`references[${index}].referenceType.code`, value.toString())} + value={ + values.references?.[index]?.referenceType?.code + ? [values.references?.[index]?.referenceType?.code] + : [] + } + placeholder={`${localization.datasetForm.fieldLabel.choseRelation}...`} + > + {localization.search.noHits} + {relations.map((relation) => ( + + {getTranslateText(relation?.label)} + + ))} + - - {({ remove, push }) => ( -
- {values.references?.map((_, index) => ( -
+ {!isLoading && ( - setFieldValue(`references[${index}].referenceType.code`, value.toString()) - } - value={ - values.references?.[index]?.referenceType?.code - ? [values.references?.[index]?.referenceType?.code] - : [] - } - placeholder={`${localization.datasetForm.fieldLabel.choseRelation}...`} + label={localization.datasetForm.fieldLabel.dataset} + onChange={(input: any) => setSearchQuery(input.target.value)} + onValueChange={(value) => { + setFieldValue(`references.${[index]}.source.uri`, value.toString()); + }} + loading={searching} + value={values.references?.[index]?.source?.uri ? [values.references?.[index]?.source?.uri] : []} + placeholder={`${localization.search.search}...`} > {localization.search.noHits} - {relations.map((relation) => ( + {comboboxOptions?.map((dataset) => ( - {getTranslateText(relation?.label)} + {dataset?.title ? getTranslateText(dataset?.title) : dataset.uri} ))} - - {!isLoading && ( - setSearchQuery(input.target.value)} - onValueChange={(value) => { - setFieldValue(`references.${[index]}.source.uri`, value.toString()); - }} - loading={searching} - value={values.references?.[index]?.source?.uri ? [values.references?.[index]?.source?.uri] : []} - placeholder={`${localization.search.search}...`} - > - {localization.search.noHits} - {comboboxOptions?.map((dataset) => ( - - {dataset?.title ? getTranslateText(dataset?.title) : dataset.uri} - - ))} - - )} - remove(index)}> -
- ))} - - push({ type: { code: '' }, source: { uri: '' } })}> -
- )} -
- - {datasetSeries && ( - setFieldValue('inSeries', value.toString())} - value={values.inSeries ? [values.inSeries] : []} - initialValue={values?.inSeries ? [values?.inSeries] : []} - placeholder={`${localization.search.search}...`} - > - {localization.search.noHits} - {datasetSeries.map((dataset) => ( - - {getTranslateText(dataset.title)} - + )} + remove(index)}> +
))} - + + push({ type: { code: '' }, source: { uri: '' } })}> +
)} +
- setFieldValue('inSeries', value.toString())} + value={values.inSeries ? [values.inSeries] : []} + initialValue={values?.inSeries ? [values?.inSeries] : []} + placeholder={`${localization.search.search}...`} + > + {localization.search.noHits} + {datasetSeries.map((dataset) => ( + + {getTranslateText(dataset.title)} + + ))} + + )} +
+ +
+
+ + - - {({ push, remove }) => ( -
- {values.relations?.map((_, index) => ( -
- - - - remove(index)}> -
- ))} - - - push({ - prefLabel: { nb: '' }, - uri: '', - }) - } - > -
- )} -
- -
+
+ ); }; diff --git a/apps/dataset-catalog/components/dataset-form/components/uri-with-label-field-set-table.tsx b/apps/dataset-catalog/components/dataset-form/components/uri-with-label-field-set-table.tsx new file mode 100644 index 000000000..4f65aa9ca --- /dev/null +++ b/apps/dataset-catalog/components/dataset-form/components/uri-with-label-field-set-table.tsx @@ -0,0 +1,158 @@ +import { UriWithLabel } from '@catalog-frontend/types'; +import { AddButton, DeleteButton, EditButton, FormikLanguageFieldset } from '@catalog-frontend/ui'; +import { getTranslateText, localization, trimObjectWhitespace } from '@catalog-frontend/utils'; +import { Button, Divider, Label, Modal, Table, Textfield } from '@digdir/designsystemet-react'; +import { Field, Formik, useFormikContext } from 'formik'; +import styles from '../dataset-form.module.css'; +import { useRef, useState } from 'react'; +import _ from 'lodash'; +import { uriWithLabelSchema } from '../utils/validation-schema'; + +interface Props { + values: UriWithLabel[] | undefined; + fieldName: string; +} + +interface ModalProps { + fieldName: string; + type: 'new' | 'edit'; + onSuccess: (values: UriWithLabel) => void; + template: UriWithLabel; +} + +const hasNoFieldValues = (values: UriWithLabel) => { + if (!values) return true; + return _.isEmpty(_.trim(values.uri)) && _.isEmpty(_.pickBy(values.prefLabel, _.identity)); +}; + +export const UriWithLabelFieldsetTable = ({ fieldName, values }: Props) => { + const { setFieldValue } = useFormikContext(); + + return ( + <> + + {values && values?.length > 0 && !hasNoFieldValues(values[0]) && ( + + + + {localization.title} + {localization.link} + + + + + {values?.map((item, index) => ( + + {getTranslateText(item?.prefLabel)} + {item?.uri} + + + setFieldValue(`${fieldName}[${index}]`, updatedItem)} + /> + setFieldValue(`${fieldName}[${index}]`, undefined)} /> + + + + ))} + +
+ )} +
+ + setFieldValue( + values && values?.length > 0 && !hasNoFieldValues(values[0]) + ? `${fieldName}[${values?.length}]` + : `${fieldName}[0]`, + formValues, + ) + } + /> +
+ + ); +}; + +const FieldModal = ({ fieldName, template, type, onSuccess }: ModalProps) => { + const [submitted, setSubmitted] = useState(false); + const modalRef = useRef(null); + + return ( + <> + + {type === 'edit' ? : } + + { + const trimmedValues = trimObjectWhitespace(formValues); + onSuccess(trimmedValues); + setSubmitting(false); + setSubmitted(true); + modalRef.current?.close(); + }} + > + {({ errors, isSubmitting, submitForm, values, dirty }) => ( + <> + + {type === 'edit' + ? `${localization.edit} ${getTranslateText(localization.datasetForm.fieldLabel[fieldName])?.toString().toLowerCase()}` + : `${localization.add} ${getTranslateText(localization.datasetForm.fieldLabel[fieldName])?.toString().toLowerCase()}`} + + + + +
+ +
+ + +
+ + + + + + + )} +
+
+
+ + ); +}; diff --git a/apps/dataset-catalog/components/dataset-form/utils/dataset-initial-values.tsx b/apps/dataset-catalog/components/dataset-form/utils/dataset-initial-values.tsx index b30289016..ec9d054f5 100644 --- a/apps/dataset-catalog/components/dataset-form/utils/dataset-initial-values.tsx +++ b/apps/dataset-catalog/components/dataset-form/utils/dataset-initial-values.tsx @@ -13,9 +13,9 @@ export const datasetTemplate = (dataset: Dataset): Dataset => { nb: (dataset && dataset.description?.nb) ?? '', }, accessRights: { uri: dataset?.accessRights?.uri ?? AccessRights.PUBLIC }, - legalBasisForAccess: dataset?.legalBasisForAccess ?? [{ uri: '', prefLabel: { nb: '' } }], - legalBasisForProcessing: dataset?.legalBasisForProcessing ?? [{ uri: '', prefLabel: { nb: '' } }], - legalBasisForRestriction: dataset?.legalBasisForRestriction ?? [{ uri: '', prefLabel: { nb: '' } }], + legalBasisForAccess: dataset?.legalBasisForAccess ?? [], + legalBasisForProcessing: dataset?.legalBasisForProcessing ?? [], + legalBasisForRestriction: dataset?.legalBasisForRestriction ?? [], registrationStatus: dataset.registrationStatus, landingPage: dataset.landingPage && dataset?.landingPage?.length > 0 && dataset.landingPage.every((page) => page !== null) @@ -81,9 +81,9 @@ export const datasetToBeCreatedTemplate = (): DatasetToBeCreated => { registrationStatus: PublicationStatus.DRAFT, landingPage: [], accessRights: { uri: '' }, - legalBasisForAccess: [{ uri: '', prefLabel: { nb: '' } }], - legalBasisForProcessing: [{ uri: '', prefLabel: { nb: '' } }], - legalBasisForRestriction: [{ uri: '', prefLabel: { nb: '' } }], + legalBasisForAccess: [], + legalBasisForProcessing: [], + legalBasisForRestriction: [], losThemeList: [], euThemeList: [], type: '', diff --git a/apps/dataset-catalog/components/dataset-form/utils/validation-schema.tsx b/apps/dataset-catalog/components/dataset-form/utils/validation-schema.tsx index a7ed003ba..85f4e4a3a 100644 --- a/apps/dataset-catalog/components/dataset-form/utils/validation-schema.tsx +++ b/apps/dataset-catalog/components/dataset-form/utils/validation-schema.tsx @@ -102,3 +102,9 @@ export const distributionSectionSchema = Yup.object().shape({ }), ), }); + +export const uriWithLabelSchema = Yup.object().shape({ + uri: Yup.string() + .matches(httpsRegex, localization.validation.invalidProtocol) + .url(localization.validation.invalidUrl), +}); diff --git a/libs/ui/src/lib/button/add.tsx b/libs/ui/src/lib/button/add.tsx index 994682c17..6c8ab4787 100644 --- a/libs/ui/src/lib/button/add.tsx +++ b/libs/ui/src/lib/button/add.tsx @@ -6,12 +6,12 @@ import styles from './button.module.css'; const AddButton = ({ children = localization.add, ...props }: ButtonProps) => ( diff --git a/libs/ui/src/lib/button/button.module.css b/libs/ui/src/lib/button/button.module.css index e9d868054..ea7c6fae2 100644 --- a/libs/ui/src/lib/button/button.module.css +++ b/libs/ui/src/lib/button/button.module.css @@ -3,13 +3,9 @@ --component-button-outline-primary-color-text-default: #2d3741; --component-button-outline-primary-color-border-default: #2d3741; } -/* -.addContainer { - display: flex; - width: fit-content; - justify-content: flex-start; -} */ -.add { - width: fit-content; +.withIcon { + display: flex; + gap: 0.5rem; + align-items: center; } diff --git a/libs/ui/src/lib/button/delete.tsx b/libs/ui/src/lib/button/delete.tsx index fa0093e13..fcc96bf6d 100644 --- a/libs/ui/src/lib/button/delete.tsx +++ b/libs/ui/src/lib/button/delete.tsx @@ -1,17 +1,17 @@ import { Button, ButtonProps } from '@digdir/designsystemet-react'; import { localization } from '@catalog-frontend/utils'; import { TrashIcon } from '@navikt/aksel-icons'; +import styles from './button.module.css'; const DeleteButton = ({ children = localization.button.delete, ...props }: ButtonProps) => ( diff --git a/libs/ui/src/lib/button/edit.tsx b/libs/ui/src/lib/button/edit.tsx new file mode 100644 index 000000000..694b6bebe --- /dev/null +++ b/libs/ui/src/lib/button/edit.tsx @@ -0,0 +1,19 @@ +import { Button, ButtonProps } from '@digdir/designsystemet-react'; +import { localization } from '@catalog-frontend/utils'; +import { PencilWritingIcon } from '@navikt/aksel-icons'; +import styles from './button.module.css'; + +const EditButton = ({ children = localization.button.edit, ...props }: ButtonProps) => ( + +); + +export { EditButton }; diff --git a/libs/ui/src/lib/button/index.tsx b/libs/ui/src/lib/button/index.tsx index e317c75f6..c99816927 100644 --- a/libs/ui/src/lib/button/index.tsx +++ b/libs/ui/src/lib/button/index.tsx @@ -3,3 +3,4 @@ export * from './upload'; export * from './link'; export * from './delete'; export * from './add'; +export * from './edit'; diff --git a/libs/utils/src/lib/language/dataset.form.nb.ts b/libs/utils/src/lib/language/dataset.form.nb.ts index 67888da88..f58c0d18d 100644 --- a/libs/utils/src/lib/language/dataset.form.nb.ts +++ b/libs/utils/src/lib/language/dataset.form.nb.ts @@ -46,9 +46,6 @@ export const datasetFormNb = { landingPage: 'Lenke til mer informasjon om datasettet', titleAndDescription: 'Tittel og beskrivelse', accessRights: 'Tilgangsnivå', - legalBasisForRestriction: 'Skjermingshjemmel', - legalBasisForProcessing: 'Behandlingsgrunnlag', - legalBasisForAccess: 'Utleveringshjemmel', losTheme: 'LOS-tema og emner', euTheme: 'EU-tema', concept: 'Begrep og emneord', @@ -57,7 +54,6 @@ export const datasetFormNb = { frequency: 'Oppdateringsfrekvens', lastUpdated: 'Sist oppdatert', actuality: 'Aktualitet', - standard: 'Standard', content: 'Innhold', relevance: 'Relevans', completeness: 'Kompletthet', @@ -102,12 +98,16 @@ export const datasetFormNb = { relationType: 'Relasjonstype', datasetSeries: 'Datasettserie', choseRelation: 'Velg relasjon', + conformsTo: 'Standard', standard: 'Standard', distributionLink: 'Lenke til dokumentasjon av distribusjonen', license: 'Lisens', accessService: 'Tilgangstjeneste', downloadUrl: 'Nedlastingslenke', accessUrl: 'Tilgangslenke', + legalBasisForRestriction: 'Skjermingshjemmel', + legalBasisForProcessing: 'Behandlingsgrunnlag', + legalBasisForAccess: 'Utleveringshjemmel', }, alert: { confirmDelete: 'Er du sikker på at du vil slette datasettbeskrivelsen?', @@ -129,6 +129,7 @@ export const datasetFormNb = { addStandard: 'Legg til standard', addDistribution: 'Legg til distribusjon', updateDistribution: 'Oppdater distribusjon', + update: 'Oppdater', }, errors: { qualifiedAttributions: 'Kunne ikke hente enheter.', From d14744eb1ac94f1ef97fa461cc9a281423dda112 Mon Sep 17 00:00:00 2001 From: hegeaal Date: Tue, 10 Dec 2024 15:38:03 +0100 Subject: [PATCH 2/3] feat: refactor accessRights dataset form --- ...om-title-section.tsx => about-section.tsx} | 22 +- .../access-rights-uri-table.tsx | 219 ++++++++++++++++++ .../dataset-form-access-rights-section.tsx | 32 +-- .../dataset-form-contact-point-section.tsx | 8 +- .../dataset-form-geography-section.tsx | 8 - .../dataset-form/dataset-form.module.css | 4 + .../components/dataset-form/index.tsx | 17 +- .../utils/src/lib/language/dataset.form.nb.ts | 1 + 8 files changed, 250 insertions(+), 61 deletions(-) rename apps/dataset-catalog/components/dataset-form/components/{dataset-from-title-section.tsx => about-section.tsx} (76%) create mode 100644 apps/dataset-catalog/components/dataset-form/components/access-rights.tsx/access-rights-uri-table.tsx rename apps/dataset-catalog/components/dataset-form/components/{ => access-rights.tsx}/dataset-form-access-rights-section.tsx (60%) diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-from-title-section.tsx b/apps/dataset-catalog/components/dataset-form/components/about-section.tsx similarity index 76% rename from apps/dataset-catalog/components/dataset-form/components/dataset-from-title-section.tsx rename to apps/dataset-catalog/components/dataset-form/components/about-section.tsx index 5e0ee337f..760a511bb 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-from-title-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/about-section.tsx @@ -1,12 +1,12 @@ import { Dataset } from '@catalog-frontend/types'; -import { AddButton, FormikLanguageFieldset, TextareaWithPrefix, TitleWithTag } from '@catalog-frontend/ui'; +import { FormikLanguageFieldset, TextareaWithPrefix, TitleWithTag } from '@catalog-frontend/ui'; import { localization } from '@catalog-frontend/utils'; import { Textfield, Fieldset } from '@digdir/designsystemet-react'; -import { Field, FieldArray, useFormikContext } from 'formik'; -import FieldsetWithDelete from '../../fieldset-with-delete'; +import { Field, useFormikContext } from 'formik'; import { FieldsetDivider } from '@catalog-frontend/ui'; +import { AccessRightsForm } from './access-rights.tsx/dataset-form-access-rights-section'; -export const TitleSection = () => { +export const AboutSection = () => { const errors = useFormikContext()?.errors; return ( <> @@ -40,8 +40,18 @@ export const TitleSection = () => { + - + + + + + {/* {(arrayHelpers) => ( <> {arrayHelpers.form.values.landingPage && @@ -61,7 +71,7 @@ export const TitleSection = () => { arrayHelpers.push('')}>{localization.button.addUrl} )} - + */} ); }; diff --git a/apps/dataset-catalog/components/dataset-form/components/access-rights.tsx/access-rights-uri-table.tsx b/apps/dataset-catalog/components/dataset-form/components/access-rights.tsx/access-rights-uri-table.tsx new file mode 100644 index 000000000..d53863ebc --- /dev/null +++ b/apps/dataset-catalog/components/dataset-form/components/access-rights.tsx/access-rights-uri-table.tsx @@ -0,0 +1,219 @@ +import { Dataset, UriWithLabel } from '@catalog-frontend/types'; +import { AddButton, DeleteButton, EditButton, FormikLanguageFieldset } from '@catalog-frontend/ui'; +import { getTranslateText, localization, trimObjectWhitespace } from '@catalog-frontend/utils'; +import { Button, Divider, Label, Modal, Radio, Table, Textfield } from '@digdir/designsystemet-react'; +import { FastField, Formik, useFormikContext } from 'formik'; +import styles from '../../dataset-form.module.css'; +import { useRef, useState } from 'react'; +import _ from 'lodash'; +import { uriWithLabelSchema } from '../../utils/validation-schema'; + +const hasNoFieldValues = (values: UriWithLabel) => { + if (!values) return true; + return _.isEmpty(_.trim(values.uri)) && _.isEmpty(_.pickBy(values.prefLabel, _.identity)); +}; + +const accessRightTypes = ['legalBasisForRestriction', 'legalBasisForProcessing', 'legalBasisForAccess']; + +export const AccessRightsUriTable = () => { + const { setFieldValue, values } = useFormikContext(); + + const allLegalBases = [ + ...(values.legalBasisForRestriction ?? []).map((item, index) => ({ + uriWithLabel: item, + type: 'legalBasisForRestriction', + index: index, + })), + ...(values.legalBasisForProcessing ?? []).map((item, index) => ({ + uriWithLabel: item, + type: 'legalBasisForProcessing', + index: index, + })), + ...(values.legalBasisForAccess ?? []).map((item, index) => ({ + uriWithLabel: item, + type: 'legalBasisForAccess', + index: index, + })), + ]; + + const getFieldName = (formValues: LegalBasis): string => { + const fieldMap: Record = { + legalBasisForRestriction: values.legalBasisForRestriction ?? [], + legalBasisForProcessing: values.legalBasisForProcessing ?? [], + legalBasisForAccess: values.legalBasisForAccess ?? [], + }; + + const fieldArray = fieldMap[formValues.type]; + if (!fieldArray) { + throw new Error(`Invalid type: ${formValues.type}`); + } + + return fieldArray.length > 0 && !hasNoFieldValues(fieldArray[0]) + ? `${formValues.type}[${fieldArray.length}]` + : `${formValues.type}[0]`; + }; + + return ( +
+ + + {allLegalBases && allLegalBases?.length > 0 && !hasNoFieldValues(allLegalBases[0].uriWithLabel) && ( + + + + {localization.title} + {localization.link} + {localization.type} + + + + + {allLegalBases.map( + (item, i) => + item?.uriWithLabel && ( + + {getTranslateText(item?.uriWithLabel.prefLabel)} + {item?.uriWithLabel.uri} + {localization.datasetForm.fieldLabel[item?.type]} + + + + setFieldValue(`${updatedItem.type}[${item.index}]`, updatedItem.uriWithLabel) + } + initialType={item.type} + /> + setFieldValue(`${item.type}[${item.index}]`, undefined)} /> + + + + ), + )} + +
+ )} +
+ setFieldValue(getFieldName(formValues), formValues.uriWithLabel)} + /> +
+
+ ); +}; + +type LegalBasis = { + type: string; + uriWithLabel: UriWithLabel; +}; + +interface ModalProps { + formType: 'new' | 'edit'; + onSuccess: (values: LegalBasis) => void; + template: UriWithLabel; + initialType?: string; +} + +const FieldModal = ({ template, formType, onSuccess, initialType = 'legalBasisForRestriction' }: ModalProps) => { + const [submitted, setSubmitted] = useState(false); + const modalRef = useRef(null); + const [legalBasis, setLegalBasis] = useState(initialType); + + return ( + <> + + {formType === 'edit' ? : } + + { + const trimmedValues = trimObjectWhitespace(formValues); + console.log('ny', { type: legalBasis, uriWithLabel: trimmedValues }); + onSuccess({ type: legalBasis, uriWithLabel: trimmedValues }); + setSubmitting(false); + setSubmitted(true); + modalRef.current?.close(); + }} + > + {({ errors, isSubmitting, submitForm, values, dirty }) => ( + <> + + {formType === 'edit' + ? `${localization.edit} ${localization.datasetForm.fieldLabel.legalBasis.toLowerCase()}` + : `${localization.add} ${localization.datasetForm.fieldLabel.legalBasis.toLowerCase()}`} + + + + { + const newType = val.toString(); + setLegalBasis(newType); + }} + defaultValue={legalBasis} + > + {accessRightTypes.map((type) => ( + + {localization.datasetForm.fieldLabel[type]} + + ))} + + + +
+ +
+ + +
+ + + + + + + )} +
+
+
+ + ); +}; diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-form-access-rights-section.tsx b/apps/dataset-catalog/components/dataset-form/components/access-rights.tsx/dataset-form-access-rights-section.tsx similarity index 60% rename from apps/dataset-catalog/components/dataset-form/components/dataset-form-access-rights-section.tsx rename to apps/dataset-catalog/components/dataset-form/components/access-rights.tsx/dataset-form-access-rights-section.tsx index 70a31736e..9a454e0de 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-form-access-rights-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/access-rights.tsx/dataset-form-access-rights-section.tsx @@ -1,11 +1,11 @@ import { AccessRights, Dataset } from '@catalog-frontend/types'; import { TitleWithTag } from '@catalog-frontend/ui'; import { localization } from '@catalog-frontend/utils'; -import { Divider, NativeSelect } from '@digdir/designsystemet-react'; +import { NativeSelect } from '@digdir/designsystemet-react'; import { Field, FormikHelpers, useFormikContext } from 'formik'; -import { UriWithLabelFieldsetTable } from './uri-with-label-field-set-table'; +import { AccessRightsUriTable } from './access-rights-uri-table'; -export const AccessRightsSection = () => { +export const AccessRightsForm = () => { const { values } = useFormikContext(); return ( <> @@ -30,31 +30,7 @@ export const AccessRightsSection = () => {
{(values.accessRights?.uri === AccessRights.RESTRICTED || - values.accessRights?.uri === AccessRights.NON_PUBLIC) && ( - <> - - -
- -
- - -
- -
- - - - )} + values.accessRights?.uri === AccessRights.NON_PUBLIC) && } ); }; diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-form-contact-point-section.tsx b/apps/dataset-catalog/components/dataset-form/components/dataset-form-contact-point-section.tsx index 7fe839067..6f4bf8945 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-form-contact-point-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/dataset-form-contact-point-section.tsx @@ -10,10 +10,10 @@ import { useState } from 'react'; export const ContactPointSection = () => { const { setFieldValue, values, errors } = useFormikContext(); const [selectedFields, setSelectedFields] = useState([ - ...(values.contactPoint?.[0].email ? ['email'] : []), - ...(values.contactPoint?.[0].hasTelephone ? ['hasTelephone'] : []), - ...(values.contactPoint?.[0].organizationUnit ? ['organizationUnit'] : []), - ...(values.contactPoint?.[0].hasURL ? ['hasURL'] : []), + ...(values.contactPoint?.[0]?.email ? ['email'] : []), + ...(values.contactPoint?.[0]?.hasTelephone ? ['hasTelephone'] : []), + ...(values.contactPoint?.[0]?.organizationUnit ? ['organizationUnit'] : []), + ...(values.contactPoint?.[0]?.hasURL ? ['hasURL'] : []), ]); const contactPointOptions = [ diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-form-geography-section.tsx b/apps/dataset-catalog/components/dataset-form/components/dataset-form-geography-section.tsx index 0926f7769..c145ad534 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-form-geography-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/dataset-form-geography-section.tsx @@ -102,14 +102,6 @@ export const GeographySection = ({ envVariable, languages }: Props) => { )} /> - - setFieldValue('languageList', values)} diff --git a/apps/dataset-catalog/components/dataset-form/dataset-form.module.css b/apps/dataset-catalog/components/dataset-form/dataset-form.module.css index d883c2740..e052e66ea 100644 --- a/apps/dataset-catalog/components/dataset-form/dataset-form.module.css +++ b/apps/dataset-catalog/components/dataset-form/dataset-form.module.css @@ -53,3 +53,7 @@ background-color: #ccc; margin: 0 0.5rem; } + +.buttonSet { + display: flex; +} diff --git a/apps/dataset-catalog/components/dataset-form/index.tsx b/apps/dataset-catalog/components/dataset-form/index.tsx index c4396eabd..d78639529 100644 --- a/apps/dataset-catalog/components/dataset-form/index.tsx +++ b/apps/dataset-catalog/components/dataset-form/index.tsx @@ -15,8 +15,7 @@ import { createDataset, updateDataset } from './../../app/actions/actions'; import { datasetTemplate } from './utils/dataset-initial-values'; import { useState } from 'react'; import { datasetValidationSchema } from './utils/validation-schema'; -import { TitleSection } from './components/dataset-from-title-section'; -import { AccessRightsSection } from './components/dataset-form-access-rights-section'; +import { AboutSection } from './components/about-section'; import ThemeSection from './components/dataset-form-theme-section'; import { TypeSection } from './components/dataset-form-type-section'; import { ConceptSection } from './components/dataset-form-concept-section'; @@ -142,19 +141,7 @@ export const DatasetForm = ({ id='title-section' title={localization.datasetForm.heading.titleAndDescription} required - > - - - - - - + > Date: Thu, 12 Dec 2024 16:08:52 +0100 Subject: [PATCH 3/3] feat: hide fields behind buttons dataset field --- .../dataset-form/components/about-section.tsx | 28 +-- .../dataset-form-provenance-section.tsx | 51 +---- ...et-form-qualified-attributions-section.tsx | 1 + .../details-section/details-section.tsx | 33 +++ .../details-section/details.module.css | 3 + .../details-section/hidden-detail-fields.tsx | 214 ++++++++++++++++++ .../recommended-detail-fields.tsx} | 103 +++++---- .../dataset-form-distribution-section.tsx | 0 .../distribution-details.tsx | 0 .../distribution-modal.tsx | 0 .../distributions.module.css | 0 .../components/toggle-field-button.tsx | 51 +++++ .../uri-with-label-field-set-table.tsx | 13 +- .../components/dataset-form/index.tsx | 153 +++++-------- .../utils/dataset-initial-values.tsx | 2 +- .../dataset-form/utils/validation-schema.tsx | 16 +- .../src/lib/formik-search-combobox/index.tsx | 1 + libs/ui/src/lib/title-with-tag/index.tsx | 4 +- .../utils/src/lib/language/dataset.form.nb.ts | 2 + 19 files changed, 452 insertions(+), 223 deletions(-) create mode 100644 apps/dataset-catalog/components/dataset-form/components/details-section/details-section.tsx create mode 100644 apps/dataset-catalog/components/dataset-form/components/details-section/details.module.css create mode 100644 apps/dataset-catalog/components/dataset-form/components/details-section/hidden-detail-fields.tsx rename apps/dataset-catalog/components/dataset-form/components/{dataset-form-geography-section.tsx => details-section/recommended-detail-fields.tsx} (74%) rename apps/dataset-catalog/components/dataset-form/components/{dataset-from-distribution => distribution-section}/dataset-form-distribution-section.tsx (100%) rename apps/dataset-catalog/components/dataset-form/components/{dataset-from-distribution => distribution-section}/distribution-details.tsx (100%) rename apps/dataset-catalog/components/dataset-form/components/{dataset-from-distribution => distribution-section}/distribution-modal.tsx (100%) rename apps/dataset-catalog/components/dataset-form/components/{dataset-from-distribution => distribution-section}/distributions.module.css (100%) create mode 100644 apps/dataset-catalog/components/dataset-form/components/toggle-field-button.tsx diff --git a/apps/dataset-catalog/components/dataset-form/components/about-section.tsx b/apps/dataset-catalog/components/dataset-form/components/about-section.tsx index 760a511bb..964d46be3 100644 --- a/apps/dataset-catalog/components/dataset-form/components/about-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/about-section.tsx @@ -1,10 +1,11 @@ import { Dataset } from '@catalog-frontend/types'; -import { FormikLanguageFieldset, TextareaWithPrefix, TitleWithTag } from '@catalog-frontend/ui'; +import { AddButton, FormikLanguageFieldset, TextareaWithPrefix, TitleWithTag } from '@catalog-frontend/ui'; import { localization } from '@catalog-frontend/utils'; import { Textfield, Fieldset } from '@digdir/designsystemet-react'; -import { Field, useFormikContext } from 'formik'; +import { Field, FieldArray, useFormikContext } from 'formik'; import { FieldsetDivider } from '@catalog-frontend/ui'; import { AccessRightsForm } from './access-rights.tsx/dataset-form-access-rights-section'; +import FieldsetWithDelete from '../../fieldset-with-delete'; export const AboutSection = () => { const errors = useFormikContext()?.errors; @@ -46,32 +47,11 @@ export const AboutSection = () => { - - {/* - {(arrayHelpers) => ( - <> - {arrayHelpers.form.values.landingPage && - arrayHelpers.form.values.landingPage.map((_: string, index: number) => ( -
- arrayHelpers.remove(index)}> - - -
- ))} - - arrayHelpers.push('')}>{localization.button.addUrl} - - )} -
*/} ); }; diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-form-provenance-section.tsx b/apps/dataset-catalog/components/dataset-form/components/dataset-form-provenance-section.tsx index 0c37593ac..09e84902e 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-form-provenance-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/dataset-form-provenance-section.tsx @@ -13,54 +13,5 @@ export const ProvenanceSection = ({ data }: Props) => { const { setFieldValue, values } = useFormikContext(); const { provenanceStatements, frequencies } = data; - return ( - <> - setFieldValue('provenance.uri', value.toString())} - label={localization.datasetForm.heading.provenance} - > - {`${localization.choose}...`} - {provenanceStatements.map((item) => ( - - {getTranslateText(item.label)} - - ))} - - - setFieldValue('accrualPeriodicity.uri', value.toString())} - label={localization.datasetForm.heading.frequency} - > - {`${localization.choose}...`} - {frequencies.map((item) => ( - - {capitalizeFirstLetter(getTranslateText(item.label).toString())} - - ))} - - - - - - ); + return <>; }; diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-form-qualified-attributions-section.tsx b/apps/dataset-catalog/components/dataset-form/components/dataset-form-qualified-attributions-section.tsx index 6cb82a52c..c0a43d686 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-form-qualified-attributions-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/dataset-form-qualified-attributions-section.tsx @@ -48,6 +48,7 @@ export const QualifiedAttributionsSection = () => { <> {!isLoading && ( setFieldValue('qualifiedAttributions', selectedValues)} onChange={(input: any) => debouncedSearch(input.target.value)} loading={searching} diff --git a/apps/dataset-catalog/components/dataset-form/components/details-section/details-section.tsx b/apps/dataset-catalog/components/dataset-form/components/details-section/details-section.tsx new file mode 100644 index 000000000..2fbd54a90 --- /dev/null +++ b/apps/dataset-catalog/components/dataset-form/components/details-section/details-section.tsx @@ -0,0 +1,33 @@ +'use client'; + +import { FieldsetDivider } from '@catalog-frontend/ui'; +import { useFormikContext } from 'formik'; +import { Dataset, ReferenceData } from '@catalog-frontend/types'; +import { RecommendedDetailFields } from './recommended-detail-fields'; +import { HiddenDetailFields } from './hidden-detail-fields'; + +type Props = { + referenceDataEnv: string; + referenceData: ReferenceData; +}; + +export const DetailsSection = ({ referenceDataEnv, referenceData }: Props) => { + const { errors } = useFormikContext(); + const { datasetTypes, provenanceStatements, languages, frequencies } = referenceData; + return ( + <> + + +
+ +
+ + ); +}; diff --git a/apps/dataset-catalog/components/dataset-form/components/details-section/details.module.css b/apps/dataset-catalog/components/dataset-form/components/details-section/details.module.css new file mode 100644 index 000000000..b11177c65 --- /dev/null +++ b/apps/dataset-catalog/components/dataset-form/components/details-section/details.module.css @@ -0,0 +1,3 @@ +.padding { + padding-bottom: 0.5rem; +} diff --git a/apps/dataset-catalog/components/dataset-form/components/details-section/hidden-detail-fields.tsx b/apps/dataset-catalog/components/dataset-form/components/details-section/hidden-detail-fields.tsx new file mode 100644 index 000000000..42fee71fc --- /dev/null +++ b/apps/dataset-catalog/components/dataset-form/components/details-section/hidden-detail-fields.tsx @@ -0,0 +1,214 @@ +'use client'; + +import { AddButton, FormikLanguageFieldset, TextareaWithPrefix } from '@catalog-frontend/ui'; +import { capitalizeFirstLetter, getTranslateText, localization } from '@catalog-frontend/utils'; +import { Combobox, Textfield } from '@digdir/designsystemet-react'; +import { Field, FieldArray, useFormikContext } from 'formik'; +import { Dataset, ReferenceDataCode } from '@catalog-frontend/types'; +import styles from './details.module.css'; +import { QualifiedAttributionsSection } from '../dataset-form-qualified-attributions-section'; +import FieldsetWithDelete from '../../../fieldset-with-delete'; +import { ToggleFieldButton } from '../toggle-field-button'; +import { UriWithLabelFieldsetTable } from '../uri-with-label-field-set-table'; + +type Props = { + datasetTypes: ReferenceDataCode[]; + provenanceStatements: ReferenceDataCode[]; + frequencies: ReferenceDataCode[]; +}; + +export const HiddenDetailFields = ({ datasetTypes, provenanceStatements, frequencies }: Props) => { + const { setFieldValue, errors, values } = useFormikContext(); + return ( + <> +
+ + {(arrayHelpers) => ( + <> + {arrayHelpers.form.values.landingPage && + arrayHelpers.form.values.landingPage.map((_: string, index: number) => ( +
+ arrayHelpers.remove(index)}> + + +
+ ))} + + arrayHelpers.push('')}> + {`${localization.datasetForm.heading.landingPage}`} + + + )} +
+
+ + + setFieldValue('type', value.toString())} + > + {`${localization.choose}...`} + {datasetTypes.map((type) => ( + + {getTranslateText(type?.label)} + + ))} + + + + + setFieldValue('provenance.uri', value.toString())} + label={localization.datasetForm.heading.provenance} + size='sm' + > + {`${localization.choose}...`} + {provenanceStatements.map((item) => ( + + {getTranslateText(item.label)} + + ))} + + + + setFieldValue('accrualPeriodicity.uri', value.toString())} + label={localization.datasetForm.heading.frequency} + > + {`${localization.choose}...`} + {frequencies.map((item) => ( + + {capitalizeFirstLetter(getTranslateText(item.label).toString())} + + ))} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-form-geography-section.tsx b/apps/dataset-catalog/components/dataset-form/components/details-section/recommended-detail-fields.tsx similarity index 74% rename from apps/dataset-catalog/components/dataset-form/components/dataset-form-geography-section.tsx rename to apps/dataset-catalog/components/dataset-form/components/details-section/recommended-detail-fields.tsx index c145ad534..3e1be0d26 100644 --- a/apps/dataset-catalog/components/dataset-form/components/dataset-form-geography-section.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/details-section/recommended-detail-fields.tsx @@ -3,24 +3,27 @@ import { AddButton, FormikSearchCombobox, TitleWithTag } from '@catalog-frontend import { getTranslateText, localization } from '@catalog-frontend/utils'; import { Checkbox, Label, Textfield } from '@digdir/designsystemet-react'; import { useCallback, useState } from 'react'; -import { useSearchAdministrativeUnits, useSearchAdministrativeUnitsByUri } from '../../../hooks/useReferenceDataSearch'; +import { + useSearchAdministrativeUnits, + useSearchAdministrativeUnitsByUri, +} from '../../../../hooks/useReferenceDataSearch'; import { Field, FieldArray, useFormikContext } from 'formik'; import { Dataset, ReferenceDataCode } from '@catalog-frontend/types'; import { debounce, sortBy } from 'lodash'; -import FieldsetWithDelete from '../../fieldset-with-delete'; +import FieldsetWithDelete from '../../../fieldset-with-delete'; interface Props { - envVariable: string; + referenceDataEnv: string; languages: ReferenceDataCode[]; } -export const GeographySection = ({ envVariable, languages }: Props) => { +export const RecommendedDetailFields = ({ referenceDataEnv, languages }: Props) => { const [searchTerm, setSearchTerm] = useState(''); const { values, setFieldValue } = useFormikContext(); const langNOR = languages.filter((lang) => lang.code === 'NOR')[0]; - const { data: searchHits, isLoading: isSearching } = useSearchAdministrativeUnits(searchTerm, envVariable); - const { data: selectedValues } = useSearchAdministrativeUnitsByUri(values?.spatialList, envVariable); + const { data: searchHits, isLoading: isSearching } = useSearchAdministrativeUnits(searchTerm, referenceDataEnv); + const { data: selectedValues } = useSearchAdministrativeUnitsByUri(values?.spatialList, referenceDataEnv); const debouncedSetSearchTerm = debounce((term: string) => { setSearchTerm(term); @@ -46,17 +49,55 @@ export const GeographySection = ({ envVariable, languages }: Props) => { return ( <> - setFieldValue('spatialList', selectedValues)} - value={values.spatialList || []} - virtual - loading={isSearching} - label={localization.datasetForm.heading.spatial} - /> + setFieldValue('languageList', values)} + value={values.languageList} + legend={ + + } + size='sm' + > + {values.languageList && values.languageList.includes('NOR') && ( + + {getTranslateText(langNOR.label)} + + )} + {sortedLanguages + .filter((lang) => lang.code !== 'NOR') + .map((lang) => ( + + {getTranslateText(lang.label)} + + ))} + +
+ + setFieldValue('spatialList', selectedValues)} + value={values.spatialList || []} + virtual + loading={isSearching} + /> +
( @@ -70,6 +111,7 @@ export const GeographySection = ({ envVariable, languages }: Props) => { > { /> { )} /> - - setFieldValue('languageList', values)} - value={values.languageList} - legend={localization.datasetForm.heading.language} - > - {values.languageList && values.languageList.includes('NOR') && ( - - {getTranslateText(langNOR.label)} - - )} - {sortedLanguages - .filter((lang) => lang.code !== 'NOR') - .map((lang) => ( - - {getTranslateText(lang.label)} - - ))} - ); }; diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-from-distribution/dataset-form-distribution-section.tsx b/apps/dataset-catalog/components/dataset-form/components/distribution-section/dataset-form-distribution-section.tsx similarity index 100% rename from apps/dataset-catalog/components/dataset-form/components/dataset-from-distribution/dataset-form-distribution-section.tsx rename to apps/dataset-catalog/components/dataset-form/components/distribution-section/dataset-form-distribution-section.tsx diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-from-distribution/distribution-details.tsx b/apps/dataset-catalog/components/dataset-form/components/distribution-section/distribution-details.tsx similarity index 100% rename from apps/dataset-catalog/components/dataset-form/components/dataset-from-distribution/distribution-details.tsx rename to apps/dataset-catalog/components/dataset-form/components/distribution-section/distribution-details.tsx diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-from-distribution/distribution-modal.tsx b/apps/dataset-catalog/components/dataset-form/components/distribution-section/distribution-modal.tsx similarity index 100% rename from apps/dataset-catalog/components/dataset-form/components/dataset-from-distribution/distribution-modal.tsx rename to apps/dataset-catalog/components/dataset-form/components/distribution-section/distribution-modal.tsx diff --git a/apps/dataset-catalog/components/dataset-form/components/dataset-from-distribution/distributions.module.css b/apps/dataset-catalog/components/dataset-form/components/distribution-section/distributions.module.css similarity index 100% rename from apps/dataset-catalog/components/dataset-form/components/dataset-from-distribution/distributions.module.css rename to apps/dataset-catalog/components/dataset-form/components/distribution-section/distributions.module.css diff --git a/apps/dataset-catalog/components/dataset-form/components/toggle-field-button.tsx b/apps/dataset-catalog/components/dataset-form/components/toggle-field-button.tsx new file mode 100644 index 000000000..6bcb26f2f --- /dev/null +++ b/apps/dataset-catalog/components/dataset-form/components/toggle-field-button.tsx @@ -0,0 +1,51 @@ +import { Dataset } from '@catalog-frontend/types'; +import { AddButton } from '@catalog-frontend/ui'; +import { localization } from '@catalog-frontend/utils'; +import { useFormikContext } from 'formik'; +import { PropsWithChildren, useMemo } from 'react'; +import FieldsetWithDelete from '../../fieldset-with-delete'; +import _ from 'lodash'; + +type Props = { + fieldName: string; + fieldValues: any; + hasDeleteButton?: boolean; + onDeleteValue?: any; +} & PropsWithChildren; + +export const ToggleFieldButton = ({ children, fieldName, hasDeleteButton, onDeleteValue, fieldValues }: Props) => { + const { setFieldValue } = useFormikContext(); + + const hasFieldValues = (value: any): boolean => { + if (_.isUndefined(value) || _.isNull(value)) { + return false; + } + + if (Array.isArray(value)) { + return value.length > 0; + } + + if (_.isObject(value)) { + return !_.isEmpty(value); + } + + return true; + }; + + const fieldValue = useMemo(() => fieldValues, [fieldValues, fieldName]); + const showField = hasFieldValues(fieldValue); + + return ( + <> + {showField ? ( + hasDeleteButton ? ( + setFieldValue(fieldName, onDeleteValue)}>{children} + ) : ( + children + ) + ) : ( + setFieldValue(fieldName, {})}>{`${localization.add} ${fieldName}`} + )} + + ); +}; diff --git a/apps/dataset-catalog/components/dataset-form/components/uri-with-label-field-set-table.tsx b/apps/dataset-catalog/components/dataset-form/components/uri-with-label-field-set-table.tsx index 4f65aa9ca..bf7e15414 100644 --- a/apps/dataset-catalog/components/dataset-form/components/uri-with-label-field-set-table.tsx +++ b/apps/dataset-catalog/components/dataset-form/components/uri-with-label-field-set-table.tsx @@ -11,6 +11,7 @@ import { uriWithLabelSchema } from '../utils/validation-schema'; interface Props { values: UriWithLabel[] | undefined; fieldName: string; + showLabel?: boolean; } interface ModalProps { @@ -25,12 +26,12 @@ const hasNoFieldValues = (values: UriWithLabel) => { return _.isEmpty(_.trim(values.uri)) && _.isEmpty(_.pickBy(values.prefLabel, _.identity)); }; -export const UriWithLabelFieldsetTable = ({ fieldName, values }: Props) => { +export const UriWithLabelFieldsetTable = ({ fieldName, values, showLabel = true }: Props) => { const { setFieldValue } = useFormikContext(); return ( <> - + {showLabel ?? } {values && values?.length > 0 && !hasNoFieldValues(values[0]) && ( @@ -87,7 +88,13 @@ const FieldModal = ({ fieldName, template, type, onSuccess }: ModalProps) => { return ( <> - {type === 'edit' ? : } + + {type === 'edit' ? ( + + ) : ( + {`${localization.add} ${localization.datasetForm.fieldLabel?.[fieldName]?.toLowerCase()}`} + )} + { +export const DatasetForm = ({ initialValues, referenceData, searchEnv, referenceDataEnv, datasetSeries }: Props) => { const { catalogId, datasetId } = useParams(); const [isDirty, setIsDirty] = useState(false); + const [isSubmitted, setIsSubmitted] = useState(false); + const [isCanceled, setIsCanceled] = useState(false); const { losThemes, dataThemes, provenanceStatements, datasetTypes, frequencies, languages, openLicenses } = referenceData; + const router = useRouter(); useWarnIfUnsavedChanges({ unsavedChanges: isDirty }); @@ -71,9 +62,8 @@ export const DatasetForm = ({ } }; - const router = useRouter(); - const handleCancel = () => { + setIsCanceled(true); router.push(datasetId ? `/catalogs/${catalogId}/datasets/${datasetId}` : `/catalogs/${catalogId}/datasets`); }; @@ -111,17 +101,19 @@ export const DatasetForm = ({ { - const trimmedValues = trimObjectWhitespace(values); - submitType === 'create' ? handleCreate(trimmedValues) : handleUpdate(trimmedValues as Dataset); + validateOnChange={isSubmitted} + validateOnBlur={isSubmitted} + onSubmit={async (values, { setSubmitting }) => { + datasetId === null ? handleCreate(values as Dataset) : await handleUpdate(values as Dataset); setSubmitting(false); + setIsSubmitted(true); }} > - {({ errors, values, dirty, handleSubmit, isValid, setFieldValue }) => { + {({ setFieldValue, values, dirty, isValid, isSubmitting, isValidating, submitForm, errors }) => { setTimeout(() => setIsDirty(dirty), 0); - const notifications = getNotifications({ isValid, hasUnsavedChanges: dirty }); + const notifications = getNotifications({ isValid, hasUnsavedChanges: false }); + + console.log(errors); return ( <> @@ -132,16 +124,18 @@ export const DatasetForm = ({ e.preventDefault(); window.alert(localization.datasetForm.alert.formError); } else { - handleSubmit(e); + submitForm(); } }} > + > + + - + - + - - - - - + - - - - - - - - - - - + @@ -245,22 +211,27 @@ export const DatasetForm = ({ @@ -286,7 +257,7 @@ export const DatasetForm = ({ - + {notifications.length > 0 && } ); diff --git a/apps/dataset-catalog/components/dataset-form/utils/dataset-initial-values.tsx b/apps/dataset-catalog/components/dataset-form/utils/dataset-initial-values.tsx index ec9d054f5..c23c707ec 100644 --- a/apps/dataset-catalog/components/dataset-form/utils/dataset-initial-values.tsx +++ b/apps/dataset-catalog/components/dataset-form/utils/dataset-initial-values.tsx @@ -120,7 +120,7 @@ export const datasetToBeCreatedTemplate = (): DatasetToBeCreated => { relations: [{ uri: '', prefLabel: { nb: '' } }], inSeries: '', distribution: [], - contactPoint: {}, + contactPoint: [], }; }; diff --git a/apps/dataset-catalog/components/dataset-form/utils/validation-schema.tsx b/apps/dataset-catalog/components/dataset-form/utils/validation-schema.tsx index 85f4e4a3a..26d720578 100644 --- a/apps/dataset-catalog/components/dataset-form/utils/validation-schema.tsx +++ b/apps/dataset-catalog/components/dataset-form/utils/validation-schema.tsx @@ -64,15 +64,13 @@ export const datasetValidationSchema = Yup.object().shape({ .url(localization.validation.invalidUrl), }), ), - contactPoint: Yup.array().of( - Yup.object().shape({ - hasURL: Yup.string() - .matches(httpsRegex, localization.validation.invalidProtocol) - .url(localization.validation.invalidUrl), - email: Yup.string().email(localization.validation.invalidEmail), - hasTelephone: Yup.string().matches(telephoneNumberRegex, localization.validation.invalidTlf), - }), - ), + // contactPoint: Yup.object().shape({ + // hasURL: Yup.string() + // .matches(httpsRegex, localization.validation.invalidProtocol) + // .url(localization.validation.invalidUrl), + // email: Yup.string().email(localization.validation.invalidEmail), + // hasTelephone: Yup.string().matches(telephoneNumberRegex, localization.validation.invalidTlf), + // }), }); export const distributionSectionSchema = Yup.object().shape({ diff --git a/libs/ui/src/lib/formik-search-combobox/index.tsx b/libs/ui/src/lib/formik-search-combobox/index.tsx index f6b34f2bd..47aeb1c8b 100644 --- a/libs/ui/src/lib/formik-search-combobox/index.tsx +++ b/libs/ui/src/lib/formik-search-combobox/index.tsx @@ -54,6 +54,7 @@ export function FormikSearchCombobox({ placeholder={`${localization.search.search}...`} multiple filter={() => true} // disable filter + size='sm' > {`${localization.search.noHits}... `} {comboboxOptions.map((item) => ( diff --git a/libs/ui/src/lib/title-with-tag/index.tsx b/libs/ui/src/lib/title-with-tag/index.tsx index 775b9ada9..97d391a02 100644 --- a/libs/ui/src/lib/title-with-tag/index.tsx +++ b/libs/ui/src/lib/title-with-tag/index.tsx @@ -13,10 +13,10 @@ type TagColor = 'first' | 'second' | 'success' | 'danger' | 'third' | 'neutral' type TagSize = 'sm' | 'md' | 'lg' | 'small' | 'medium' | 'large'; -export function TitleWithTag({ title, tagTitle, tagColor = 'warning', tagSize = 'medium' }: Props) { +export function TitleWithTag({ title, tagTitle, tagColor = 'warning', tagSize = 'sm' }: Props) { return (
- {typeof title === 'string' ? : title} + {typeof title === 'string' ? : title}