Skip to content
Snippets Groups Projects
Commit a1eb981f authored by Mathieu Massaviol's avatar Mathieu Massaviol
Browse files

Creation du OcCatalogForm #35

parent bf0cae72
No related branches found
No related tags found
1 merge request!73Resolve "Créer un catalogue"
import type { Meta, StoryObj } from '@storybook/vue3';
import OcCatalogForm from './OcCatalogForm.vue';
const meta: Meta<typeof OcCatalogForm> = {
component: OcCatalogForm,
};
export default meta;
type Story = StoryObj<typeof OcCatalogForm>;
export const Default: Story = {
render: (args) => ({
components: { OcCatalogForm },
setup() {
return { args };
},
template: '<OcCatalogForm v-bind="args" />',
}),
args: {
modelValue: {},
},
};
export const CustomLabels: Story = {
render: (args) => ({
components: { OcCatalogForm },
setup() {
return { args };
},
template: '<OcCatalogForm v-bind="args" />',
}),
args: {
modelValue: {},
saveLabel: 'Next',
cancelLabel: 'Exit',
},
};
export const WithoutCancel: Story = {
render: (args) => ({
components: { OcCatalogForm },
setup() {
return { args };
},
template: '<OcCatalogForm v-bind="args" />',
}),
args: {
modelValue: {},
cancelButton: false,
},
};
<template>
<div class="flex items-center gap-3 mb-4">
<label for="mode">{{ t('selectForm') }}</label>
<SelectButton
inputId="mode"
v-model="mode"
:options="modeOptions"
optionLabel="name"
optionValue="value"
/>
</div>
<Form
class="flex flex-col gap-2"
:validation-schema="validationSchema"
:initial-values="model"
@submit="submit"
>
<Field name="title" v-slot="{ value, handleChange, errorMessage }">
<OcField for="title" :metadata="catalogMetadata.title">
<OcMultilingualField
id="title"
:initial-value="value"
@updateValue="handleChange"
:inputComponent="InputText"
:inputProps="{ invalid: !!errorMessage, required: true, fluid: true }"
/>
</OcField>
<Message v-if="errorMessage" severity="error">{{ errorMessage }}</Message>
</Field>
<Field name="description" v-slot="{ value, handleChange, errorMessage }">
<OcField for="description" :metadata="catalogMetadata.description">
<OcMultilingualField
id="description"
:initial-value="value"
@updateValue="handleChange"
:inputComponent="Textarea"
:inputProps="{ invalid: !!errorMessage, required: true, fluid: true }"
/>
</OcField>
<Message v-if="errorMessage" severity="error">{{ errorMessage }}</Message>
</Field>
<Field name="contactPoint" v-slot="{ value, handleChange, errorMessage }">
<OcField for="contactPoint" :metadata="catalogMetadata.contactPoint">
<OcAgentAutocomplete
inputId="contactPoint"
:model-value="value"
@update:model-value="handleChange"
:invalid="!!errorMessage"
required
fluid
/>
</OcField>
<Message v-if="errorMessage" severity="error">{{ errorMessage }}</Message>
</Field>
<Field name="publisher" v-slot="{ value, handleChange, errorMessage }">
<OcField for="publisher" :metadata="catalogMetadata.publisher">
<OcAgentAutocomplete
id="publisher"
:model-value="value"
@update:model-value="handleChange"
:invalid="!!errorMessage"
required
:multiple="false"
targets="organization"
fluid
/>
</OcField>
<Message v-if="errorMessage" severity="error">{{ errorMessage }}</Message>
</Field>
<Field name="issued" v-slot="{ value, errorMessage, handleChange }" v-if="showFair">
<OcField for="issued" :metadata="catalogMetadata.issued">
<DatePicker
id="issued"
:model-value="value"
@update:model-value="handleChange"
:invalid="!!errorMessage"
required
fluid
/>
</OcField>
<Message v-if="errorMessage" severity="error">{{ errorMessage }}</Message>
</Field>
<Field name="theme" v-slot="{ value, handleChange, errorMessage }" v-if="showFair">
<OcField for="theme" :metadata="catalogMetadata.theme" :show-fair-badges="showFair">
<OcConceptAutocomplete
inputId="theme"
:model-value="value"
@update:model-value="handleChange"
:vocabulariesUriList="catalogMetadata.theme.vocabularies ?? []"
:invalid="!!errorMessage"
with-browser
required
fluid
/>
</OcField>
<Message v-if="errorMessage" severity="error">{{ errorMessage }}</Message>
</Field>
<Field name="temporal" v-slot="{ value, errorMessage, handleChange }" v-if="showFair">
<OcField for="temporal" :metadata="catalogMetadata.temporal">
<OcMultipleField
id="temporal"
:initial-value="value"
@updateValue="handleChange"
:inputComponent="DatePicker"
:inputProps="{
selectionMode: 'range',
invalid: !!errorMessage,
required: true,
fluid: true,
class: 'w-full'
}"
/>
</OcField>
<Message v-if="errorMessage" severity="error">{{ errorMessage }}</Message>
</Field>
<Field name="spatial" v-slot="{ value, errorMessage, handleChange }" v-if="showFair">
<OcField for="spatial" :metadata="catalogMetadata.spatial" :show-fair-badges="showFair">
<OcConceptAutocomplete
inputId="spatial"
:model-value="value"
@update:model-value="handleChange"
:vocabulariesUriList="catalogMetadata.spatial.vocabularies ?? []"
:invalid="!!errorMessage"
withBrowser
required
fluid
/>
</OcField>
<Message v-if="errorMessage" severity="error">{{ errorMessage }}</Message>
</Field>
<div class="flex justify-between pt-6">
<Button
v-if="cancelButton"
:label="cancelLabel ?? t('cancel')"
severity="secondary"
icon="fa-solid fa-chevron-left"
iconPos="left"
@click="$emit('cancel')"
/>
<Button
:label="saveLabel ?? t('save')"
icon="fa-solid fa-chevron-right"
class="ml-auto"
iconPos="right"
type="submit"
value="next"
/>
</div>
</Form>
</template>
<script setup lang="ts">
import { Field, Form, type GenericObject } from 'vee-validate'
import * as yup from 'yup'
import type {
OcOrganization,
OcPerson,
OcConcept,
LocalizedProperty,
OcCatalog
} from '@/declarations'
import Button from 'primevue/button'
import { useI18n } from 'vue-i18n'
import DatePicker from 'primevue/datepicker'
import InputText from 'primevue/inputtext'
import Textarea from 'primevue/textarea'
import Message from 'primevue/message'
import OcField from '@/components/FormInputs/OcField/OcField.vue'
import OcAgentAutocomplete from '@/components/FormInputs/OcAgentAutocomplete/OcAgentAutocomplete.vue'
import OcConceptAutocomplete from '@/components/FormInputs/OcConceptAutocomplete/OcConceptAutocomplete.vue'
import { useTranslateValue } from '@/composables/useTranslateValue'
import { catalogMetadata } from '@/modelMetadata/catalog'
import { toTypedSchema } from '@vee-validate/yup'
import SelectButton from 'primevue/selectbutton'
import { ref } from 'vue'
import { computed } from 'vue'
import OcMultilingualField from '../FormInputs/OcMultilingualField/OcMultilingualField.vue'
import OcMultipleField from '../FormInputs/OcMultipleField/OcMultipleField.vue'
const { t } = useI18n()
const { translateValue } = useTranslateValue()
defineProps({
saveLabel: {
type: [String, null],
default: null
},
cancelLabel: {
type: [String, null],
default: null
},
cancelButton: {
type: Boolean,
default: true
}
})
const model = defineModel<Partial<OcCatalog>>({ required: true })
const mode = ref<'fair' | 'mandatory'>('fair')
const modeOptions = computed(() => [
{ name: t('fair.fair'), value: 'fair' },
{ name: t('mandatory'), value: 'mandatory' }
])
const showFair = computed(() => mode.value === 'fair')
const emit = defineEmits<{
save: []
cancel: []
}>()
const validationSchema = toTypedSchema(
yup.object({
title: yup
.mixed<LocalizedProperty<string>>()
.required()
.label(translateValue(catalogMetadata.title.label)),
description: yup
.mixed<LocalizedProperty<string>>()
.required()
.label(translateValue(catalogMetadata.description.label)),
contactPoint: yup
.mixed<OcPerson | OcOrganization>()
.required()
.label(translateValue(catalogMetadata.contactPoint.label)),
publisher: yup
.object<OcOrganization>()
.required()
.label(translateValue(catalogMetadata.publisher.label)),
issued: yup.date().label(translateValue(catalogMetadata.issued.label)),
theme: yup
.array()
.of(yup.object<OcConcept>())
.label(translateValue(catalogMetadata.theme.label)),
temporal: yup
.array()
.of(
yup.tuple([
yup.date().label(t('form.period.start')),
yup.date().label(t('form.period.end'))
])
)
.label(translateValue(catalogMetadata.temporal.label)),
spatial: yup.mixed<OcConcept>().label(translateValue(catalogMetadata.spatial.label)),
})
)
const submit = async (values: GenericObject) => {
// Mandatory values
model.value.title = values.title
model.value.description = values.description
model.value.contactPoint = values.contactPoint
model.value.publisher = values.publisher
// Optional values
model.value.theme = values.theme
model.value.issued = values.issued
model.value.temporal = values.temporal
model.value.spatial = values.spatial
emit('save')
}
</script>
\ No newline at end of file
......@@ -44,7 +44,14 @@ export type OcResource = {
graph?: string[]
}
export type OcCatalog = OcResource
export type OcCatalog = OcResource & {
contactPoint?: Array<OcPerson | OcOrganization>
publisher?: OcOrganization
theme?: OcConcept[]
issued?: Date
temporal?: [Date, Date][]
spatial?: Array<OcConcept | OcGeometry>
}
export type OcDataset = OcResource & {
otherIdentifier?: OcAdmsIdentifier[]
......
import type { OcCatalog, OcModelMetadata } from '@/declarations'
export const catalogMetadata: OcModelMetadata<OcCatalog> = {
'@id': {
label: '@id'
},
'@type': {
label: '@type'
},
identifier: {
label: {
en: 'Identifier',
fr: 'Identifiant'
},
required: true,
propertyUri: 'http://purl.org/dc/terms/identifier',
dereferencement: 'https://ec-jrc.github.io/dcat-ap-jrc/#catalogue-identifier',
desc: {
en: 'A unique identifier of the resource being described or catalogued.',
fr: 'Un identifiant unique de la ressource décrite ou cataloguée.'
},
fair: ['f'],
comment: {
en: 'The identifier is a text string which is assigned to the resource to provide an unambiguous reference within a particular context.',
fr: "L'identifiant est une chaîne de texte attribuée à la ressource pour fournir une référence non ambiguë dans un contexte particulier."
}
},
title: {
propertyUri: 'http://purl.org/dc/terms/title',
dereferencement: 'https://ec-jrc.github.io/dcat-ap-jrc/#catalogue-title',
label: {
en: 'Title',
fr: 'Titre'
},
required: true,
desc: {
en: 'The name / title of the catalogue',
fr: 'Le nom / titre du catalogue'
},
fair: ['f', 'r'],
context: {
'@container': '@language'
}
},
description: {
propertyUri: 'http://purl.org/dc/terms/description',
dereferencement: 'https://ec-jrc.github.io/dcat-ap-jrc/#catalogue-description',
label: {
en: 'Description',
fr: 'Description'
},
required: true,
desc: {
en: 'The description of the catalogue',
fr: 'La description du catalogue'
},
fair: ['f', 'r'],
context: {
'@container': '@language'
}
},
contactPoint: {
propertyUri: 'http://www.w3.org/ns/dcat#contactPoint',
dereferencement: 'https://ec-jrc.github.io/dcat-ap-jrc/#catalogue-contact-point',
label: {
en: 'Contact Point',
fr: 'Point de contact'
},
required: true,
desc: {
en: 'The contact point for the catalogue',
fr: 'Le point de contact du catalogue'
},
fair: ['f', 'a', 'r']
},
publisher: {
propertyUri: 'http://purl.org/dc/terms/publisher',
dereferencement: 'https://ec-jrc.github.io/dcat-ap-jrc/#catalogue-publisher',
label: {
en: 'Publisher',
fr: 'Éditeur'
},
required: true,
desc: {
en: 'The organisation responsible for the publication of the catalogue',
fr: "L'organisation responsable de la publication du catalogue"
},
fair: ['f', 'a']
},
theme: {
propertyUri: 'https://www.w3.org/ns/dcat#theme',
dereferencement: 'https://semiceu.github.io/DCAT-AP/releases/3.0.0/#Catalogue.themes',
label: {
en: 'Theme',
fr: 'Thème'
},
required: false,
desc: {
en: 'A main category of the catalogue. A catalogue can have multiple themes.',
fr: 'Catégorie principale du catalogue. Un catalogue peut avoir plusieurs thèmes.'
},
fair: ['f', 'i'],
vocabularies: ['http://publications.europa.eu/resource/authority/data-theme'],
context: {
'@container': '@set'
}
},
issued: {
label: {
en: 'Publication date (release date)',
fr: 'Date de publication'
},
required: false,
desc: {
en: 'Date of formal issuance (e.g., publication) of the catalogue.',
fr: "Date d'émission officielle (par exemple, publication) de la ressource."
},
propertyUri: 'http://purl.org/dc/terms/issued',
dereferencement: 'https://semiceu.github.io/DCAT-AP/releases/3.0.0/#Catalogue.releasedate',
fair: ['a'],
comment: {
en: 'This property SHOULD be set using the first known date of issuance.',
fr: "Cette propriété DEVRAIT être définie en utilisant la première date d'émission connue."
}
},
temporal: {
label: {
en: 'Temporal coverage',
fr: 'Couverture temporelle'
},
required: false,
desc: {
en: 'The temporal period that the catalogue and its contents covers.',
fr: 'Couverture temporelle du catalogue et de ses contenus.'
},
propertyUri: 'http://purl.org/dc/terms/temporal',
dereferencement: 'https://semiceu.github.io/DCAT-AP/releases/3.0.0/#Catalogue.temporalcoverage',
fair: ['f'],
comment: {
en: 'The temporal coverage of a catalogue may be encoded as an instance of dcterms:PeriodOfTime, or may be indicated using an IRI reference (link) to a resource describing a time period or interval.',
fr: "La couverture temporelle d'un catalogue peut être encodée comme une instance de dcterms:PeriodOfTime, ou peut être indiquée en utilisant une référence IRI (lien) vers une ressource décrivant une période ou un intervalle de temps."
}
},
spatial: {
label: {
en: 'Spatial/geographical coverage',
fr: 'Couverture spatiale'
},
required: false,
desc: {
en: 'The geographical area covered by the catalogue and its contents.',
fr: 'Emprise spatiale/géographique du catalogue et de ses contenus.'
},
propertyUri: 'http://purl.org/dc/terms/spatial',
dereferencement: 'https://semiceu.github.io/DCAT-AP/releases/3.0.0/#Catalogue.geographicalcoverage',
fair: ['f'],
vocabularies: [
'http://publications.europa.eu/resource/authority/continent',
'http://publications.europa.eu/resource/authority/country'
],
comment: {
en: 'The spatial coverage of a catalogue may be encoded as an instance of dcterms:Location, or may be indicated using an IRI reference (link) to a resource describing a location. It is recommended that links are to entries in a well maintained gazetteer such as Geonames.',
fr: "La couverture spatiale d'un catalogue peut être encodée comme une instance de dcterms:Location, ou peut être indiquée en utilisant une référence IRI (lien) vers une ressource décrivant une localisation. Il est recommandé que les liens renvoient à des entrées d'un répertoire toponymique bien tenu, tel que Geonames."
}
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment