@datagouv/components-next 1.0.2-dev.163 → 1.0.2-dev.164
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-DXPU1V24.js → Datafair.client-B-OG5WtK.js} +1 -1
- package/dist/ImagePreview.client-D0c-ifUi.js +36 -0
- package/dist/{JsonPreview.client-D1SnGfWG.js → JsonPreview.client-Dwh9sW9M.js} +2 -2
- package/dist/{MapContainer.client-DlsaEVGx.js → MapContainer.client-C2AZ7sOB.js} +2 -2
- package/dist/{PdfPreview.client-C9OrLR0z.js → PdfPreview.client-8NzNfW8b.js} +2 -2
- package/dist/{Pmtiles.client-CyylWfTy.js → Pmtiles.client-BFH4rTB7.js} +5842 -5660
- package/dist/{PreviewWrapper.vue_vue_type_script_setup_true_lang-CtXZOHXI.js → PreviewWrapper.vue_vue_type_script_setup_true_lang-BOgE441d.js} +7 -10
- package/dist/{XmlPreview.client-DoX7RurH.js → XmlPreview.client-DMOUO508.js} +3 -3
- package/dist/components-next.css +1 -1
- package/dist/components-next.js +179 -171
- package/dist/components.css +1 -1
- package/dist/{index-Br1sa7wQ.js → index-C9obT9DJ.js} +4392 -4293
- package/dist/{leaflet-src-DWG7tmpQ.js → leaflet-src-B4AZU0vr.js} +1 -1
- package/dist/{main-BU6kP4dE.js → main-DNoYWfit.js} +16159 -15631
- package/dist/{vue3-xml-viewer.common-Cpui-Yi9.js → vue3-xml-viewer.common-Cp7Cu5ME.js} +1 -1
- package/package.json +4 -5
- package/src/components/Chart/ChartViewer.vue +103 -10
- package/src/components/Chart/ChartViewerWrapper.vue +8 -0
- package/src/components/DataserviceCard.vue +6 -0
- package/src/components/DataserviceQuality.vue +82 -0
- package/src/components/DataserviceQualityInline.vue +31 -0
- package/src/components/DataserviceQualityTooltipContent.vue +79 -0
- package/src/components/DatasetQuality.vue +11 -11
- package/src/components/DatasetQualityInline.vue +2 -2
- package/src/components/DatasetQualityTooltipContent.vue +1 -1
- package/src/components/ResourceAccordion/ImagePreview.client.vue +48 -0
- package/src/components/ResourceAccordion/ResourceAccordion.vue +8 -3
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +15 -1
- package/src/components/ReuseCard.vue +2 -2
- package/src/components/ReuseDetails.vue +2 -2
- package/src/components/ReuseHorizontalCard.vue +2 -2
- package/src/components/Search/GlobalSearch.vue +2 -2
- package/src/components/TabularExplorer/TabularCell.vue +5 -4
- package/src/components/TabularExplorer/TabularCellPopover.vue +1 -1
- package/src/components/TabularExplorer/TabularExplorer.vue +168 -49
- package/src/components/TabularExplorer/TabularFilterContent.vue +27 -10
- package/src/components/TabularExplorer/TabularFilterPopover.vue +1 -0
- package/src/components/TabularExplorer/types.ts +3 -3
- package/src/composables/useHasTabularData.ts +2 -1
- package/src/composables/useResourceCapabilities.ts +27 -14
- package/src/config.ts +1 -0
- package/src/functions/charts.ts +23 -3
- package/src/functions/resources.ts +56 -0
- package/src/functions/tabular.ts +44 -1
- package/src/main.ts +15 -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 +1 -1
- /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
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { computed,
|
|
1
|
+
import { computed, type MaybeRefOrGetter, toValue } from 'vue'
|
|
2
2
|
import { useComponentsConfig } from '../config'
|
|
3
|
-
import { useTranslation } from './useTranslation'
|
|
4
|
-
import { useHasTabularData } from './useHasTabularData'
|
|
5
|
-
import { detectOgcService } from '../functions/resources'
|
|
6
3
|
import { isOrganizationCertified } from '../functions/organizations'
|
|
7
|
-
import type { Resource, WfsMetadata } from '../types/resources'
|
|
8
|
-
import type { Dataset, DatasetV2 } from '../types/datasets'
|
|
9
4
|
import { getWfsExportFormats } from '../functions/resourceCapabilities'
|
|
5
|
+
import { detectOgcService, getParsingErrorMessage, getParsingErrorStep, isImagePreviewFormat } from '../functions/resources'
|
|
6
|
+
import type { Dataset, DatasetV2 } from '../types/datasets'
|
|
7
|
+
import type { Resource, WfsMetadata } from '../types/resources'
|
|
8
|
+
import { useHasTabularData } from './useHasTabularData'
|
|
9
|
+
import { useTranslation } from './useTranslation'
|
|
10
10
|
|
|
11
11
|
const GENERATED_FORMATS = ['parquet', 'pmtiles', 'geojson']
|
|
12
12
|
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']
|
|
@@ -21,7 +21,7 @@ export function useResourceCapabilities(
|
|
|
21
21
|
|
|
22
22
|
const hasPreview = computed(() => {
|
|
23
23
|
const format = toValue(resource).format?.toLowerCase()
|
|
24
|
-
return format === 'json' || format === 'pdf' || format === 'xml'
|
|
24
|
+
return format === 'json' || format === 'pdf' || format === 'xml' || isImagePreviewFormat(format)
|
|
25
25
|
})
|
|
26
26
|
|
|
27
27
|
const hasTabularData = computed(() => {
|
|
@@ -49,6 +49,11 @@ export function useResourceCapabilities(
|
|
|
49
49
|
const ogcService = computed(() => detectOgcService(toValue(resource)))
|
|
50
50
|
const ogcWms = computed(() => ogcService.value === 'wms')
|
|
51
51
|
|
|
52
|
+
// The map is built from a pmtiles export; when that export fails we still want
|
|
53
|
+
// to show the Carte tab, but with the reason it could not be generated.
|
|
54
|
+
const hasPmtilesError = computed(() => getParsingErrorStep(toValue(resource)) === 'pmtiles_export')
|
|
55
|
+
const pmtilesError = computed(() => hasPmtilesError.value ? getParsingErrorMessage(toValue(resource)) : null)
|
|
56
|
+
|
|
52
57
|
const generatedFormats = computed(() => {
|
|
53
58
|
const r = toValue(resource)
|
|
54
59
|
const formats = GENERATED_FORMATS
|
|
@@ -85,21 +90,27 @@ export function useResourceCapabilities(
|
|
|
85
90
|
const r = toValue(resource)
|
|
86
91
|
const options = []
|
|
87
92
|
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
const dataTab = { key: 'data', label: hasTabularData.value ? t('Données') : t('Aperçu') }
|
|
94
|
+
const mapTab = { key: 'map', label: t('Carte') }
|
|
95
|
+
const hasMap = hasPmtiles.value || ogcWms.value
|
|
96
|
+
|
|
97
|
+
// The map is the most visual preview: when it is available, show it first.
|
|
98
|
+
// When its generation failed, keep the data preview first and surface the
|
|
99
|
+
// Carte tab (with its error) right after.
|
|
100
|
+
if (hasMap) {
|
|
101
|
+
options.push(mapTab, dataTab)
|
|
102
|
+
}
|
|
103
|
+
else if (hasPmtilesError.value) {
|
|
104
|
+
options.push(dataTab, mapTab)
|
|
90
105
|
}
|
|
91
106
|
else {
|
|
92
|
-
options.push(
|
|
107
|
+
options.push(dataTab)
|
|
93
108
|
}
|
|
94
109
|
|
|
95
110
|
if (hasTabularData.value) {
|
|
96
111
|
options.push({ key: 'data-structure', label: t('Structure des données') })
|
|
97
112
|
}
|
|
98
113
|
|
|
99
|
-
if (hasPmtiles.value || ogcWms.value) {
|
|
100
|
-
options.push({ key: 'map', label: t('Carte') })
|
|
101
|
-
}
|
|
102
|
-
|
|
103
114
|
if (r.description) {
|
|
104
115
|
options.push({ key: 'description', label: t('Description') })
|
|
105
116
|
}
|
|
@@ -118,6 +129,8 @@ export function useResourceCapabilities(
|
|
|
118
129
|
hasPreview,
|
|
119
130
|
hasTabularData,
|
|
120
131
|
hasPmtiles,
|
|
132
|
+
hasPmtilesError,
|
|
133
|
+
pmtilesError,
|
|
121
134
|
hasDatafairPreview,
|
|
122
135
|
hasOpenAPIPreview,
|
|
123
136
|
ogcService,
|
package/src/config.ts
CHANGED
|
@@ -12,6 +12,7 @@ export type PluginConfig = {
|
|
|
12
12
|
datasetQualityGuideUrl?: string
|
|
13
13
|
maxJsonPreviewCharSize?: number // Maximum size of JSON to preview in characters. JSON preview module is partly collapsed by default so we can have a preview for large files.
|
|
14
14
|
maxPdfPreviewByteSize?: number // Maximum size of PDF to preview in bytes
|
|
15
|
+
maxImagePreviewByteSize?: number // Maximum size of image to preview in bytes
|
|
15
16
|
maxXmlPreviewCharSize?: number // Maximum size of XML to preview in characters. XML preview module can NOT be collapsed by default so we should not have a preview for large files.
|
|
16
17
|
pmtilesViewerBaseUrl?: string | null // Base URL of a pmtiles viewer (ex: https://pmtiles.io/#url=)
|
|
17
18
|
metricsApiUrl?: string
|
package/src/functions/charts.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Chart, ChartForm, ChartForApi, Filter, ColumnDefinition } from '../types/visualizations'
|
|
2
|
-
import type { TabularProfile } from '../components/TabularExplorer/types'
|
|
2
|
+
import type { ColumnType, TabularProfile } from '../components/TabularExplorer/types'
|
|
3
3
|
import { resolveColumnType } from './tabular'
|
|
4
4
|
|
|
5
5
|
export function toChartForm(chart: Chart) {
|
|
@@ -73,7 +73,27 @@ export function buildColumnsFromProfile(profile: { profile: TabularProfile }): A
|
|
|
73
73
|
return profile.profile.header.map((name) => {
|
|
74
74
|
const colInfo = profile.profile.columns[name]
|
|
75
75
|
const isCategorical = profile.profile.categorical.includes(name)
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
// The chart stack only branches on 'number' and 'date' (continuous axis,
|
|
77
|
+
// aggregatable series, time formatting): it has no notion of a year column,
|
|
78
|
+
// and on an axis a year is a number.
|
|
79
|
+
const resolvedType = resolveColumnType(colInfo ?? { python_type: 'unknown', format: undefined }, isCategorical)
|
|
80
|
+
const colType = resolvedType === 'year' ? 'number' : resolvedType
|
|
81
|
+
const colProfile = profile.profile.profile[name]
|
|
82
|
+
return {
|
|
83
|
+
name,
|
|
84
|
+
type: colType,
|
|
85
|
+
min: normalizeProfileNumber(colProfile?.min, colType),
|
|
86
|
+
max: normalizeProfileNumber(colProfile?.max, colType),
|
|
87
|
+
}
|
|
78
88
|
})
|
|
79
89
|
}
|
|
90
|
+
|
|
91
|
+
function normalizeProfileNumber(value: number | string | undefined, type: ColumnType): number | undefined {
|
|
92
|
+
if (value === undefined || value === null) return undefined
|
|
93
|
+
if (type === 'date' && typeof value === 'string') {
|
|
94
|
+
const timestamp = new Date(value).getTime()
|
|
95
|
+
return Number.isNaN(timestamp) ? undefined : timestamp
|
|
96
|
+
}
|
|
97
|
+
const parsed = Number(value)
|
|
98
|
+
return Number.isNaN(parsed) ? undefined : parsed
|
|
99
|
+
}
|
|
@@ -105,14 +105,29 @@ export const getResourceLabel = (type: ResourceType, count?: number) => {
|
|
|
105
105
|
}
|
|
106
106
|
return t('Fichiers principaux')
|
|
107
107
|
case 'documentation':
|
|
108
|
+
if (typeof count === 'number') {
|
|
109
|
+
return t('Aucun fichier de documentation | 1 fichier de documentation | {n} fichiers de documentation', count)
|
|
110
|
+
}
|
|
108
111
|
return t('Documentation')
|
|
109
112
|
case 'update':
|
|
113
|
+
if (typeof count === 'number') {
|
|
114
|
+
return t('Aucune mise à jour | 1 mise à jour | {n} mises à jour', count)
|
|
115
|
+
}
|
|
110
116
|
return t('Mise à jour')
|
|
111
117
|
case 'api':
|
|
118
|
+
if (typeof count === 'number') {
|
|
119
|
+
return t('Aucune API | 1 API | {n} API', count)
|
|
120
|
+
}
|
|
112
121
|
return t('API')
|
|
113
122
|
case 'code':
|
|
123
|
+
if (typeof count === 'number') {
|
|
124
|
+
return t('Aucun fichier de code source | 1 fichier de code source | {n} fichiers de code source', count)
|
|
125
|
+
}
|
|
114
126
|
return t('Code source')
|
|
115
127
|
case 'other':
|
|
128
|
+
if (typeof count === 'number') {
|
|
129
|
+
return t('Aucun autre fichier | 1 autre fichier | {n} autres fichiers', count)
|
|
130
|
+
}
|
|
116
131
|
return t('Autre')
|
|
117
132
|
}
|
|
118
133
|
}
|
|
@@ -152,6 +167,47 @@ export function getResourceFilesize(resource: Resource): null | number {
|
|
|
152
167
|
return null
|
|
153
168
|
}
|
|
154
169
|
|
|
170
|
+
const IMAGE_PREVIEW_FORMATS = ['png', 'jpg', 'jpeg', 'jpe', 'gif', 'webp'] as const
|
|
171
|
+
|
|
172
|
+
export function isImagePreviewFormat(format: string | undefined | null): boolean {
|
|
173
|
+
if (!format) return false
|
|
174
|
+
return IMAGE_PREVIEW_FORMATS.includes(format.toLowerCase() as typeof IMAGE_PREVIEW_FORMATS[number])
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Parsing errors are stored as `<step>:<message>`, where `<step>` names the
|
|
178
|
+
// analysis step that failed (e.g. `pmtiles_export`, `geojson_export`).
|
|
179
|
+
|
|
180
|
+
/** The analysis step that failed, or null when there is no parsing error. */
|
|
181
|
+
export function getParsingErrorStep(resource: Resource): string | null {
|
|
182
|
+
const error = resource.extras['analysis:parsing:error']
|
|
183
|
+
if (typeof error !== 'string' || !error) return null
|
|
184
|
+
const [step] = error.split(':', 1)
|
|
185
|
+
return step ?? null
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** The parsing error message without its `<step>:` prefix, or null when there is none. */
|
|
189
|
+
export function getParsingErrorMessage(resource: Resource): string | null {
|
|
190
|
+
const error = resource.extras['analysis:parsing:error']
|
|
191
|
+
if (typeof error !== 'string' || !error) return null
|
|
192
|
+
const colon = error.indexOf(':')
|
|
193
|
+
return colon === -1 ? error : error.slice(colon + 1)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Geo/format export steps run *after* the tabular table has been built, so a
|
|
197
|
+
// failure here (e.g. a huge geometry timing out the pmtiles export) leaves the
|
|
198
|
+
// tabular data fully usable and must not disable the tabular explorer.
|
|
199
|
+
const NON_TABULAR_PARSING_ERROR_STEPS = ['pmtiles_export', 'geojson_export']
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Whether the resource's parsing error prevents reading its tabular data.
|
|
203
|
+
* Only errors from the tabular parsing itself are fatal; downstream geo/format
|
|
204
|
+
* export failures are not.
|
|
205
|
+
*/
|
|
206
|
+
export function hasTabularParsingError(resource: Resource): boolean {
|
|
207
|
+
const step = getParsingErrorStep(resource)
|
|
208
|
+
return step !== null && !NON_TABULAR_PARSING_ERROR_STEPS.includes(step)
|
|
209
|
+
}
|
|
210
|
+
|
|
155
211
|
type CorsStatus = 'allowed' | 'blocked' | 'unknown'
|
|
156
212
|
|
|
157
213
|
export const getResourceCorsStatus = (resource: Resource): CorsStatus => {
|
package/src/functions/tabular.ts
CHANGED
|
@@ -42,12 +42,13 @@ export function buildTypeConfig(t: TranslationFunction): Record<ColumnType, Type
|
|
|
42
42
|
text: { icon: RiText, label: t('Texte') },
|
|
43
43
|
date: { icon: RiCalendarLine, label: t('Date') },
|
|
44
44
|
boolean: { icon: RiCheckboxLine, label: t('Booléen') },
|
|
45
|
+
year: { icon: RiCalendarLine, label: t('Année') },
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
export function resolveColumnType(colInfo: { python_type: string, format?: string }, isCategorical: boolean): ColumnType {
|
|
50
|
+
if (colInfo.format === 'year') return 'year'
|
|
49
51
|
if (['int', 'float'].includes(colInfo.python_type)) return 'number'
|
|
50
|
-
if (colInfo.format === 'year') return 'date'
|
|
51
52
|
if (['date', 'datetime'].includes(colInfo.python_type)) return 'date'
|
|
52
53
|
if (colInfo.python_type === 'bool') return 'boolean'
|
|
53
54
|
if (isCategorical) return 'categorical'
|
|
@@ -158,6 +159,48 @@ export function useFormatTabular() {
|
|
|
158
159
|
const TRUTHY_VALUES = ['true', '1', 'oui', 'yes']
|
|
159
160
|
const FALSY_VALUES = ['false', '0', 'non', 'no']
|
|
160
161
|
|
|
162
|
+
// `encodeURIComponent` leaves `.`, `(` and `)` as-is, but they are the operator
|
|
163
|
+
// separator and the delimiters of the API's `or(...)` grammar: a search value
|
|
164
|
+
// containing one makes the parser reject the whole query with a 400. Wrapping
|
|
165
|
+
// the value in double quotes (as the API README suggests) does not work here —
|
|
166
|
+
// the API keeps them as part of the searched string and returns no result. It
|
|
167
|
+
// does percent-decode the value after parsing, so encoding them is enough.
|
|
168
|
+
function encodeConditionValue(value: string): string {
|
|
169
|
+
return encodeURIComponent(value)
|
|
170
|
+
.replace(/\./g, '%2E')
|
|
171
|
+
.replace(/\(/g, '%28')
|
|
172
|
+
.replace(/\)/g, '%29')
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// A decimal literal, not `Number()`: the API compares against a number column,
|
|
176
|
+
// and it answers an error for the whole `or(...)` when it is handed something it
|
|
177
|
+
// cannot parse as one — which `Number()` happily accepts (`0x10`, `1e5`, ` `).
|
|
178
|
+
const NUMBER_LITERAL_RE = /^-?\d+(\.\d+)?$/
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Builds the OR conditions for global search across all columns.
|
|
182
|
+
* Text and categorical columns get a `__contains` filter; number columns
|
|
183
|
+
* get a `__exact` filter only when the search value is numeric.
|
|
184
|
+
* Year, date and boolean columns are excluded.
|
|
185
|
+
*/
|
|
186
|
+
export function buildGlobalSearchConditions(
|
|
187
|
+
allColumns: string[],
|
|
188
|
+
getColumnType: (col: string) => ColumnType,
|
|
189
|
+
searchValue: string,
|
|
190
|
+
): string[] {
|
|
191
|
+
const conditions: string[] = []
|
|
192
|
+
for (const col of allColumns) {
|
|
193
|
+
const type = getColumnType(col)
|
|
194
|
+
if (type === 'text' || type === 'categorical') {
|
|
195
|
+
conditions.push(col + '__contains.' + encodeConditionValue(searchValue))
|
|
196
|
+
}
|
|
197
|
+
else if (type === 'number' && NUMBER_LITERAL_RE.test(searchValue)) {
|
|
198
|
+
conditions.push(col + '__exact.' + encodeConditionValue(searchValue))
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return conditions
|
|
202
|
+
}
|
|
203
|
+
|
|
161
204
|
export function isTruthy(value: unknown): boolean {
|
|
162
205
|
if (typeof value === 'boolean') return value
|
|
163
206
|
if (typeof value === 'string') return TRUTHY_VALUES.includes(value.toLowerCase())
|
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'
|
|
@@ -24,7 +24,7 @@ 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
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 { ColumnType } from './components/TabularExplorer/types'
|
|
27
|
+
import type { ColumnFilters, ColumnType, TabularRow } from './components/TabularExplorer/types'
|
|
28
28
|
import type { GlobalSearchConfig, SearchType, SearchTypeConfig, SortOption, HiddenFilter, BuiltInFilterKey, DatasetSearchConfig, DatasetSearchFilters, DataserviceSearchConfig, DataserviceSearchFilters, ReuseSearchConfig, ReuseSearchFilters, OrganizationSearchConfig, OrganizationSearchFilters, TopicSearchConfig, TopicSearchFilters } from './types/search'
|
|
29
29
|
import { getDefaultDatasetConfig, getDefaultDataserviceConfig, getDefaultReuseConfig, getDefaultOrganizationConfig, getDefaultTopicConfig, getDefaultGlobalSearchConfig, defaultDatasetSortOptions, defaultDataserviceSortOptions, defaultReuseSortOptions, defaultOrganizationSortOptions } from './types/search'
|
|
30
30
|
import { useSearchFilter } from './composables/useSearchFilter'
|
|
@@ -40,6 +40,9 @@ import BannerAction from './components/BannerAction.vue'
|
|
|
40
40
|
import BrandedButton from './components/BrandedButton.vue'
|
|
41
41
|
import CopyButton from './components/CopyButton.vue'
|
|
42
42
|
import DataserviceCard from './components/DataserviceCard.vue'
|
|
43
|
+
import DataserviceQuality from './components/DataserviceQuality.vue'
|
|
44
|
+
import DataserviceQualityInline from './components/DataserviceQualityInline.vue'
|
|
45
|
+
import DataserviceQualityTooltipContent from './components/DataserviceQualityTooltipContent.vue'
|
|
43
46
|
import DatasetCard from './components/DatasetCard.vue'
|
|
44
47
|
import DataStructure from './components/ResourceAccordion/DataStructure.vue'
|
|
45
48
|
import Downloads from './components/ResourceAccordion/Downloads.vue'
|
|
@@ -54,8 +57,8 @@ import LicenseBadge from './components/LicenseBadge.vue'
|
|
|
54
57
|
import Tag from './components/Tag.vue'
|
|
55
58
|
import DatasetQuality from './components/DatasetQuality.vue'
|
|
56
59
|
import DatasetQualityInline from './components/DatasetQualityInline.vue'
|
|
57
|
-
import
|
|
58
|
-
import
|
|
60
|
+
import QualityItem from './components/QualityItem.vue'
|
|
61
|
+
import QualityScore from './components/QualityScore.vue'
|
|
59
62
|
import ProgressBar from './components/ProgressBar.vue'
|
|
60
63
|
import DatasetQualityTooltipContent from './components/DatasetQualityTooltipContent.vue'
|
|
61
64
|
import ExtraAccordion from './components/ExtraAccordion.vue'
|
|
@@ -228,6 +231,7 @@ export type {
|
|
|
228
231
|
ResourceType,
|
|
229
232
|
ReuseReference,
|
|
230
233
|
Reuse,
|
|
234
|
+
ReuseV2,
|
|
231
235
|
ReuseTopic,
|
|
232
236
|
ReuseType,
|
|
233
237
|
Schema,
|
|
@@ -254,8 +258,10 @@ export type {
|
|
|
254
258
|
ChartForApi,
|
|
255
259
|
CombinedSort,
|
|
256
260
|
ColumnDefinition,
|
|
261
|
+
ColumnFilters,
|
|
257
262
|
ColumnType,
|
|
258
263
|
ColumnsDefinition,
|
|
264
|
+
TabularRow,
|
|
259
265
|
FilterCondition,
|
|
260
266
|
Filter,
|
|
261
267
|
AndFilters,
|
|
@@ -334,6 +340,9 @@ export {
|
|
|
334
340
|
BrandedButton,
|
|
335
341
|
CopyButton,
|
|
336
342
|
DataserviceCard,
|
|
343
|
+
DataserviceQuality,
|
|
344
|
+
DataserviceQualityInline,
|
|
345
|
+
DataserviceQualityTooltipContent,
|
|
337
346
|
DatasetCard,
|
|
338
347
|
DataStructure,
|
|
339
348
|
Downloads,
|
|
@@ -348,8 +357,8 @@ export {
|
|
|
348
357
|
DiscussionMessageCard,
|
|
349
358
|
DatasetQuality,
|
|
350
359
|
DatasetQualityInline,
|
|
351
|
-
|
|
352
|
-
|
|
360
|
+
QualityItem,
|
|
361
|
+
QualityScore,
|
|
353
362
|
DatasetQualityTooltipContent,
|
|
354
363
|
DateRangeDetails,
|
|
355
364
|
ExtraAccordion,
|
|
@@ -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
|
}
|
|
@@ -89,5 +89,5 @@ export type ChartForm = Omit<ChartForApi, 'x_axis' | 'series' | 'owner' | 'organ
|
|
|
89
89
|
filter: GenericFilter | null
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
-
export type ColumnDefinition = { name: string, type: ColumnType }
|
|
92
|
+
export type ColumnDefinition = { name: string, type: ColumnType, min?: number, max?: number }
|
|
93
93
|
export type ColumnsDefinition = Record<string, Array<ColumnDefinition>>
|
|
File without changes
|
|
File without changes
|
|
File without changes
|