@datagouv/components-next 1.1.2 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{Datafair.client-8bXp6UeQ.js → Datafair.client-rf4T1IkA.js} +1 -1
- package/dist/{JsonPreview.client-BxuoPK_w.js → JsonPreview.client-dzar6iuh.js} +2 -2
- package/dist/{MapContainer.client-CTz0wmJG.js → MapContainer.client-D-MoRNhG.js} +2 -2
- package/dist/{PdfPreview.client-DpVreUSl.js → PdfPreview.client-DoDYLmJD.js} +2 -2
- package/dist/{Pmtiles.client-BwmHo3T8.js → Pmtiles.client-Dzm01Zfm.js} +1 -1
- package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-stmU5qEB.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-BRNYswg3.js} +1 -1
- package/dist/{XmlPreview.client-DAOs89cR.js → XmlPreview.client-cOhwff6P.js} +3 -3
- package/dist/components-next.css +1 -1
- package/dist/components-next.js +160 -155
- package/dist/components.css +1 -1
- package/dist/{index-JqjPja1u.js → index-NofRBuyf.js} +1 -1
- package/dist/{main-D4WQMky0.js → main-Iz1ZCL6k.js} +41691 -89416
- package/dist/{vue3-xml-viewer.common-BGsoNyZe.js → vue3-xml-viewer.common-tVI9uXUz.js} +1 -1
- package/package.json +10 -3
- package/src/chart.ts +5 -0
- package/src/components/ActivityList/ActivityList.vue +3 -0
- package/src/components/DatasetCard.vue +6 -4
- package/src/components/ObjectCardHeader.vue +1 -1
- package/src/components/RadioInput.vue +7 -2
- package/src/components/ResourceAccordion/DataStructure.vue +11 -33
- package/src/components/ResourceAccordion/Downloads.vue +160 -0
- package/src/components/ResourceAccordion/ResourceAccordion.vue +5 -102
- package/src/components/ResourceExplorer/ResourceExplorer.vue +2 -55
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +26 -135
- package/src/components/ResourceExplorer/ResourceSelector.vue +113 -0
- package/src/components/Search/GlobalSearch.vue +11 -4
- package/src/components/TabularExplorer/TabularExplorer.vue +257 -154
- package/src/composables/useHasTabularData.ts +7 -0
- package/src/composables/useStableQueryParams.ts +7 -3
- package/src/composables/useTabularProfile.ts +70 -0
- package/src/functions/activities.ts +3 -3
- package/src/main.ts +12 -6
- package/src/types/search.ts +11 -0
- package/src/types/ui.ts +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<div class="border border-gray-default">
|
|
3
3
|
<header class="p-4 flex flex-wrap md:flex-nowrap gap-4 items-center justify-between">
|
|
4
4
|
<div>
|
|
5
|
-
<div class="flex items-center mb-1">
|
|
5
|
+
<div class="flex items-center gap-1 mb-1">
|
|
6
6
|
<h3 class="m-0 flex items-baseline text-base font-bold leading-tight">
|
|
7
7
|
<ResourceIcon
|
|
8
8
|
:resource
|
|
@@ -10,6 +10,12 @@
|
|
|
10
10
|
/>
|
|
11
11
|
<span class="line-clamp-2">{{ resource.title || t('Fichier sans nom') }}</span>
|
|
12
12
|
</h3>
|
|
13
|
+
<ResourceSelector
|
|
14
|
+
v-if="resources && resources.length > 1"
|
|
15
|
+
:resources
|
|
16
|
+
:selected-id="resource.id"
|
|
17
|
+
@select="emit('select', $event)"
|
|
18
|
+
/>
|
|
13
19
|
<CopyButton
|
|
14
20
|
:label="t('Copier le lien')"
|
|
15
21
|
:copied-label="t('Lien copié !')"
|
|
@@ -139,9 +145,9 @@
|
|
|
139
145
|
v-else-if="hasOpenAPIPreview"
|
|
140
146
|
:url="resource.extras['apidocUrl'] as string"
|
|
141
147
|
/>
|
|
142
|
-
<
|
|
148
|
+
<TabularExplorer
|
|
143
149
|
v-else-if="hasTabularData"
|
|
144
|
-
:resource="resource"
|
|
150
|
+
:resource-id="resource.id"
|
|
145
151
|
/>
|
|
146
152
|
<PreviewUnavailable v-else>
|
|
147
153
|
<!-- "File too large to download" is the only analysis:error value from hydra for now -->
|
|
@@ -174,128 +180,10 @@
|
|
|
174
180
|
<Metadata :resource />
|
|
175
181
|
</div>
|
|
176
182
|
<div v-if="tab.key === 'downloads'">
|
|
177
|
-
<
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
>
|
|
182
|
-
{{ t("URL d'origine") }}
|
|
183
|
-
</dt>
|
|
184
|
-
<dt
|
|
185
|
-
v-else
|
|
186
|
-
class="font-bold fr-text--sm fr-mb-0"
|
|
187
|
-
>
|
|
188
|
-
{{ t('Format original') }}
|
|
189
|
-
</dt>
|
|
190
|
-
<dd class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center">
|
|
191
|
-
<span
|
|
192
|
-
v-if="resource.format === 'url'"
|
|
193
|
-
class="inline-flex items-center max-w-full"
|
|
194
|
-
>
|
|
195
|
-
<a
|
|
196
|
-
:href="resource.latest"
|
|
197
|
-
class="fr-link no-icon-after truncate"
|
|
198
|
-
rel="ugc nofollow noopener"
|
|
199
|
-
target="_blank"
|
|
200
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', 'Bouton : télécharger un fichier')"
|
|
201
|
-
>
|
|
202
|
-
{{ resource.url }}
|
|
203
|
-
</a>
|
|
204
|
-
<span class="fr-ml-1v fr-icon-external-link-line fr-icon--sm shrink-0" />
|
|
205
|
-
</span>
|
|
206
|
-
<span v-else>
|
|
207
|
-
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
|
|
208
|
-
<a
|
|
209
|
-
:href="resource.latest"
|
|
210
|
-
class="fr-link"
|
|
211
|
-
rel="ugc nofollow noopener"
|
|
212
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${resource.format}`)"
|
|
213
|
-
>
|
|
214
|
-
<span>{{ t('Format {format}', { format: resource.format }) }}<span v-if="resourceFilesize"> - {{ filesize(resourceFilesize) }}</span></span>
|
|
215
|
-
</a>
|
|
216
|
-
</span>
|
|
217
|
-
<CopyButton
|
|
218
|
-
:label="t('Copier le lien')"
|
|
219
|
-
:copied-label="t('Lien copié !')"
|
|
220
|
-
:text="resource.latest"
|
|
221
|
-
class="relative"
|
|
222
|
-
/>
|
|
223
|
-
</dd>
|
|
224
|
-
<template v-if="generatedFormats.length">
|
|
225
|
-
<dt class="font-bold fr-text--sm fr-mb-0">
|
|
226
|
-
{{ t('Formats générés automatiquement par {platform} (dernière mise à jour {date})', { platform: config.name, date: conversionsLastUpdate }) }}
|
|
227
|
-
</dt>
|
|
228
|
-
<dd
|
|
229
|
-
v-for="generatedFormat in generatedFormats"
|
|
230
|
-
:key="generatedFormat.format"
|
|
231
|
-
class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center"
|
|
232
|
-
>
|
|
233
|
-
<span>
|
|
234
|
-
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
|
|
235
|
-
<a
|
|
236
|
-
:href="generatedFormat.url"
|
|
237
|
-
class="fr-link"
|
|
238
|
-
rel="ugc nofollow noopener"
|
|
239
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${generatedFormat.format}`)"
|
|
240
|
-
>
|
|
241
|
-
<span>{{ t('Format {format}', { format: generatedFormat.format }) }}<span v-if="generatedFormat.size"> - {{ filesize(generatedFormat.size) }}</span></span>
|
|
242
|
-
</a>
|
|
243
|
-
</span>
|
|
244
|
-
<CopyButton
|
|
245
|
-
:label="t('Copier le lien')"
|
|
246
|
-
:copied-label="t('Lien copié !')"
|
|
247
|
-
:text="generatedFormat.url"
|
|
248
|
-
class="relative"
|
|
249
|
-
/>
|
|
250
|
-
</dd>
|
|
251
|
-
</template>
|
|
252
|
-
<template v-if="wfsFormats.length">
|
|
253
|
-
<dt class="font-bold fr-text--sm fr-mb-0">
|
|
254
|
-
<div class="flex gap-1 items-center">
|
|
255
|
-
{{ t('Formats exportés depuis le service WFS') }}
|
|
256
|
-
<span v-if="defaultWfsProjection"> ({{ t('projection {crs}', { crs: defaultWfsProjection }) }})</span>
|
|
257
|
-
<Tooltip>
|
|
258
|
-
<RiInformationLine
|
|
259
|
-
class="flex-none size-4"
|
|
260
|
-
: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é.`)"
|
|
261
|
-
aria-hidden="true"
|
|
262
|
-
/>
|
|
263
|
-
<template #tooltip>
|
|
264
|
-
<p class="text-sm font-normal mb-0">
|
|
265
|
-
{{ t(`Le lien de téléchargement interroge directement le flux WFS distant.`) }}
|
|
266
|
-
</p>
|
|
267
|
-
<p class="text-sm font-normal mb-0">
|
|
268
|
-
{{ t(`Le nombre de features téléchargées peut être limité.`) }}
|
|
269
|
-
</p>
|
|
270
|
-
</template>
|
|
271
|
-
</Tooltip>
|
|
272
|
-
</div>
|
|
273
|
-
</dt>
|
|
274
|
-
<dd
|
|
275
|
-
v-for="wfsFormat in wfsFormats"
|
|
276
|
-
:key="wfsFormat.format"
|
|
277
|
-
class="text-sm pl-0 mb-4 text-gray-medium h-8 flex flex-wrap items-center"
|
|
278
|
-
>
|
|
279
|
-
<span>
|
|
280
|
-
<span class="text-datagouv fr-icon-download-line fr-icon--sm fr-mr-1v fr-mt-1v" />
|
|
281
|
-
<a
|
|
282
|
-
:href="wfsFormat.url"
|
|
283
|
-
class="fr-link"
|
|
284
|
-
rel="ugc nofollow noopener"
|
|
285
|
-
@click="trackEvent('Jeux de données', 'Télécharger un fichier', `Bouton : format ${wfsFormat.format}`)"
|
|
286
|
-
>
|
|
287
|
-
<span>{{ t('Format {format}', { format: wfsFormat.format }) }}</span>
|
|
288
|
-
</a>
|
|
289
|
-
</span>
|
|
290
|
-
<CopyButton
|
|
291
|
-
:label="t('Copier le lien')"
|
|
292
|
-
:copied-label="t('Lien copié !')"
|
|
293
|
-
:text="wfsFormat.url"
|
|
294
|
-
class="relative"
|
|
295
|
-
/>
|
|
296
|
-
</dd>
|
|
297
|
-
</template>
|
|
298
|
-
</dl>
|
|
183
|
+
<Downloads
|
|
184
|
+
:resource="resource"
|
|
185
|
+
:dataset="dataset"
|
|
186
|
+
/>
|
|
299
187
|
</div>
|
|
300
188
|
<div v-if="tab.key === 'swagger'">
|
|
301
189
|
<div class="fr-mb-4w">
|
|
@@ -318,7 +206,7 @@
|
|
|
318
206
|
|
|
319
207
|
<script setup lang="ts">
|
|
320
208
|
import { computed, defineAsyncComponent } from 'vue'
|
|
321
|
-
import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine,
|
|
209
|
+
import { RiDownloadLine, RiFileCopyLine, RiFileWarningLine, RiSubtractLine } from '@remixicon/vue'
|
|
322
210
|
import PreviewUnavailable from '../ResourceAccordion/PreviewUnavailable.vue'
|
|
323
211
|
import { toast } from 'vue-sonner'
|
|
324
212
|
import BrandedButton from '../BrandedButton.vue'
|
|
@@ -331,11 +219,12 @@ import TabList from '../Tabs/TabList.vue'
|
|
|
331
219
|
import Tab from '../Tabs/Tab.vue'
|
|
332
220
|
import TabPanels from '../Tabs/TabPanels.vue'
|
|
333
221
|
import TabPanel from '../Tabs/TabPanel.vue'
|
|
334
|
-
import
|
|
335
|
-
import Preview from '../ResourceAccordion/Preview.vue'
|
|
222
|
+
import TabularExplorer from '../TabularExplorer/TabularExplorer.vue'
|
|
336
223
|
import DataStructure from '../ResourceAccordion/DataStructure.vue'
|
|
224
|
+
import Downloads from '../ResourceAccordion/Downloads.vue'
|
|
337
225
|
import Metadata from '../ResourceAccordion/Metadata.vue'
|
|
338
226
|
import SchemaBadge from '../ResourceAccordion/SchemaBadge.vue'
|
|
227
|
+
import ResourceSelector from './ResourceSelector.vue'
|
|
339
228
|
import { filesize, summarize } from '../../functions/helpers'
|
|
340
229
|
import { getResourceFormatIcon, getResourceExternalUrl, getResourceFilesize } from '../../functions/resources'
|
|
341
230
|
import { trackEvent } from '../../functions/matomo'
|
|
@@ -343,6 +232,7 @@ import { useComponentsConfig } from '../../config'
|
|
|
343
232
|
import { useFormatDate } from '../../functions/dates'
|
|
344
233
|
import { useTranslation } from '../../composables/useTranslation'
|
|
345
234
|
import { useResourceCapabilities } from '../../composables/useResourceCapabilities'
|
|
235
|
+
import { provideTabularProfile } from '../../composables/useTabularProfile'
|
|
346
236
|
import type { Resource } from '../../types/resources'
|
|
347
237
|
import type { Dataset, DatasetV2 } from '../../types/datasets'
|
|
348
238
|
|
|
@@ -368,6 +258,11 @@ const Pmtiles = defineAsyncComponent(() =>
|
|
|
368
258
|
const props = defineProps<{
|
|
369
259
|
dataset: Dataset | DatasetV2
|
|
370
260
|
resource: Resource
|
|
261
|
+
resources?: Resource[]
|
|
262
|
+
}>()
|
|
263
|
+
|
|
264
|
+
const emit = defineEmits<{
|
|
265
|
+
select: [resource: Resource]
|
|
371
266
|
}>()
|
|
372
267
|
|
|
373
268
|
const { t } = useTranslation()
|
|
@@ -381,13 +276,13 @@ const {
|
|
|
381
276
|
hasOpenAPIPreview,
|
|
382
277
|
ogcService,
|
|
383
278
|
ogcWms,
|
|
384
|
-
generatedFormats,
|
|
385
|
-
wfsFormats,
|
|
386
|
-
defaultWfsProjection,
|
|
387
279
|
isResourceUrl,
|
|
388
280
|
tabsOptions,
|
|
389
281
|
} = useResourceCapabilities(() => props.resource, () => props.dataset)
|
|
390
282
|
|
|
283
|
+
// Share the tabular profile fetch between TabularExplorer and DataStructure tabs.
|
|
284
|
+
await provideTabularProfile(() => props.resource.id)
|
|
285
|
+
|
|
391
286
|
const resourceFilesize = computed(() => getResourceFilesize(props.resource))
|
|
392
287
|
const resourceExternalUrl = computed(() => getResourceExternalUrl(props.dataset, props.resource))
|
|
393
288
|
|
|
@@ -401,10 +296,6 @@ const downloadButtonTitle = computed(() => {
|
|
|
401
296
|
return t('Télécharger le fichier en {format}', { format: format.value })
|
|
402
297
|
})
|
|
403
298
|
|
|
404
|
-
const conversionsLastUpdate = computed(() =>
|
|
405
|
-
formatRelativeIfRecentDate(props.resource.extras['analysis:parsing:finished_at'] as string | undefined),
|
|
406
|
-
)
|
|
407
|
-
|
|
408
299
|
const copyResourceUrl = async () => {
|
|
409
300
|
try {
|
|
410
301
|
await navigator.clipboard.writeText(props.resource.url)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<Popover
|
|
3
|
+
v-slot="{ open, close }"
|
|
4
|
+
class="relative inline-block"
|
|
5
|
+
>
|
|
6
|
+
<slot
|
|
7
|
+
name="trigger"
|
|
8
|
+
:open="open"
|
|
9
|
+
>
|
|
10
|
+
<PopoverButton
|
|
11
|
+
class="inline-flex items-center justify-center size-6 rounded text-gray-plain hover:bg-gray-100 focus:outline-none focus-visible:ring-2 focus-visible:ring-new-primary"
|
|
12
|
+
:aria-label="t('Choisir une autre ressource')"
|
|
13
|
+
>
|
|
14
|
+
<RiArrowDownSLine
|
|
15
|
+
class="size-4"
|
|
16
|
+
:class="{ 'rotate-180': open }"
|
|
17
|
+
aria-hidden="true"
|
|
18
|
+
/>
|
|
19
|
+
</PopoverButton>
|
|
20
|
+
</slot>
|
|
21
|
+
<PopoverPanel
|
|
22
|
+
:class="searchable
|
|
23
|
+
? 'absolute left-0 top-full z-50 mt-2 w-96 max-w-[calc(100vw-2rem)] bg-white border border-gray-default rounded shadow-lg p-3 space-y-2'
|
|
24
|
+
: 'absolute left-0 top-full z-50 mt-1 w-80 max-h-96 overflow-auto bg-white border border-gray-default rounded shadow-lg p-1'"
|
|
25
|
+
>
|
|
26
|
+
<input
|
|
27
|
+
v-if="searchable"
|
|
28
|
+
v-model="searchQuery"
|
|
29
|
+
type="search"
|
|
30
|
+
class="w-full border border-gray-default rounded px-2.5 py-1.5 text-sm"
|
|
31
|
+
:placeholder="t('Rechercher dans les ressources…')"
|
|
32
|
+
>
|
|
33
|
+
<ul
|
|
34
|
+
v-if="filteredResources.length > 0"
|
|
35
|
+
class="list-none p-0 m-0 space-y-0.5 max-h-80 overflow-y-auto"
|
|
36
|
+
>
|
|
37
|
+
<li
|
|
38
|
+
v-for="r in filteredResources"
|
|
39
|
+
:key="r.id"
|
|
40
|
+
>
|
|
41
|
+
<button
|
|
42
|
+
v-if="!isDisabled?.(r)"
|
|
43
|
+
type="button"
|
|
44
|
+
class="flex items-center gap-1.5 w-full text-left px-2 py-1.5 rounded text-sm hover:bg-gray-100 focus:outline-none focus-visible:bg-gray-100"
|
|
45
|
+
:class="{ 'font-bold bg-blue-50 text-new-primary': r.id === selectedId }"
|
|
46
|
+
@click="emit('select', r); close()"
|
|
47
|
+
>
|
|
48
|
+
<ResourceIcon
|
|
49
|
+
:resource="r"
|
|
50
|
+
class="size-3.5 shrink-0"
|
|
51
|
+
/>
|
|
52
|
+
<span class="truncate">{{ r.title || t('Fichier sans nom') }}</span>
|
|
53
|
+
<span
|
|
54
|
+
v-if="r.format"
|
|
55
|
+
class="ml-auto text-xs text-gray-medium uppercase shrink-0"
|
|
56
|
+
>
|
|
57
|
+
{{ r.format }}
|
|
58
|
+
</span>
|
|
59
|
+
</button>
|
|
60
|
+
<div
|
|
61
|
+
v-else
|
|
62
|
+
class="flex items-center gap-1.5 px-2 py-1.5 rounded text-sm text-gray-medium cursor-not-allowed"
|
|
63
|
+
:title="disabledTitle"
|
|
64
|
+
>
|
|
65
|
+
<ResourceIcon
|
|
66
|
+
:resource="r"
|
|
67
|
+
class="size-3.5 shrink-0 opacity-50"
|
|
68
|
+
/>
|
|
69
|
+
<span class="truncate opacity-70">{{ r.title || t('Fichier sans nom') }}</span>
|
|
70
|
+
</div>
|
|
71
|
+
</li>
|
|
72
|
+
</ul>
|
|
73
|
+
<p
|
|
74
|
+
v-else
|
|
75
|
+
class="text-sm text-gray-medium italic mb-0 px-2 py-2"
|
|
76
|
+
>
|
|
77
|
+
{{ t('Aucune ressource correspondante') }}
|
|
78
|
+
</p>
|
|
79
|
+
</PopoverPanel>
|
|
80
|
+
</Popover>
|
|
81
|
+
</template>
|
|
82
|
+
|
|
83
|
+
<script setup lang="ts">
|
|
84
|
+
import { computed, ref } from 'vue'
|
|
85
|
+
import { Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'
|
|
86
|
+
import { RiArrowDownSLine } from '@remixicon/vue'
|
|
87
|
+
import { useTranslation } from '../../composables/useTranslation'
|
|
88
|
+
import ResourceIcon from '../ResourceAccordion/ResourceIcon.vue'
|
|
89
|
+
import type { Resource } from '../../types/resources'
|
|
90
|
+
|
|
91
|
+
const props = defineProps<{
|
|
92
|
+
resources: Resource[]
|
|
93
|
+
selectedId: string
|
|
94
|
+
searchable?: boolean
|
|
95
|
+
isDisabled?: (resource: Resource) => boolean
|
|
96
|
+
disabledTitle?: string
|
|
97
|
+
}>()
|
|
98
|
+
|
|
99
|
+
const emit = defineEmits<{
|
|
100
|
+
select: [resource: Resource]
|
|
101
|
+
}>()
|
|
102
|
+
|
|
103
|
+
const { t } = useTranslation()
|
|
104
|
+
|
|
105
|
+
const searchQuery = ref('')
|
|
106
|
+
|
|
107
|
+
const filteredResources = computed(() => {
|
|
108
|
+
if (!props.searchable) return props.resources
|
|
109
|
+
const q = searchQuery.value.trim().toLowerCase()
|
|
110
|
+
if (!q) return props.resources
|
|
111
|
+
return props.resources.filter(r => (r.title ?? '').toLowerCase().includes(q))
|
|
112
|
+
})
|
|
113
|
+
</script>
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
:value="configKey(typeConfig)"
|
|
37
37
|
:count="resultsMap[configKey(typeConfig)]?.data.value?.total"
|
|
38
38
|
:loading="resultsMap[configKey(typeConfig)]?.status.value === 'pending' || resultsMap[configKey(typeConfig)]?.status.value === 'idle'"
|
|
39
|
-
:icon="strategies[typeConfig.class].icon"
|
|
39
|
+
:icon="typeConfig.icon ?? strategies[typeConfig.class].icon"
|
|
40
40
|
>
|
|
41
41
|
{{ typeConfig.name || strategies[typeConfig.class].name }}
|
|
42
42
|
</RadioInput>
|
|
@@ -200,10 +200,13 @@
|
|
|
200
200
|
<div class="fr-col">
|
|
201
201
|
<select
|
|
202
202
|
id="sort-search"
|
|
203
|
-
v-model="
|
|
203
|
+
v-model="effectiveSort"
|
|
204
204
|
class="fr-select text-sm shadow-input-blue!"
|
|
205
205
|
>
|
|
206
|
-
<option
|
|
206
|
+
<option
|
|
207
|
+
v-if="!currentTypeConfig?.defaultSort"
|
|
208
|
+
:value="undefined"
|
|
209
|
+
>
|
|
207
210
|
{{ t('Pertinence') }}
|
|
208
211
|
</option>
|
|
209
212
|
<option
|
|
@@ -489,6 +492,10 @@ const { debounced: qDebounced, flush: flushQ } = useDebouncedRef(q, componentsCo
|
|
|
489
492
|
const qForParams = computed(() => props.hideSearchInput ? q.value : qDebounced.value)
|
|
490
493
|
const page = useRouteQuery('page', 1, { transform: Number })
|
|
491
494
|
const sort = useRouteQuery<string | undefined>('sort')
|
|
495
|
+
const effectiveSort = computed({
|
|
496
|
+
get: () => sort.value ?? currentTypeConfig.value?.defaultSort,
|
|
497
|
+
set: (value) => { sort.value = value },
|
|
498
|
+
})
|
|
492
499
|
|
|
493
500
|
provide(searchFilterContextKey, {
|
|
494
501
|
register(urlParam, entry) {
|
|
@@ -759,7 +766,7 @@ const rssUrl = computed(() => {
|
|
|
759
766
|
}, currentTypeConfig.value ? configKey(currentTypeConfig.value) : undefined)
|
|
760
767
|
|
|
761
768
|
// Add sort if set
|
|
762
|
-
if (
|
|
769
|
+
if (effectiveSort.value) params.set('sort', effectiveSort.value)
|
|
763
770
|
|
|
764
771
|
const queryString = params.toString()
|
|
765
772
|
const basePath = '/api/1/datasets/recent.atom'
|