Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions datagouv-components/src/components/DatasetCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,12 @@
</p>
</div>
</div>
<ObjectCardShortDescription
v-if="showDescriptionShort"
:text="getDescriptionShort(props.dataset)"
/>
<slot>
<ObjectCardShortDescription
v-if="showDescriptionShort"
:text="getDescriptionShort(props.dataset)"
/>
</slot>
</ObjectCard>
</template>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,45 +49,23 @@
</template>

<script setup lang="ts">
import { onMounted, ref } from 'vue'
import { computed } from 'vue'
import type { Resource } from '../../types/resources'
import { useGetProfile } from '../../functions/tabularApi'
import { useTranslation } from '../../composables/useTranslation'
import { injectTabularProfile } from '../../composables/useTabularProfile'
import PreviewLoader from './PreviewLoader.vue'

const props = defineProps<{ resource: Resource }>()
const getProfile = useGetProfile()
const { t } = useTranslation()

type ColumnInfo = {
score: number
format: string
python_type: string
}
// Profile is shared with sibling components (e.g. TabularExplorer) via
// `provideTabularProfile` in the parent. Falls back to a local fetch
// when no parent provides it (standalone usage).
const { data: profileData, status } = await injectTabularProfile(() => props.resource.id)

const columns = ref<Array<string>>([])
const columnsInfo = ref<Record<string, ColumnInfo>>({})
const loading = ref(true)
const hasError = ref(false)
const hasColumnInfo = ref(false)

