@datagouv/components-next 1.0.2-dev.6 → 1.0.2-dev.60
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/assets/main.css +4 -0
- package/dist/Datafair.client-4zDFMXaE.js +30 -0
- package/dist/JsonPreview.client-DSKs3Wg7.js +40 -0
- package/dist/{MapContainer.client-DRkAmdOc.js → MapContainer.client-Cjwpar3k.js} +35 -38
- package/dist/{PdfPreview.client-C-w6-w44.js → PdfPreview.client-6H3KMLOL.js} +822 -865
- package/dist/{Pmtiles.client-BR7_ldHY.js → Pmtiles.client-BDAAb3_H.js} +574 -579
- package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-BFSXn0mv.js +61 -0
- package/dist/XmlPreview.client-DnL8nMyL.js +34 -0
- package/dist/components-next.css +3 -3
- package/dist/components-next.js +140 -131
- package/dist/components.css +1 -1
- package/dist/{index-SrYZwgCT.js → index-7yWP5a5K.js} +1 -1
- package/dist/main-C-0Gkcks.js +73004 -0
- package/dist/{vue3-xml-viewer.common-BRxsqI9j.js → vue3-xml-viewer.common-xigir_CG.js} +1 -1
- package/package.json +14 -9
- package/src/components/ActivityList/ActivityList.vue +0 -2
- package/src/components/Form/SearchableSelect.vue +2 -1
- package/src/components/InfiniteLoader.vue +53 -0
- package/src/components/OpenApiViewer/ContentTypeSelect.vue +48 -0
- package/src/components/OpenApiViewer/EndpointRequest.vue +164 -0
- package/src/components/OpenApiViewer/EndpointResponses.vue +149 -0
- package/src/components/OpenApiViewer/OpenApiViewer.vue +308 -0
- package/src/components/OpenApiViewer/SchemaPanel.vue +53 -0
- package/src/components/OpenApiViewer/SchemaTree.vue +77 -0
- package/src/components/OpenApiViewer/openapi.ts +150 -0
- package/src/components/OrganizationNameWithCertificate.vue +3 -2
- package/src/components/Pagination.vue +8 -5
- package/src/components/ReadMore.vue +1 -1
- package/src/components/ResourceAccordion/Datafair.client.vue +4 -10
- package/src/components/ResourceAccordion/JsonPreview.client.vue +23 -121
- package/src/components/ResourceAccordion/MapContainer.client.vue +7 -11
- package/src/components/ResourceAccordion/Metadata.vue +1 -2
- package/src/components/ResourceAccordion/PdfPreview.client.vue +24 -103
- package/src/components/ResourceAccordion/Pmtiles.client.vue +5 -10
- package/src/components/ResourceAccordion/Preview.vue +15 -20
- package/src/components/ResourceAccordion/PreviewLoader.vue +1 -2
- package/src/components/ResourceAccordion/PreviewUnavailable.vue +22 -0
- package/src/components/ResourceAccordion/PreviewWrapper.vue +82 -0
- package/src/components/ResourceAccordion/ResourceAccordion.vue +5 -7
- package/src/components/ResourceAccordion/XmlPreview.client.vue +16 -115
- package/src/components/ResourceExplorer/ResourceExplorer.vue +81 -13
- package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +2 -2
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +30 -11
- package/src/components/Search/GlobalSearch.vue +164 -107
- package/src/components/TabularExplorer/TabularCell.vue +51 -0
- package/src/components/TabularExplorer/TabularCellPopover.vue +170 -0
- package/src/components/TabularExplorer/TabularExplorer.vue +870 -0
- package/src/components/TabularExplorer/TabularFilterContent.vue +351 -0
- package/src/components/TabularExplorer/TabularFilterPopover.vue +111 -0
- package/src/components/TabularExplorer/types.ts +83 -0
- package/src/composables/useResourceCapabilities.ts +1 -1
- package/src/composables/useSearchFilter.ts +90 -0
- package/src/composables/useStableQueryParams.ts +28 -3
- package/src/config.ts +2 -0
- package/src/functions/api.ts +34 -33
- package/src/functions/api.types.ts +1 -0
- package/src/functions/datasets.ts +0 -17
- package/src/functions/resources.ts +56 -1
- package/src/functions/tabular.ts +60 -0
- package/src/functions/tabularApi.ts +4 -6
- package/src/main.ts +14 -6
- package/src/types/dataservices.ts +2 -0
- package/src/types/pages.ts +0 -5
- package/src/types/posts.ts +2 -2
- package/src/types/reports.ts +3 -0
- package/src/types/search.ts +45 -1
- package/src/types/site.ts +5 -3
- package/src/types/users.ts +0 -1
- package/assets/swagger-themes/newspaper.css +0 -1670
- package/dist/Datafair.client-E5D6ePRC.js +0 -35
- package/dist/JsonPreview.client-C-6eBbPw.js +0 -87
- package/dist/Swagger.client-D4-F6yEf.js +0 -4
- package/dist/XmlPreview.client-Dl2VCgXF.js +0 -79
- package/dist/main-B2kXxWRG.js +0 -105833
- package/src/components/ResourceAccordion/Swagger.client.vue +0 -48
- package/src/functions/pagination.ts +0 -9
- /package/assets/illustrations/{_microscope.svg → microscope.svg} +0 -0
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<ClientOnly>
|
|
3
|
+
<Teleport to="#tooltips">
|
|
4
|
+
<div
|
|
5
|
+
v-if="cell"
|
|
6
|
+
ref="panel"
|
|
7
|
+
class="bg-white border border-black/10 rounded-lg shadow-md w-80 absolute z-[800]"
|
|
8
|
+
:style="floatingStyles"
|
|
9
|
+
>
|
|
10
|
+
<!-- Value -->
|
|
11
|
+
<div class="px-3 pt-3 pb-2 border-b border-gray-default">
|
|
12
|
+
<p class="text-[10px] text-gray-plain mb-0">
|
|
13
|
+
{{ t('Valeur brute') }}
|
|
14
|
+
</p>
|
|
15
|
+
<p class="text-xs text-gray-title mb-0">
|
|
16
|
+
{{ displayValue }}
|
|
17
|
+
</p>
|
|
18
|
+
</div>
|
|
19
|
+
|
|
20
|
+
<!-- Type -->
|
|
21
|
+
<div class="flex items-center gap-2 px-3 py-2 border-b border-gray-default">
|
|
22
|
+
<span class="text-[10px] text-gray-plain">{{ t('Type') }}</span>
|
|
23
|
+
<span class="inline-flex items-center gap-1 bg-gray-some rounded px-1.5 py-0.5 text-xs text-gray-plain">
|
|
24
|
+
<component
|
|
25
|
+
:is="typeIcon"
|
|
26
|
+
class="size-3"
|
|
27
|
+
aria-hidden="true"
|
|
28
|
+
/>
|
|
29
|
+
{{ typeLabel }}
|
|
30
|
+
</span>
|
|
31
|
+
<span class="text-[10px] text-gray-plain shrink-0">·</span>
|
|
32
|
+
<span class="text-[10px] text-gray-plain truncate min-w-0">{{ cell.column }}</span>
|
|
33
|
+
</div>
|
|
34
|
+
|
|
35
|
+
<!-- Actions -->
|
|
36
|
+
<div class="p-1">
|
|
37
|
+
<button
|
|
38
|
+
class="flex items-center gap-2.5 w-full px-3 py-2 rounded-md text-xs font-medium hover:bg-gray-50"
|
|
39
|
+
@click="filterByValue"
|
|
40
|
+
>
|
|
41
|
+
<RiFilter2Line
|
|
42
|
+
class="size-4"
|
|
43
|
+
aria-hidden="true"
|
|
44
|
+
/>
|
|
45
|
+
{{ t('Filtrer par cette valeur') }}
|
|
46
|
+
</button>
|
|
47
|
+
<button
|
|
48
|
+
class="flex items-center gap-2.5 w-full px-3 py-2 rounded-md text-xs font-medium hover:bg-gray-50"
|
|
49
|
+
@click="copyValue"
|
|
50
|
+
>
|
|
51
|
+
<RiCheckLine
|
|
52
|
+
v-if="copied"
|
|
53
|
+
class="size-4 text-green-500"
|
|
54
|
+
aria-hidden="true"
|
|
55
|
+
/>
|
|
56
|
+
<RiFileCopyLine
|
|
57
|
+
v-else
|
|
58
|
+
class="size-4 text-gray-plain"
|
|
59
|
+
aria-hidden="true"
|
|
60
|
+
/>
|
|
61
|
+
{{ copied ? t('Copié !') : t('Copier la valeur') }}
|
|
62
|
+
</button>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
</Teleport>
|
|
66
|
+
</ClientOnly>
|
|
67
|
+
</template>
|
|
68
|
+
|
|
69
|
+
<script setup lang="ts">
|
|
70
|
+
import { computed, ref, useTemplateRef, watch } from 'vue'
|
|
71
|
+
import { flip, shift, autoUpdate, useFloating } from '@floating-ui/vue'
|
|
72
|
+
import { onClickOutside } from '@vueuse/core'
|
|
73
|
+
import {
|
|
74
|
+
RiFilter2Line,
|
|
75
|
+
RiFileCopyLine,
|
|
76
|
+
RiCheckLine,
|
|
77
|
+
} from '@remixicon/vue'
|
|
78
|
+
import { toast } from 'vue-sonner'
|
|
79
|
+
import { useTranslation } from '../../composables/useTranslation'
|
|
80
|
+
import { buildTypeConfig } from '../../functions/tabular'
|
|
81
|
+
import ClientOnly from '../ClientOnly.vue'
|
|
82
|
+
import type { ColumnType, ColumnFilters } from './types'
|
|
83
|
+
|
|
84
|
+
export interface CellInfo {
|
|
85
|
+
column: string
|
|
86
|
+
columnType: ColumnType
|
|
87
|
+
value: unknown
|
|
88
|
+
element: HTMLElement
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const cell = defineModel<CellInfo | null>('cell', { default: null })
|
|
92
|
+
const filters = defineModel<Record<string, ColumnFilters>>('filters', { default: () => ({}) })
|
|
93
|
+
|
|
94
|
+
const { t } = useTranslation()
|
|
95
|
+
|
|
96
|
+
const panelRef = useTemplateRef<HTMLElement>('panel')
|
|
97
|
+
const anchorRef = ref<HTMLElement | null>(null)
|
|
98
|
+
|
|
99
|
+
watch(cell, (c) => {
|
|
100
|
+
anchorRef.value = c?.element ?? null
|
|
101
|
+
})
|
|
102
|
+
|
|
103
|
+
const { floatingStyles } = useFloating(anchorRef, panelRef, {
|
|
104
|
+
placement: 'bottom-start',
|
|
105
|
+
middleware: [flip(), shift()],
|
|
106
|
+
whileElementsMounted: autoUpdate,
|
|
107
|
+
})
|
|
108
|
+
|
|
109
|
+
const displayValue = computed(() => {
|
|
110
|
+
if (!cell.value) return ''
|
|
111
|
+
const v = cell.value.value
|
|
112
|
+
if (v == null || v === '') return '–'
|
|
113
|
+
if (typeof v === 'object') return JSON.stringify(v)
|
|
114
|
+
return String(v)
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
const typeConfig = buildTypeConfig(t)
|
|
118
|
+
|
|
119
|
+
const typeIcon = computed(() => cell.value ? typeConfig[cell.value.columnType].icon : typeConfig.text.icon)
|
|
120
|
+
const typeLabel = computed(() => cell.value ? typeConfig[cell.value.columnType].label : '')
|
|
121
|
+
|
|
122
|
+
function close() {
|
|
123
|
+
cell.value = null
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function filterByValue() {
|
|
127
|
+
if (!cell.value) return
|
|
128
|
+
const val = String(cell.value.value ?? '')
|
|
129
|
+
const col = cell.value.column
|
|
130
|
+
const existing = filters.value[col] ?? {}
|
|
131
|
+
if (cell.value.columnType === 'categorical' || cell.value.columnType === 'text' || cell.value.columnType === 'date') {
|
|
132
|
+
const current = existing.in ?? []
|
|
133
|
+
if (!current.includes(val)) {
|
|
134
|
+
filters.value = { ...filters.value, [col]: { ...existing, in: [...current, val] } }
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
else if (cell.value.columnType === 'number') {
|
|
138
|
+
const num = Number(cell.value.value)
|
|
139
|
+
if (Number.isFinite(num)) {
|
|
140
|
+
filters.value = { ...filters.value, [col]: { ...existing, min: num, max: num } }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
else if (cell.value.columnType === 'boolean') {
|
|
144
|
+
filters.value = { ...filters.value, [col]: { ...existing, exact: val } }
|
|
145
|
+
}
|
|
146
|
+
close()
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const copied = ref(false)
|
|
150
|
+
|
|
151
|
+
async function copyValue() {
|
|
152
|
+
try {
|
|
153
|
+
await navigator.clipboard.writeText(displayValue.value)
|
|
154
|
+
copied.value = true
|
|
155
|
+
setTimeout(() => {
|
|
156
|
+
copied.value = false
|
|
157
|
+
}, 1500)
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
toast.error(t('Impossible de copier dans le presse-papier'))
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
onClickOutside(panelRef, (e) => {
|
|
165
|
+
if (!cell.value) return
|
|
166
|
+
const clickedCell = (e.target as HTMLElement).closest('[data-cell]')
|
|
167
|
+
if (clickedCell && clickedCell === cell.value.element) return
|
|
168
|
+
close()
|
|
169
|
+
})
|
|
170
|
+
</script>
|