@datagouv/components-next 1.3.0 → 1.4.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/{Control-b-43UT2B.js → Control-B9WQxlpJ.js} +10 -10
- package/dist/{Datafair.client-BrjISlaZ.js → Datafair.client-D_6yzJUG.js} +9 -9
- package/dist/{Event-py_AAwJY.js → Event-iXDrp-fy.js} +15 -15
- package/dist/{Image-BHQYZWzH.js → Image-mNMBOofs.js} +22 -22
- package/dist/ImagePreview.client-B0iPhFm3.js +36 -0
- package/dist/{JsonPreview.client-DivFAnbN.js → JsonPreview.client-DSl1kiwC.js} +2 -2
- package/dist/{Map-CtP7leHl.js → Map-BfqKMw0S.js} +165 -165
- package/dist/{MapContainer.client-Cq8tNLZZ.js → MapContainer.client-BSfpk_rT.js} +17 -17
- package/dist/{OSM-gdDSIsDA.js → OSM-CcrUhItr.js} +1 -1
- package/dist/{PdfPreview.client-BNBgLsK2.js → PdfPreview.client-BANFeM6K.js} +438 -427
- package/dist/{Pmtiles.client-CQi5Rw8W.js → Pmtiles.client-DH9ZrsZR.js} +6177 -5967
- package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-I8EZCgzp.js +60 -0
- package/dist/{ScaleLine-hG-FhNqy.js → ScaleLine-VGQ7nkMS.js} +2 -2
- package/dist/{Tile-D6rFonpT.js → Tile-CSpn0Ca8.js} +47 -47
- package/dist/{TileImage-cfrEgz5y.js → TileImage-CpbaEFwd.js} +44 -44
- package/dist/{View-vp7vDb9q.js → View-BYBpt-AU.js} +58 -58
- package/dist/{XmlPreview.client-XCsNvnsZ.js → XmlPreview.client-KCB5mwVf.js} +3 -3
- package/dist/{common-C8efyyuc.js → common-BoeTUnDZ.js} +58 -58
- package/dist/components-next.css +1 -1
- package/dist/components-next.js +199 -172
- package/dist/components.css +1 -1
- package/dist/{index-CXUamc8Z.js → index-DHWzX5vK.js} +4668 -4466
- package/dist/{leaflet-src-BRKv9Ksv.js → leaflet-src-pVQfonBI.js} +1 -1
- package/dist/{main-DKu5SOAl.js → main-BDcYkhOc.js} +41684 -33432
- package/dist/{proj-CsjVeojN.js → proj-DxGbobp7.js} +110 -110
- package/dist/{tilecoord-CPcQJnrF.js → tilecoord-DvX7WWiA.js} +94 -94
- package/dist/{vue3-xml-viewer.common-BIaEIFYG.js → vue3-xml-viewer.common-Bdcn54ST.js} +1 -1
- package/package.json +28 -27
- package/src/components/ActivityList/ActivityList.vue +21 -12
- package/src/components/AppLink.vue +3 -0
- package/src/components/BannerAction.vue +6 -2
- package/src/components/Chart/ChartViewer.vue +111 -17
- package/src/components/Chart/ChartViewerWrapper.vue +28 -16
- package/src/components/ChartCard.vue +112 -0
- package/src/components/CopyButton.vue +6 -2
- package/src/components/DataserviceCard.vue +23 -6
- package/src/components/DataserviceQuality.vue +82 -0
- package/src/components/DataserviceQualityInline.vue +31 -0
- package/src/components/DataserviceQualityTooltipContent.vue +79 -0
- package/src/components/DatasetCard.vue +17 -6
- package/src/components/DatasetInformation/DatasetTemporalitySection.vue +7 -4
- package/src/components/DatasetQuality.vue +11 -11
- package/src/components/DatasetQualityInline.vue +2 -2
- package/src/components/DatasetQualityTooltipContent.vue +1 -1
- package/src/components/DiscussionMessageCard.vue +14 -15
- package/src/components/Form/SchemaSelect.vue +2 -0
- package/src/components/FormattedDate.vue +69 -0
- package/src/components/LoadingBlock.vue +4 -1
- package/src/components/ObjectCard.vue +4 -1
- package/src/components/ObjectCardOwner.vue +13 -1
- package/src/components/Pagination.vue +18 -58
- package/src/components/Placeholder.vue +3 -2
- package/src/components/PostCard.vue +13 -15
- package/src/components/ResourceAccordion/Datafair.client.vue +1 -1
- package/src/components/ResourceAccordion/Downloads.vue +19 -7
- package/src/components/ResourceAccordion/ImagePreview.client.vue +48 -0
- package/src/components/ResourceAccordion/MapContainer.client.vue +1 -8
- package/src/components/ResourceAccordion/Metadata.vue +21 -5
- package/src/components/ResourceAccordion/PdfPreview.client.vue +36 -12
- package/src/components/ResourceAccordion/PdfSkeleton.vue +44 -0
- package/src/components/ResourceAccordion/Pmtiles.client.vue +27 -18
- package/src/components/ResourceAccordion/Preview.vue +8 -4
- package/src/components/ResourceAccordion/PreviewWrapper.vue +17 -10
- package/src/components/ResourceAccordion/ResourceAccordion.vue +29 -9
- package/src/components/ResourceExplorer/ResourceExplorer.vue +105 -209
- package/src/components/ResourceExplorer/ResourceExplorerHeader.vue +79 -0
- package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +104 -71
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +136 -183
- package/src/components/ResourceExplorer/ResourceMainAction.vue +240 -0
- package/src/components/ResourceExplorer/ResourceSelector.vue +24 -86
- package/src/components/ResourceExplorer/ResourceViewerHeader.vue +124 -0
- package/src/components/ResourceExplorer/ResourceViewerSkeleton.vue +96 -0
- package/src/components/ResourceListItem.vue +168 -0
- package/src/components/ReuseCard.vue +18 -6
- package/src/components/ReuseDetails.vue +2 -2
- package/src/components/ReuseHorizontalCard.vue +4 -3
- package/src/components/SchemaCard.vue +10 -1
- package/src/components/Search/Filter/AccessTypeFilter.vue +2 -2
- package/src/components/Search/GlobalSearch.vue +12 -8
- package/src/components/Search/SearchInput.vue +1 -1
- package/src/components/Search/Sidemenu.vue +4 -3
- package/src/components/SmallChart.vue +11 -10
- package/src/components/StatBox.vue +13 -5
- package/src/components/TabularExplorer/TabularActiveFilters.vue +79 -0
- package/src/components/TabularExplorer/TabularCell.vue +7 -8
- package/src/components/TabularExplorer/TabularCellPopover.vue +19 -3
- package/src/components/TabularExplorer/TabularColumnsMenu.vue +112 -0
- package/src/components/TabularExplorer/TabularDateField.vue +41 -0
- package/src/components/TabularExplorer/TabularDateFilter.vue +403 -0
- package/src/components/TabularExplorer/TabularExplorer.vue +122 -913
- package/src/components/TabularExplorer/TabularFilterContent.vue +33 -25
- package/src/components/TabularExplorer/TabularFilterPopover.vue +7 -7
- package/src/components/TabularExplorer/TabularMobileFilterButton.vue +21 -0
- package/src/components/TabularExplorer/TabularMobileFilters.vue +150 -0
- package/src/components/TabularExplorer/TabularRowsInfo.vue +31 -0
- package/src/components/TabularExplorer/TabularSkeleton.vue +92 -0
- package/src/components/TabularExplorer/TabularTable.vue +484 -0
- package/src/components/TabularExplorer/TabularToolbar.vue +25 -0
- package/src/components/TabularExplorer/types.ts +32 -20
- package/src/components/TabularExplorer/useColumnMetadata.ts +98 -0
- package/src/components/TabularExplorer/useTabularContext.ts +82 -0
- package/src/components/TopicCard.vue +15 -14
- package/src/composables/useActiveDescendant.ts +5 -0
- package/src/composables/useDatasetResources.ts +164 -0
- package/src/composables/useHasTabularData.ts +2 -1
- package/src/composables/useResizable.ts +46 -0
- package/src/composables/useResourceCapabilities.ts +47 -39
- package/src/composables/useTranslation.ts +24 -9
- package/src/config.ts +1 -0
- package/src/functions/charts.ts +32 -1
- package/src/functions/dates.ts +26 -7
- package/src/functions/helpers.ts +15 -0
- package/src/functions/metrics.ts +57 -56
- package/src/functions/owned.ts +21 -0
- package/src/functions/paginate.ts +46 -0
- package/src/functions/resourceCapabilities.ts +34 -0
- package/src/functions/resources.ts +83 -0
- package/src/functions/schemas.ts +27 -0
- package/src/functions/scroll.ts +20 -0
- package/src/functions/tabular.ts +119 -4
- package/src/functions/tabularApi.ts +1 -43
- package/src/main.ts +32 -6
- package/src/types/dataservices.ts +15 -0
- package/src/types/organizations.ts +10 -0
- package/src/types/reuses.ts +12 -1
- package/src/types/search.ts +2 -2
- package/src/types/visualizations.ts +5 -0
- package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-C3dDzrIr.js +0 -61
- /package/src/components/{DatasetQualityItem.vue → QualityItem.vue} +0 -0
- /package/src/components/{DatasetQualityItemWarning.vue → QualityItemWarning.vue} +0 -0
- /package/src/components/{DatasetQualityScore.vue → QualityScore.vue} +0 -0
package/src/functions/tabular.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Component } from 'vue'
|
|
2
|
+
import { parseDate, type CalendarDate } from '@internationalized/date'
|
|
2
3
|
import {
|
|
3
4
|
RiHashtag,
|
|
4
5
|
RiPriceTag3Line,
|
|
@@ -22,12 +23,74 @@ import {
|
|
|
22
23
|
} from '@remixicon/vue'
|
|
23
24
|
import { useTranslation } from '../composables/useTranslation'
|
|
24
25
|
import type { TranslationFunction } from '../composables/useTranslation'
|
|
25
|
-
import type { ColumnFilters, ColumnType } from '../components/TabularExplorer/types'
|
|
26
|
+
import type { ColumnFilters, ColumnType, DateFilter } from '../components/TabularExplorer/types'
|
|
27
|
+
import { parseDateValue } from './dates'
|
|
26
28
|
|
|
27
29
|
export function hasFilterForColumn(filters: Record<string, ColumnFilters>, column: string): boolean {
|
|
28
30
|
const f = filters[column]
|
|
29
31
|
if (!f) return false
|
|
30
|
-
return !!(f.in?.length || f.exact != null || f.contains || f.null || f.min != null || f.max != null)
|
|
32
|
+
return !!(f.in?.length || f.exact != null || f.contains || f.null || f.min != null || f.max != null || f.date)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// `initialFilters` is a public prop of TabularExplorer, so a filter can carry
|
|
36
|
+
// anything a consumer put in it. An unparseable date is dropped rather than
|
|
37
|
+
// thrown, the way a non-numeric `min` is already ignored by `Number.isFinite`.
|
|
38
|
+
export function parseIsoDate(value: string | undefined): CalendarDate | null {
|
|
39
|
+
if (!value) return null
|
|
40
|
+
try {
|
|
41
|
+
return parseDate(value)
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* The calendar day a cell of a date column falls on, as an ISO date, or null
|
|
50
|
+
* when the value is not one the API produced. Timestamps keep only their day:
|
|
51
|
+
* filtering a whole day is the useful reading of "filter by this value", where
|
|
52
|
+
* the exact millisecond would only ever match that one row.
|
|
53
|
+
*/
|
|
54
|
+
export function toIsoDay(value: unknown): string | null {
|
|
55
|
+
const day = String(value ?? '').slice(0, 10)
|
|
56
|
+
return parseIsoDate(day) ? day : null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The day interval a date filter selects, half-open: `[lower, upper)`.
|
|
61
|
+
* An absent bound means the interval is open on that side.
|
|
62
|
+
*/
|
|
63
|
+
function dateFilterBounds(filter: DateFilter): { lower: CalendarDate | null, upper: CalendarDate | null } {
|
|
64
|
+
const start = parseIsoDate(filter.start)
|
|
65
|
+
if (!start) return { lower: null, upper: null }
|
|
66
|
+
switch (filter.operator) {
|
|
67
|
+
case 'is':
|
|
68
|
+
return { lower: start, upper: start.add({ days: 1 }) }
|
|
69
|
+
case 'before':
|
|
70
|
+
return { lower: null, upper: start }
|
|
71
|
+
case 'after':
|
|
72
|
+
return { lower: start.add({ days: 1 }), upper: null }
|
|
73
|
+
case 'between': {
|
|
74
|
+
const end = parseIsoDate(filter.end)
|
|
75
|
+
return { lower: start, upper: end ? end.add({ days: 1 }) : null }
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Query params for a date filter, as a half-open day interval.
|
|
82
|
+
*
|
|
83
|
+
* The same two operators cover `date` and `datetime` columns, which
|
|
84
|
+
* `resolveColumnType` merges into one display type. `__exact` would not: a
|
|
85
|
+
* timestamp is never equal to a bare day, so an exact filter silently matches
|
|
86
|
+
* nothing on a `datetime` column.
|
|
87
|
+
*/
|
|
88
|
+
export function buildDateFilterParams(column: string, filter: DateFilter): Record<string, string> {
|
|
89
|
+
const { lower, upper } = dateFilterBounds(filter)
|
|
90
|
+
const params: Record<string, string> = {}
|
|
91
|
+
if (lower) params[`${column}__greater`] = lower.toString()
|
|
92
|
+
if (upper) params[`${column}__strictly_less`] = upper.toString()
|
|
93
|
+
return params
|
|
31
94
|
}
|
|
32
95
|
|
|
33
96
|
export type TypeDisplay = {
|
|
@@ -42,9 +105,19 @@ export function buildTypeConfig(t: TranslationFunction): Record<ColumnType, Type
|
|
|
42
105
|
text: { icon: RiText, label: t('Texte') },
|
|
43
106
|
date: { icon: RiCalendarLine, label: t('Date') },
|
|
44
107
|
boolean: { icon: RiCheckboxLine, label: t('Booléen') },
|
|
108
|
+
year: { icon: RiCalendarLine, label: t('Année') },
|
|
45
109
|
}
|
|
46
110
|
}
|
|
47
111
|
|
|
112
|
+
export function resolveColumnType(colInfo: { python_type: string, format?: string }, isCategorical: boolean): ColumnType {
|
|
113
|
+
if (colInfo.format === 'year') return 'year'
|
|
114
|
+
if (['int', 'float'].includes(colInfo.python_type)) return 'number'
|
|
115
|
+
if (['date', 'datetime'].includes(colInfo.python_type)) return 'date'
|
|
116
|
+
if (colInfo.python_type === 'bool') return 'boolean'
|
|
117
|
+
if (isCategorical) return 'categorical'
|
|
118
|
+
return 'text'
|
|
119
|
+
}
|
|
120
|
+
|
|
48
121
|
// csv-detective formats that carry no semantic meaning beyond the generic
|
|
49
122
|
// display type already resolved by `ColumnType` — these fall back to
|
|
50
123
|
// `buildTypeConfig` (Texte / Nombre / Date / Booléen) in the header.
|
|
@@ -138,8 +211,8 @@ export function useFormatTabular() {
|
|
|
138
211
|
|
|
139
212
|
function formatCellDate(value: unknown): string {
|
|
140
213
|
if (value == null || value === '') return '–'
|
|
141
|
-
const d =
|
|
142
|
-
if (
|
|
214
|
+
const d = parseDateValue(String(value))
|
|
215
|
+
if (!d) return String(value)
|
|
143
216
|
return new Intl.DateTimeFormat(locale, { day: '2-digit', month: '2-digit', year: 'numeric' }).format(d)
|
|
144
217
|
}
|
|
145
218
|
|
|
@@ -149,6 +222,48 @@ export function useFormatTabular() {
|
|
|
149
222
|
const TRUTHY_VALUES = ['true', '1', 'oui', 'yes']
|
|
150
223
|
const FALSY_VALUES = ['false', '0', 'non', 'no']
|
|
151
224
|
|
|
225
|
+
// `encodeURIComponent` leaves `.`, `(` and `)` as-is, but they are the operator
|
|
226
|
+
// separator and the delimiters of the API's `or(...)` grammar: a search value
|
|
227
|
+
// containing one makes the parser reject the whole query with a 400. Wrapping
|
|
228
|
+
// the value in double quotes (as the API README suggests) does not work here —
|
|
229
|
+
// the API keeps them as part of the searched string and returns no result. It
|
|
230
|
+
// does percent-decode the value after parsing, so encoding them is enough.
|
|
231
|
+
function encodeConditionValue(value: string): string {
|
|
232
|
+
return encodeURIComponent(value)
|
|
233
|
+
.replace(/\./g, '%2E')
|
|
234
|
+
.replace(/\(/g, '%28')
|
|
235
|
+
.replace(/\)/g, '%29')
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// A decimal literal, not `Number()`: the API compares against a number column,
|
|
239
|
+
// and it answers an error for the whole `or(...)` when it is handed something it
|
|
240
|
+
// cannot parse as one — which `Number()` happily accepts (`0x10`, `1e5`, ` `).
|
|
241
|
+
const NUMBER_LITERAL_RE = /^-?\d+(\.\d+)?$/
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Builds the OR conditions for global search across all columns.
|
|
245
|
+
* Text and categorical columns get a `__contains` filter; number columns
|
|
246
|
+
* get a `__exact` filter only when the search value is numeric.
|
|
247
|
+
* Year, date and boolean columns are excluded.
|
|
248
|
+
*/
|
|
249
|
+
export function buildGlobalSearchConditions(
|
|
250
|
+
allColumns: string[],
|
|
251
|
+
getColumnType: (col: string) => ColumnType,
|
|
252
|
+
searchValue: string,
|
|
253
|
+
): string[] {
|
|
254
|
+
const conditions: string[] = []
|
|
255
|
+
for (const col of allColumns) {
|
|
256
|
+
const type = getColumnType(col)
|
|
257
|
+
if (type === 'text' || type === 'categorical') {
|
|
258
|
+
conditions.push(col + '__contains.' + encodeConditionValue(searchValue))
|
|
259
|
+
}
|
|
260
|
+
else if (type === 'number' && NUMBER_LITERAL_RE.test(searchValue)) {
|
|
261
|
+
conditions.push(col + '__exact.' + encodeConditionValue(searchValue))
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return conditions
|
|
265
|
+
}
|
|
266
|
+
|
|
152
267
|
export function isTruthy(value: unknown): boolean {
|
|
153
268
|
if (typeof value === 'boolean') return value
|
|
154
269
|
if (typeof value === 'string') return TRUTHY_VALUES.includes(value.toLowerCase())
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ofetch } from 'ofetch'
|
|
2
2
|
import { useComponentsConfig, type PluginConfig } from '../config'
|
|
3
3
|
import type { GenericFilter } from '../types/visualizations'
|
|
4
|
-
import type { SortConfig } from '../components/TabularExplorer/types'
|
|
4
|
+
import type { SortConfig, TabularProfileResponse } from '../components/TabularExplorer/types'
|
|
5
5
|
|
|
6
6
|
export type { SortConfig }
|
|
7
7
|
|
|
@@ -31,48 +31,6 @@ export type FetchTabularDataOptions = {
|
|
|
31
31
|
filters?: GenericFilter | undefined
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
export type TabularProfileResponse = {
|
|
35
|
-
profile: {
|
|
36
|
-
header: Array<string>
|
|
37
|
-
columns: Record<string, {
|
|
38
|
-
score: number
|
|
39
|
-
format: string
|
|
40
|
-
python_type: string
|
|
41
|
-
}>
|
|
42
|
-
formats: Record<string, Array<string>>
|
|
43
|
-
profile: Record<string, {
|
|
44
|
-
tops: Array<{ count: number, value: string }>
|
|
45
|
-
nb_distinct: number
|
|
46
|
-
nb_missing_values: number
|
|
47
|
-
min?: number
|
|
48
|
-
max?: number
|
|
49
|
-
std?: number
|
|
50
|
-
mean?: number
|
|
51
|
-
}>
|
|
52
|
-
encoding: string
|
|
53
|
-
separator: string
|
|
54
|
-
categorical: Array<string>
|
|
55
|
-
total_lines: number
|
|
56
|
-
nb_duplicates: number
|
|
57
|
-
columns_fields: Record<string, {
|
|
58
|
-
score: number
|
|
59
|
-
format: string
|
|
60
|
-
python_type: string
|
|
61
|
-
}>
|
|
62
|
-
columns_labels: Record<string, {
|
|
63
|
-
score: number
|
|
64
|
-
format: string
|
|
65
|
-
python_type: string
|
|
66
|
-
}>
|
|
67
|
-
header_row_idx: number
|
|
68
|
-
heading_columns: number
|
|
69
|
-
trailing_columns: number
|
|
70
|
-
}
|
|
71
|
-
deleted_at: string | null
|
|
72
|
-
dataset_id: string
|
|
73
|
-
indexes: null
|
|
74
|
-
}
|
|
75
|
-
|
|
76
34
|
/**
|
|
77
35
|
* Call Tabular-api to get table content with options object
|
|
78
36
|
*/
|
package/src/main.ts
CHANGED
|
@@ -15,7 +15,7 @@ import type { Owned, OwnedWithFullObject, OwnedWithId } from './types/owned'
|
|
|
15
15
|
import type { Comment, Thread } from './types/discussions'
|
|
16
16
|
import type { PageBloc, ContentBloc, BlocWithTitle, DatasetsListBloc, DataservicesListBloc, ReusesListBloc, LinkInBloc, LinksListBloc, MarkdownBloc, AccordionItemBloc, AccordionListBloc, HeroBloc } from './types/pages'
|
|
17
17
|
import type { Post } from './types/posts'
|
|
18
|
-
import type { ReuseReference, NewReuse, Reuse, ReuseTopic, ReuseType } from './types/reuses'
|
|
18
|
+
import type { ReuseReference, NewReuse, Reuse, ReuseV2, ReuseTopic, ReuseType } from './types/reuses'
|
|
19
19
|
import type { RegisteredSchema, Schema, SchemaDetails, SchemaField, SchemaPath, SchemaPublicationMode, SchemaResponseData, SchemaVersion, ValidataError } from './types/schemas'
|
|
20
20
|
import type { TopicV2, TopicElement, TopicElementClass, TopicElementRel } from './types/topics'
|
|
21
21
|
import type { CommunityResource, FileResourceFileType, RemoteResourceFileType, ResourceFileType, ResourceGroup, ResourceType, Resource } from './types/resources'
|
|
@@ -23,7 +23,8 @@ import type { Site } from './types/site'
|
|
|
23
23
|
import type { Weight, WellType } from './types/ui'
|
|
24
24
|
import type { User, UserReference } from './types/users'
|
|
25
25
|
import type { Report, ReportSubject, ReportReason } from './types/reports'
|
|
26
|
-
import type { Chart, ChartForm, ChartForApi, FilterCondition, Filter, AndFilters, GenericFilter, XAxisType, XAxisSortBy, SortDirection, XAxis, XAxisForm, UnitPosition, YAxis, DataSeriesType, DataSeries, DataSeriesForm } from './types/visualizations'
|
|
26
|
+
import type { Chart, ChartForm, ChartForApi, FilterCondition, Filter, AndFilters, GenericFilter, XAxisType, XAxisSortBy, SortDirection, XAxis, XAxisForm, UnitPosition, YAxis, DataSeriesType, DataSeries, DataSeriesForm, CombinedSort, ColumnDefinition, ColumnsDefinition } from './types/visualizations'
|
|
27
|
+
import type { ColumnFilters, ColumnType, TabularRow } from './components/TabularExplorer/types'
|
|
27
28
|
import type { GlobalSearchConfig, SearchType, SearchTypeConfig, SortOption, HiddenFilter, BuiltInFilterKey, DatasetSearchConfig, DatasetSearchFilters, DataserviceSearchConfig, DataserviceSearchFilters, ReuseSearchConfig, ReuseSearchFilters, OrganizationSearchConfig, OrganizationSearchFilters, TopicSearchConfig, TopicSearchFilters } from './types/search'
|
|
28
29
|
import { getDefaultDatasetConfig, getDefaultDataserviceConfig, getDefaultReuseConfig, getDefaultOrganizationConfig, getDefaultTopicConfig, getDefaultGlobalSearchConfig, defaultDatasetSortOptions, defaultDataserviceSortOptions, defaultReuseSortOptions, defaultOrganizationSortOptions } from './types/search'
|
|
29
30
|
import { useSearchFilter } from './composables/useSearchFilter'
|
|
@@ -37,8 +38,12 @@ import Avatar from './components/Avatar.vue'
|
|
|
37
38
|
import AvatarWithName from './components/AvatarWithName.vue'
|
|
38
39
|
import BannerAction from './components/BannerAction.vue'
|
|
39
40
|
import BrandedButton from './components/BrandedButton.vue'
|
|
41
|
+
import ChartCard from './components/ChartCard.vue'
|
|
40
42
|
import CopyButton from './components/CopyButton.vue'
|
|
41
43
|
import DataserviceCard from './components/DataserviceCard.vue'
|
|
44
|
+
import DataserviceQuality from './components/DataserviceQuality.vue'
|
|
45
|
+
import DataserviceQualityInline from './components/DataserviceQualityInline.vue'
|
|
46
|
+
import DataserviceQualityTooltipContent from './components/DataserviceQualityTooltipContent.vue'
|
|
42
47
|
import DatasetCard from './components/DatasetCard.vue'
|
|
43
48
|
import DataStructure from './components/ResourceAccordion/DataStructure.vue'
|
|
44
49
|
import Downloads from './components/ResourceAccordion/Downloads.vue'
|
|
@@ -47,14 +52,15 @@ import DescriptionListTerm from './components/DescriptionListTerm.vue'
|
|
|
47
52
|
import DescriptionListDetails from './components/DescriptionListDetails.vue'
|
|
48
53
|
import DiscussionMessageCard from './components/DiscussionMessageCard.vue'
|
|
49
54
|
import DateRangeDetails from './components/DateRangeDetails.vue'
|
|
55
|
+
import FormattedDate from './components/FormattedDate.vue'
|
|
50
56
|
import { DatasetInformationSection, DatasetTemporalitySection, DatasetSpatialSection, DatasetSchemaSection, DatasetEmbedSection } from './components/DatasetInformation'
|
|
51
57
|
import LeafletMap from './components/LeafletMap.vue'
|
|
52
58
|
import LicenseBadge from './components/LicenseBadge.vue'
|
|
53
59
|
import Tag from './components/Tag.vue'
|
|
54
60
|
import DatasetQuality from './components/DatasetQuality.vue'
|
|
55
61
|
import DatasetQualityInline from './components/DatasetQualityInline.vue'
|
|
56
|
-
import
|
|
57
|
-
import
|
|
62
|
+
import QualityItem from './components/QualityItem.vue'
|
|
63
|
+
import QualityScore from './components/QualityScore.vue'
|
|
58
64
|
import ProgressBar from './components/ProgressBar.vue'
|
|
59
65
|
import DatasetQualityTooltipContent from './components/DatasetQualityTooltipContent.vue'
|
|
60
66
|
import ExtraAccordion from './components/ExtraAccordion.vue'
|
|
@@ -104,6 +110,9 @@ import SelectGroup from './components/Form/SelectGroup.vue'
|
|
|
104
110
|
import Listbox from './components/Form/Listbox.vue'
|
|
105
111
|
import InfiniteLoader from './components/InfiniteLoader.vue'
|
|
106
112
|
import TabularExplorer from './components/TabularExplorer/TabularExplorer.vue'
|
|
113
|
+
import TabularMobileFilters from './components/TabularExplorer/TabularMobileFilters.vue'
|
|
114
|
+
import TabularTable from './components/TabularExplorer/TabularTable.vue'
|
|
115
|
+
import TabularToolbar from './components/TabularExplorer/TabularToolbar.vue'
|
|
107
116
|
import type { UseFetchFunction } from './functions/api.types'
|
|
108
117
|
import { configKey, useComponentsConfig, type PluginConfig } from './config.js'
|
|
109
118
|
import { ofetch } from 'ofetch'
|
|
@@ -119,6 +128,8 @@ export * from './composables/useTranslation'
|
|
|
119
128
|
export * from './composables/useHasTabularData'
|
|
120
129
|
export * from './composables/useResourceCapabilities'
|
|
121
130
|
export * from './composables/useTabularProfile'
|
|
131
|
+
export * from './composables/useDatasetResources'
|
|
132
|
+
export * from './composables/useResizable'
|
|
122
133
|
|
|
123
134
|
export * from './functions/activities'
|
|
124
135
|
export * from './functions/datasets'
|
|
@@ -227,6 +238,7 @@ export type {
|
|
|
227
238
|
ResourceType,
|
|
228
239
|
ReuseReference,
|
|
229
240
|
Reuse,
|
|
241
|
+
ReuseV2,
|
|
230
242
|
ReuseTopic,
|
|
231
243
|
ReuseType,
|
|
232
244
|
Schema,
|
|
@@ -251,6 +263,12 @@ export type {
|
|
|
251
263
|
Chart,
|
|
252
264
|
ChartForm,
|
|
253
265
|
ChartForApi,
|
|
266
|
+
CombinedSort,
|
|
267
|
+
ColumnDefinition,
|
|
268
|
+
ColumnFilters,
|
|
269
|
+
ColumnType,
|
|
270
|
+
ColumnsDefinition,
|
|
271
|
+
TabularRow,
|
|
254
272
|
FilterCondition,
|
|
255
273
|
Filter,
|
|
256
274
|
AndFilters,
|
|
@@ -327,8 +345,12 @@ export {
|
|
|
327
345
|
AvatarWithName,
|
|
328
346
|
BannerAction,
|
|
329
347
|
BrandedButton,
|
|
348
|
+
ChartCard,
|
|
330
349
|
CopyButton,
|
|
331
350
|
DataserviceCard,
|
|
351
|
+
DataserviceQuality,
|
|
352
|
+
DataserviceQualityInline,
|
|
353
|
+
DataserviceQualityTooltipContent,
|
|
332
354
|
DatasetCard,
|
|
333
355
|
DataStructure,
|
|
334
356
|
Downloads,
|
|
@@ -343,10 +365,11 @@ export {
|
|
|
343
365
|
DiscussionMessageCard,
|
|
344
366
|
DatasetQuality,
|
|
345
367
|
DatasetQualityInline,
|
|
346
|
-
|
|
347
|
-
|
|
368
|
+
QualityItem,
|
|
369
|
+
QualityScore,
|
|
348
370
|
DatasetQualityTooltipContent,
|
|
349
371
|
DateRangeDetails,
|
|
372
|
+
FormattedDate,
|
|
350
373
|
ExtraAccordion,
|
|
351
374
|
LabelTag,
|
|
352
375
|
LeafletMap,
|
|
@@ -399,4 +422,7 @@ export {
|
|
|
399
422
|
Listbox,
|
|
400
423
|
InfiniteLoader,
|
|
401
424
|
TabularExplorer,
|
|
425
|
+
TabularMobileFilters,
|
|
426
|
+
TabularTable,
|
|
427
|
+
TabularToolbar,
|
|
402
428
|
}
|
|
@@ -31,6 +31,20 @@ export type BaseDataservice = Owned & WithAccessType & {
|
|
|
31
31
|
|
|
32
32
|
export type NewDataservice = Omit<BaseDataservice, keyof OwnedWithId> & OwnedWithId
|
|
33
33
|
|
|
34
|
+
export type DataserviceQuality = {
|
|
35
|
+
has_description: boolean
|
|
36
|
+
has_machine_documentation: boolean
|
|
37
|
+
has_technical_documentation: boolean
|
|
38
|
+
has_business_documentation: boolean
|
|
39
|
+
license: boolean
|
|
40
|
+
has_contact_point: boolean
|
|
41
|
+
has_base_api_url: boolean
|
|
42
|
+
availability_documented: boolean
|
|
43
|
+
rate_limiting_documented: boolean
|
|
44
|
+
access_conditions_clear: boolean
|
|
45
|
+
score: number
|
|
46
|
+
}
|
|
47
|
+
|
|
34
48
|
export type Dataservice = Owned & WithAccessType & {
|
|
35
49
|
acronym: string
|
|
36
50
|
archived_at: string | null
|
|
@@ -72,4 +86,5 @@ export type Dataservice = Owned & WithAccessType & {
|
|
|
72
86
|
slug: string
|
|
73
87
|
tags: Array<string>
|
|
74
88
|
title: string
|
|
89
|
+
quality?: DataserviceQuality
|
|
75
90
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { User } from './users'
|
|
2
2
|
import type { Badges } from './badges'
|
|
3
|
+
import type { PageBloc } from './pages'
|
|
3
4
|
|
|
4
5
|
export type MemberRole = 'admin' | 'editor' | 'partial_editor'
|
|
5
6
|
|
|
@@ -68,4 +69,13 @@ export type Organization = {
|
|
|
68
69
|
reuses_by_months: Record<string, number>
|
|
69
70
|
views: number
|
|
70
71
|
}
|
|
72
|
+
// Editorial blocs powering the organization "Présentation" tab. Excluded from
|
|
73
|
+
// the default API read mask, so only present when requested with X-Fields.
|
|
74
|
+
// Read through the API's `public_presentation_blocs`: hidden from the public until
|
|
75
|
+
// published, but always returned to organization administrators.
|
|
76
|
+
presentation_blocs?: Array<PageBloc>
|
|
77
|
+
// Publication date of the blocs. `null` means draft (never public); a set date
|
|
78
|
+
// means published. Like `presentation_blocs`, only present when requested with
|
|
79
|
+
// X-Fields.
|
|
80
|
+
presentation_blocs_published_at?: string | null
|
|
71
81
|
}
|
package/src/types/reuses.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Owned, OwnedWithId } from './owned'
|
|
2
|
-
import type { Dataset } from './datasets'
|
|
2
|
+
import type { Dataset, Rel } from './datasets'
|
|
3
3
|
import type { Badges } from './badges'
|
|
4
4
|
import type { Dataservice } from './dataservices'
|
|
5
5
|
|
|
@@ -51,6 +51,17 @@ export type Reuse = BaseReuse & {
|
|
|
51
51
|
permissions: { edit: boolean, delete: boolean }
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Lightweight reuse returned by the listing endpoints (`/api/2/reuses/` and
|
|
56
|
+
* `/api/2/reuses/search/`): the `datasets` and `dataservices` reference lists
|
|
57
|
+
* are replaced by links to their respective listing endpoints filtered on this
|
|
58
|
+
* reuse, so that listing reuses does not dereference every linked dataset.
|
|
59
|
+
*/
|
|
60
|
+
export type ReuseV2 = Owned & Omit<Reuse, 'datasets' | 'dataservices'> & {
|
|
61
|
+
datasets: Rel
|
|
62
|
+
dataservices: Rel
|
|
63
|
+
}
|
|
64
|
+
|
|
54
65
|
export type ReuseType = {
|
|
55
66
|
id: string
|
|
56
67
|
label: string
|
package/src/types/search.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { AccessType } from './access_types'
|
|
|
4
4
|
import type { Dataset } from './datasets'
|
|
5
5
|
import type { Dataservice } from './dataservices'
|
|
6
6
|
import type { Organization } from './organizations'
|
|
7
|
-
import type {
|
|
7
|
+
import type { ReuseV2 } from './reuses'
|
|
8
8
|
import type { TopicV2 } from './topics'
|
|
9
9
|
import type {
|
|
10
10
|
CERTIFIED,
|
|
@@ -372,7 +372,7 @@ export type GlobalSearchConfig = SearchTypeConfig[]
|
|
|
372
372
|
export type SearchResponseByClass = {
|
|
373
373
|
datasets: DatasetSearchResponse<Dataset>
|
|
374
374
|
dataservices: DataserviceSearchResponse<Dataservice>
|
|
375
|
-
reuses: ReuseSearchResponse<
|
|
375
|
+
reuses: ReuseSearchResponse<ReuseV2>
|
|
376
376
|
organizations: OrganizationSearchResponse<Organization>
|
|
377
377
|
topics: TopicSearchResponse<TopicV2>
|
|
378
378
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { TabularAggregateType } from '../functions/tabularApi'
|
|
2
2
|
import type { Owned, OwnedWithId } from './owned'
|
|
3
|
+
import type { ColumnType } from '../components/TabularExplorer/types'
|
|
3
4
|
|
|
4
5
|
export type FilterCondition = 'exact' | 'differs' | 'is_null' | 'is_not_null' | 'greater' | 'less' | 'strictly_greater' | 'strictly_less'
|
|
5
6
|
export type Filter = {
|
|
@@ -66,6 +67,7 @@ export type Chart = Owned & {
|
|
|
66
67
|
created_at: string
|
|
67
68
|
last_modified: string
|
|
68
69
|
deleted_at: string | null
|
|
70
|
+
image: string | null
|
|
69
71
|
uri: string
|
|
70
72
|
page: string
|
|
71
73
|
x_axis: XAxis
|
|
@@ -87,3 +89,6 @@ export type ChartForm = Omit<ChartForApi, 'x_axis' | 'series' | 'owner' | 'organ
|
|
|
87
89
|
chart_type?: DataSeriesType | null
|
|
88
90
|
filter: GenericFilter | null
|
|
89
91
|
}
|
|
92
|
+
|
|
93
|
+
export type ColumnDefinition = { name: string, type: ColumnType, min?: number, max?: number }
|
|
94
|
+
export type ColumnsDefinition = Record<string, Array<ColumnDefinition>>
|
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
import { defineComponent as _, ref as g, computed as h, onMounted as S, nextTick as w, openBlock as l, createElementBlock as k, renderSlot as C, toDisplayString as r, unref as a, createBlock as n, withCtx as o, createTextVNode as u, createCommentVNode as b } from "vue";
|
|
2
|
-
import { c6 as B, bm as E, bk as L, _ as c } from "./main-DKu5SOAl.js";
|
|
3
|
-
const R = { class: "text-xs" }, q = {
|
|
4
|
-
key: 1,
|
|
5
|
-
class: "text-gray-medium"
|
|
6
|
-
}, V = /* @__PURE__ */ _({
|
|
7
|
-
__name: "PreviewWrapper",
|
|
8
|
-
props: {
|
|
9
|
-
fileType: {},
|
|
10
|
-
resource: {},
|
|
11
|
-
maxSize: {},
|
|
12
|
-
load: { type: Function }
|
|
13
|
-
},
|
|
14
|
-
emits: ["loaded"],
|
|
15
|
-
setup(s, { emit: x }) {
|
|
16
|
-
const i = s, z = x, { t } = B(), p = g(null), d = g(!1), f = g(null), y = h(() => E(i.resource)), T = h(() => L(i.resource)), v = h(() => {
|
|
17
|
-
const e = y.value, m = i.maxSize;
|
|
18
|
-
return !e || !m ? !1 : e <= m;
|
|
19
|
-
});
|
|
20
|
-
return S(async () => {
|
|
21
|
-
if (!(!v.value || T.value === "blocked")) {
|
|
22
|
-
d.value = !0;
|
|
23
|
-
try {
|
|
24
|
-
p.value = await i.load(), await w(), z("loaded");
|
|
25
|
-
} catch (e) {
|
|
26
|
-
console.error("Error loading preview:", e), f.value = e instanceof TypeError ? "network" : "generic";
|
|
27
|
-
} finally {
|
|
28
|
-
d.value = !1;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
}), (e, m) => (l(), k("div", R, [
|
|
32
|
-
p.value !== null ? C(e.$slots, "default", {
|
|
33
|
-
key: 0,
|
|
34
|
-
data: p.value
|
|
35
|
-
}) : d.value ? (l(), k("div", q, r(a(t)("Chargement de l'aperçu {fileType}...", { fileType: s.fileType })), 1)) : v.value ? T.value === "blocked" ? (l(), n(c, { key: 3 }, {
|
|
36
|
-
default: o(() => [
|
|
37
|
-
u(r(a(t)("Ce fichier {fileType} ne peut pas être prévisualisé car il est hébergé sur un site distant qui restreint l'accès (CORS). Téléchargez-le depuis l'onglet Téléchargements.", { fileType: s.fileType })), 1)
|
|
38
|
-
]),
|
|
39
|
-
_: 1
|
|
40
|
-
})) : f.value === "network" ? (l(), n(c, { key: 4 }, {
|
|
41
|
-
default: o(() => [
|
|
42
|
-
u(r(a(t)("Ce fichier est hébergé sur un site externe qui ne permet pas la prévisualisation. Téléchargez-le depuis l'onglet Téléchargements.")), 1)
|
|
43
|
-
]),
|
|
44
|
-
_: 1
|
|
45
|
-
})) : f.value ? (l(), n(c, { key: 5 }, {
|
|
46
|
-
default: o(() => [
|
|
47
|
-
u(r(a(t)("L'aperçu de ce fichier n'a pas pu être chargé. Téléchargez-le depuis l'onglet Téléchargements.")), 1)
|
|
48
|
-
]),
|
|
49
|
-
_: 1
|
|
50
|
-
})) : b("", !0) : (l(), n(c, { key: 2 }, {
|
|
51
|
-
default: o(() => [
|
|
52
|
-
u(r(y.value ? a(t)("Le fichier {fileType} est trop volumineux pour être prévisualisé. Téléchargez-le depuis l'onglet Téléchargements.", { fileType: s.fileType }) : a(t)("La taille du fichier est inconnue, l'aperçu n'est pas disponible. Téléchargez-le depuis l'onglet Téléchargements.")), 1)
|
|
53
|
-
]),
|
|
54
|
-
_: 1
|
|
55
|
-
}))
|
|
56
|
-
]));
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
export {
|
|
60
|
-
V as _
|
|
61
|
-
};
|
|
File without changes
|
|
File without changes
|
|
File without changes
|