onMounted(async () => {
try {
const response = await getProfile(props.resource.id) // Assurez-vous que cette fonction retourne bien les données attendues
if ('profile' in response && response.profile) {
columns.value = Object.keys(response.profile.columns)
columnsInfo.value = response.profile.columns
hasColumnInfo.value = true
loading.value = false
}
else {
hasError.value = true
loading.value = false
}
}
catch {
hasError.value = true
loading.value = false
}
})
const loading = computed(() => status.value === 'idle' || status.value === 'pending')
const hasError = computed(() => status.value === 'error')
const hasColumnInfo = computed(() => !!profileData.value?.profile?.columns)
const columns = computed(() => profileData.value?.profile ? Object.keys(profileData.value.profile.columns) : [])
const columnsInfo = computed(() => profileData.value?.profile?.columns ?? {})
</script>
160 changes: 160 additions & 0 deletions datagouv-components/src/components/ResourceAccordion/Downloads.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<template>
<dl class="fr-pl-0">
<dt
v-if="resource.format === 'url'"
class="font-bold fr-text--sm fr-mb-0"
>
{{ t("URL d'origine") }}
</dt>
<dt
v-else
class="font-bold fr-text--sm fr-mb-0"
>
{{ t('Format original') }}
</dt>
<dd class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center">
<span
v-if="resource.format === 'url'"
class="inline-flex items-center max-w-full"
>
<a
:href="resource.latest"
class="fr-link no-icon-after truncate"
rel="ugc nofollow noopener"
target="_blank"
@click="trackEvent('Jeux de données', 'Télécharger un fichier', 'Bouton : télécharger un fichier')"
>
{{ resource.url }}
</a>
<span class="fr-ml-1v fr-icon-external-link-line fr-icon--sm shrink-0" />
</span>
<span v-else>
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
<a
:href="resource.latest"
class="fr-link"
rel="ugc nofollow noopener"
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${resource.format}`)"
>
<span>{{ t('Format {format}', { format: resource.format }) }}<span v-if="resourceFilesize"> - {{ filesize(resourceFilesize) }}</span></span>
</a>
</span>
<CopyButton
:label="t('Copier le lien')"
:copied-label="t('Lien copié !')"
:text="resource.latest"
class="relative"
/>
</dd>
<template v-if="generatedFormats.length">
<dt class="font-bold fr-text--sm fr-mb-0">
{{ t('Formats générés automatiquement par {platform} (dernière mise à jour {date})', { platform: config.name, date: conversionsLastUpdate }) }}
</dt>
<dd
v-for="generatedFormat in generatedFormats"
:key="generatedFormat.format"
class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center"
>
<span>
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
<a
:href="generatedFormat.url"
class="fr-link"
rel="ugc nofollow noopener"
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${generatedFormat.format}`)"
>
<span>{{ t('Format {format}', { format: generatedFormat.format }) }}<span v-if="generatedFormat.size"> - {{ filesize(generatedFormat.size) }}</span></span>
</a>
</span>
<CopyButton
:label="t('Copier le lien')"
:copied-label="t('Lien copié !')"
:text="generatedFormat.url"
class="relative"
/>
</dd>
</template>
<template v-if="wfsFormats.length">
<dt class="font-bold fr-text--sm fr-mb-0">
<div class="flex gap-1 items-center">
{{ t('Formats exportés depuis le service WFS') }}
<span v-if="defaultWfsProjection"> ({{ t('projection {crs}', { crs: defaultWfsProjection }) }})</span>
<Tooltip>
<RiInformationLine
class="flex-none size-4"
:aria-label="t(`Le lien de téléchargement interroge directement le flux WFS distant. Le nombre de features téléchargées peut être limité.`)"
aria-hidden="true"
/>
<template #tooltip>
<p class="text-sm font-normal mb-0">
{{ t(`Le lien de téléchargement interroge directement le flux WFS distant.`) }}
</p>
<p class="text-sm font-normal mb-0">
{{ t(`Le nombre de features téléchargées peut être limité.`) }}
</p>
</template>
</Tooltip>
</div>
</dt>
<dd
v-for="wfsFormat in wfsFormats"
:key="wfsFormat.format"
class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center"
>
<span>
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
<a
:href="wfsFormat.url"
class="fr-link"
rel="ugc nofollow noopener"
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${wfsFormat.format}`)"
>
<span>{{ t('Format {format}', { format: wfsFormat.format }) }}</span>
</a>
</span>
<CopyButton
:label="t('Copier le lien')"
:copied-label="t('Lien copié !')"
:text="wfsFormat.url"
class="relative"
/>
</dd>
</template>
</dl>
</template>

<script setup lang="ts">
import { computed } from 'vue'
import { RiInformationLine } from '@remixicon/vue'
import CopyButton from '../CopyButton.vue'
import Tooltip from '../Tooltip.vue'
import { filesize } from '../../functions/helpers'
import { getResourceFilesize } from '../../functions/resources'
import { trackEvent } from '../../functions/matomo'
import { useComponentsConfig } from '../../config'
import { useFormatDate } from '../../functions/dates'
import { useTranslation } from '../../composables/useTranslation'
import { useResourceCapabilities } from '../../composables/useResourceCapabilities'
import type { Resource } from '../../types/resources'
import type { Dataset, DatasetV2 } from '../../types/datasets'

const props = defineProps<{
resource: Resource
dataset: Dataset | DatasetV2
}>()

const { t } = useTranslation()
const config = useComponentsConfig()
const { formatRelativeIfRecentDate } = useFormatDate()

const { generatedFormats, wfsFormats, defaultWfsProjection } = useResourceCapabilities(
() => props.resource,
() => props.dataset,
)

const resourceFilesize = computed(() => getResourceFilesize(props.resource))

const conversionsLastUpdate = computed(() =>
formatRelativeIfRecentDate(props.resource.extras['analysis:parsing:finished_at'] as string | undefined),
)
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -265,88 +265,10 @@
<div
v-if="tab.key === 'downloads'"
>
<dl class="fr-pl-0">
<dt
v-if="resource.format === 'url'"
class="font-bold fr-text--sm fr-mb-0"
>
{{ t("URL d'origine") }}
</dt>
<dt
v-else
class="font-bold fr-text--sm fr-mb-0"
>
{{ t('Format original') }}
</dt>
<dd class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center">
<span v-if="resource.format === 'url'">
<a
:href="resource.latest"
class="fr-link no-icon-after"
rel="ugc nofollow noopener"
target="_blank"
@click="trackEvent('Jeux de données', 'Télécharger un fichier', 'Bouton : télécharger un fichier')"
>
<component
:is="config.textClamp"
v-if="config && config.textClamp"
:auto-resize="true"
:max-lines="1"
:text="resource.url"
>
<template #after>
<span class="fr-ml-1v fr-icon-external-link-line fr-icon--sm" />
</template>
</component>
</a>
</span>
<span v-else>
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
<a
:href="resource.latest"
class="fr-link"
rel="ugc nofollow noopener"
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${resource.format}`)"
>
<span>{{ t('Format {format}', { format: resource.format }) }}<span v-if="resourceFilesize"> - {{ filesize(resourceFilesize) }}</span></span>
</a>
</span>
<CopyButton
:label="t('Copier le lien')"
:copied-label="t('Lien copié !')"
:text="resource.latest"
class="relative"
/>
</dd>
<template v-if="generatedFormats.length">
<dt class="font-bold fr-text--sm fr-mb-0">
{{ t('Formats générés automatiquement par {platform} (dernière mise à jour {date})', { platform: config.name, date: conversionsLastUpdate }) }}
</dt>
<dd
v-for="generatedFormat in generatedFormats"
:key="generatedFormat.format"
class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center"
>
<span>
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
<a
:href="generatedFormat.url"
class="fr-link"
rel="ugc nofollow noopener"
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${generatedFormat.format}`)"
>
<span>{{ t('Format {format}', { format: generatedFormat.format }) }}<span v-if="generatedFormat.size"> - {{ filesize(generatedFormat.size) }}</span></span>
</a>
</span>
<CopyButton
:label="t('Copier le lien')"
:copied-label="t('Lien copié !')"
:text="generatedFormat.url"
class="relative"
/>
</dd>
</template>
</dl>
<Downloads
:resource="resource"
:dataset="dataset"
/>
</div>
<div
v-if="tab.key === 'swagger'"
Expand Down Expand Up @@ -396,11 +318,11 @@ import SchemaBadge from './SchemaBadge.vue'
import ResourceIcon from './ResourceIcon.vue'
import EditButton from './EditButton.vue'
import DataStructure from './DataStructure.vue'
import Downloads from './Downloads.vue'
import Preview from './Preview.vue'
import { isOrganizationCertified } from '../../functions/organizations'
import OpenApiViewer from '../OpenApiViewer/OpenApiViewer.vue'

const GENERATED_FORMATS = ['parquet', 'pmtiles', 'geojson']
const URL_FORMATS = ['url', 'doi', 'www:link', ' www:link-1.0-http--link', 'www:link-1.0-http--partners', 'www:link-1.0-http--related', 'www:link-1.0-http--samples']

const props = withDefaults(defineProps<{
Expand Down Expand Up @@ -460,24 +382,6 @@ const ogcService = computed(() => detectOgcService(props.resource))

const ogcWms = computed(() => ogcService.value === 'wms')

const generatedFormats = computed(() => {
const formats = GENERATED_FORMATS
.filter(format => `analysis:parsing:${format}_url` in props.resource.extras)
.map(format => ({
url: props.resource.extras[`analysis:parsing:${format}_url`] as string,
size: props.resource.extras[`analysis:parsing:${format}_size`] as number | undefined,
format: format,
}))
if ('analysis:parsing:parsing_table' in props.resource.extras) {
formats.push({
url: `${config.tabularApiUrl}/api/resources/${props.resource.id}/data/json/`,
size: undefined,
format: 'json',
})
}
return formats
})

const open = ref(props.expandedOnMount)
const toggle = () => {
open.value = !open.value
Expand Down Expand Up @@ -540,7 +444,6 @@ const communityResource = computed<CommunityResource | null>(() => {
const owner = computed(() => communityResource.value ? getOwnerName(communityResource.value) : null)

const lastUpdate = props.resource.last_modified
const conversionsLastUpdate = computed(() => formatRelativeIfRecentDate(props.resource.extras['analysis:parsing:finished_at'] as string | undefined))
const availabilityChecked = props.resource.extras && 'check:available' in props.resource.extras
const resourceFilesize = computed(() => getResourceFilesize(props.resource))

Expand Down
Loading
Loading