@datagouv/components-next 1.0.2-dev.11 → 1.0.2-dev.110
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/{Control-DuZJdKV_.js → Control-ZFh5ta_U.js} +1 -1
- package/dist/{Datafair.client-8haHXl47.js → Datafair.client-rf4T1IkA.js} +1 -1
- package/dist/{Event--kp8kMdJ.js → Event-DSQcW7OF.js} +24 -24
- package/dist/{Image-34hvypZI.js → Image-BijNEG0p.js} +6 -6
- package/dist/JsonPreview.client-dzar6iuh.js +40 -0
- package/dist/{Map-BjUnLyj8.js → Map-BUtPf5GN.js} +756 -756
- package/dist/{MapContainer.client-l6HuXTHR.js → MapContainer.client-D-MoRNhG.js} +37 -38
- package/dist/{OSM-s40W6sQ2.js → OSM-D4MTdBtk.js} +2 -2
- package/dist/{PdfPreview.client-4OueK-2Z.js → PdfPreview.client-DoDYLmJD.js} +822 -850
- package/dist/{Pmtiles.client-4j3VTYkz.js → Pmtiles.client-Dzm01Zfm.js} +1 -1
- package/dist/PreviewWrapper.vue_vue_type_script_setup_true_lang-BRNYswg3.js +61 -0
- package/dist/{ScaleLine-KW-nXqp3.js → ScaleLine-hJQIqcZm.js} +2 -2
- package/dist/{Tile-DbNFNPfU.js → Tile-Dcl7oIVu.js} +35 -35
- package/dist/{TileImage-BsXBxMtq.js → TileImage-BJeHipMX.js} +4 -4
- package/dist/{View-BR92hTWP.js → View-xp_P_OHw.js} +412 -401
- package/dist/XmlPreview.client-cOhwff6P.js +34 -0
- package/dist/{common-PJfpC179.js → common-BjQlan3k.js} +36 -36
- package/dist/components-next.css +6 -6
- package/dist/components-next.js +165 -142
- package/dist/components.css +1 -1
- package/dist/{index-CVTIoZQ0.js → index-NofRBuyf.js} +32886 -27183
- package/dist/main-Iz1ZCL6k.js +73606 -0
- package/dist/{proj-DsetBcW7.js → proj-CsNo9yH1.js} +532 -512
- package/dist/{tilecoord-Db24Px13.js → tilecoord-A0fLnBZr.js} +28 -28
- package/dist/{vue3-xml-viewer.common-CWer_T5-.js → vue3-xml-viewer.common-tVI9uXUz.js} +1 -1
- package/package.json +25 -11
- package/src/chart.ts +5 -0
- package/src/components/ActivityList/ActivityList.vue +3 -2
- package/src/components/Chart/ChartViewer.vue +226 -0
- package/src/components/Chart/ChartViewerWrapper.vue +170 -0
- package/src/components/DataserviceCard.vue +3 -0
- package/src/components/DatasetCard.vue +9 -4
- package/src/components/Form/Listbox.vue +101 -0
- package/src/components/Form/SearchableSelect.vue +2 -1
- package/src/components/InfiniteLoader.vue +53 -0
- package/src/components/ObjectCardHeader.vue +11 -4
- 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/RadioInput.vue +7 -2
- package/src/components/ReadMore.vue +1 -1
- package/src/components/ResourceAccordion/DataStructure.vue +11 -33
- package/src/components/ResourceAccordion/Downloads.vue +160 -0
- package/src/components/ResourceAccordion/JsonPreview.client.vue +23 -104
- package/src/components/ResourceAccordion/MapContainer.client.vue +1 -3
- package/src/components/ResourceAccordion/Metadata.vue +1 -2
- package/src/components/ResourceAccordion/PdfPreview.client.vue +24 -87
- package/src/components/ResourceAccordion/Preview.vue +11 -11
- package/src/components/ResourceAccordion/PreviewWrapper.vue +82 -0
- package/src/components/ResourceAccordion/ResourceAccordion.vue +10 -109
- package/src/components/ResourceAccordion/XmlPreview.client.vue +16 -98
- package/src/components/ResourceExplorer/ResourceExplorer.vue +14 -10
- package/src/components/ResourceExplorer/ResourceExplorerSidebar.vue +2 -2
- package/src/components/ResourceExplorer/ResourceExplorerViewer.vue +46 -147
- package/src/components/ResourceExplorer/ResourceSelector.vue +113 -0
- package/src/components/ReuseCard.vue +12 -4
- package/src/components/Search/GlobalSearch.vue +201 -113
- package/src/components/Search/SearchInput.vue +5 -4
- package/src/components/TabularExplorer/TabularCell.vue +51 -0
- package/src/components/TabularExplorer/TabularCellPopover.vue +170 -0
- package/src/components/TabularExplorer/TabularExplorer.vue +973 -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/useHasTabularData.ts +13 -0
- package/src/composables/useMetrics.ts +1 -1
- package/src/composables/useSearchFilter.ts +118 -0
- package/src/composables/useStableQueryParams.ts +38 -6
- package/src/composables/useTabularProfile.ts +70 -0
- package/src/config.ts +20 -3
- package/src/functions/activities.ts +3 -3
- package/src/functions/api.ts +9 -37
- package/src/functions/api.types.ts +1 -0
- package/src/functions/charts.ts +68 -0
- package/src/functions/datasets.ts +0 -17
- package/src/functions/metrics.ts +6 -4
- package/src/functions/resources.ts +56 -1
- package/src/functions/tabular.ts +60 -0
- package/src/functions/tabularApi.ts +138 -11
- package/src/main.ts +90 -9
- 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 +5 -1
- package/src/types/search.ts +63 -1
- package/src/types/site.ts +5 -3
- package/src/types/ui.ts +2 -0
- package/src/types/users.ts +2 -1
- package/src/types/visualizations.ts +89 -0
- package/assets/swagger-themes/newspaper.css +0 -1670
- package/dist/JsonPreview.client-D53pj9Cw.js +0 -72
- package/dist/Swagger.client-DPBmsH9q.js +0 -4
- package/dist/XmlPreview.client-XElkoA4F.js +0 -64
- package/dist/main-BbT-LUXy.js +0 -105854
- package/src/components/ResourceAccordion/Swagger.client.vue +0 -48
- package/src/functions/pagination.ts +0 -9
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { Component } from 'vue'
|
|
2
|
+
import {
|
|
3
|
+
RiHashtag,
|
|
4
|
+
RiPriceTag3Line,
|
|
5
|
+
RiText,
|
|
6
|
+
RiCalendarLine,
|
|
7
|
+
RiCheckboxLine,
|
|
8
|
+
} from '@remixicon/vue'
|
|
9
|
+
import { useTranslation } from '../composables/useTranslation'
|
|
10
|
+
import type { ColumnFilters, ColumnType } from '../components/TabularExplorer/types'
|
|
11
|
+
|
|
12
|
+
export function hasFilterForColumn(filters: Record<string, ColumnFilters>, column: string): boolean {
|
|
13
|
+
const f = filters[column]
|
|
14
|
+
if (!f) return false
|
|
15
|
+
return !!(f.in?.length || f.exact != null || f.contains || f.null || f.min != null || f.max != null)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function buildTypeConfig(t: (s: string) => string): Record<ColumnType, { icon: Component, label: string }> {
|
|
19
|
+
return {
|
|
20
|
+
number: { icon: RiHashtag, label: t('Nombre') },
|
|
21
|
+
categorical: { icon: RiPriceTag3Line, label: t('Catégoriel') },
|
|
22
|
+
text: { icon: RiText, label: t('Texte') },
|
|
23
|
+
date: { icon: RiCalendarLine, label: t('Date') },
|
|
24
|
+
boolean: { icon: RiCheckboxLine, label: t('Booléen') },
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function useFormatTabular() {
|
|
29
|
+
const { locale } = useTranslation()
|
|
30
|
+
|
|
31
|
+
function formatNumber(value: unknown): string {
|
|
32
|
+
const num = Number(value)
|
|
33
|
+
if (Number.isNaN(num)) return String(value)
|
|
34
|
+
return num.toLocaleString(locale)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function formatCellDate(value: unknown): string {
|
|
38
|
+
if (value == null || value === '') return '–'
|
|
39
|
+
const d = new Date(String(value))
|
|
40
|
+
if (Number.isNaN(d.getTime())) return String(value)
|
|
41
|
+
return new Intl.DateTimeFormat(locale, { day: '2-digit', month: '2-digit', year: 'numeric' }).format(d)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return { formatNumber, formatCellDate }
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const TRUTHY_VALUES = ['true', '1', 'oui', 'yes']
|
|
48
|
+
const FALSY_VALUES = ['false', '0', 'non', 'no']
|
|
49
|
+
|
|
50
|
+
export function isTruthy(value: unknown): boolean {
|
|
51
|
+
if (typeof value === 'boolean') return value
|
|
52
|
+
if (typeof value === 'string') return TRUTHY_VALUES.includes(value.toLowerCase())
|
|
53
|
+
return Boolean(value)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function isFalsy(value: unknown): boolean {
|
|
57
|
+
if (typeof value === 'boolean') return !value
|
|
58
|
+
if (typeof value === 'string') return FALSY_VALUES.includes(value.toLowerCase())
|
|
59
|
+
return !value
|
|
60
|
+
}
|
|
@@ -1,20 +1,147 @@
|
|
|
1
1
|
import { ofetch } from 'ofetch'
|
|
2
2
|
import { useComponentsConfig, type PluginConfig } from '../config'
|
|
3
|
+
import type { GenericFilter } from '../types/visualizations'
|
|
4
|
+
import type { SortConfig } from '../components/TabularExplorer/types'
|
|
3
5
|
|
|
4
|
-
export type SortConfig
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
export type { SortConfig }
|
|
7
|
+
|
|
8
|
+
export type TabularDataResponse = {
|
|
9
|
+
data: Array<Record<string, unknown>>
|
|
10
|
+
links: {
|
|
11
|
+
profile: string
|
|
12
|
+
swagger: string
|
|
13
|
+
next: string
|
|
14
|
+
}
|
|
15
|
+
meta: { total: number }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type TabularAggregateType = 'avg' | 'sum' | 'count' | 'min' | 'max'
|
|
19
|
+
|
|
20
|
+
export type FetchTabularDataOptions = {
|
|
21
|
+
resourceId: string
|
|
22
|
+
page?: number
|
|
23
|
+
pageSize?: number
|
|
24
|
+
columns?: Array<string> | undefined
|
|
25
|
+
sort?: SortConfig
|
|
26
|
+
groupBy?: string | undefined
|
|
27
|
+
aggregation?: {
|
|
28
|
+
column: string
|
|
29
|
+
type: TabularAggregateType
|
|
30
|
+
} | undefined
|
|
31
|
+
filters?: GenericFilter | undefined
|
|
32
|
+
}
|
|
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
|
+
}
|
|
8
75
|
|
|
9
76
|
/**
|
|
10
|
-
* Call Tabular-api to get table content
|
|
77
|
+
* Call Tabular-api to get table content with options object
|
|
11
78
|
*/
|
|
12
|
-
export async function
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
79
|
+
export async function fetchTabularData(config: PluginConfig, options: FetchTabularDataOptions): Promise<TabularDataResponse> {
|
|
80
|
+
const page = options.page ?? 1
|
|
81
|
+
const pageSize = options.pageSize ?? config.tabularApiPageSize ?? 15
|
|
82
|
+
let url = `${config.tabularApiUrl}/api/resources/${options.resourceId}/data/?page=${page}&page_size=${pageSize}`
|
|
83
|
+
if (options.columns) {
|
|
84
|
+
url += `&columns=${options.columns.map(col => encodeURIComponent(col)).join(',')}`
|
|
85
|
+
}
|
|
86
|
+
if (options.sort) {
|
|
87
|
+
url += `&${encodeURIComponent(options.sort.column)}__sort=${encodeURIComponent(options.sort.direction)}`
|
|
16
88
|
}
|
|
17
|
-
|
|
89
|
+
if (options.groupBy && options.aggregation?.type) {
|
|
90
|
+
url += `&${encodeURIComponent(options.groupBy)}__groupby&${encodeURIComponent(options.aggregation.column)}__${encodeURIComponent(options.aggregation.type)}`
|
|
91
|
+
}
|
|
92
|
+
if (options.filters) {
|
|
93
|
+
const filterQuery = buildFilterQuery(options.filters)
|
|
94
|
+
if (filterQuery) {
|
|
95
|
+
url += `&${filterQuery}`
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return await ofetch<TabularDataResponse>(url)
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function buildFilterQuery(filters: GenericFilter): string {
|
|
102
|
+
const params: Array<string> = []
|
|
103
|
+
if ('filters' in filters) {
|
|
104
|
+
for (const filter of filters.filters) {
|
|
105
|
+
if ('filters' in filter) {
|
|
106
|
+
params.push(buildFilterQuery(filter))
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
if (filter.condition === 'is_null') {
|
|
110
|
+
params.push(`${encodeURIComponent(filter.column)}__isnull`)
|
|
111
|
+
}
|
|
112
|
+
else if (filter.condition === 'is_not_null') {
|
|
113
|
+
params.push(`${encodeURIComponent(filter.column)}__isnotnull`)
|
|
114
|
+
}
|
|
115
|
+
else if (filter.value !== null && filter.value !== undefined && filter.value !== '') {
|
|
116
|
+
params.push(`${encodeURIComponent(filter.column)}__${encodeURIComponent(filter.condition)}=${encodeURIComponent(filter.value)}`)
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
const filter = filters
|
|
123
|
+
if (filter.condition === 'is_null') {
|
|
124
|
+
params.push(`${encodeURIComponent(filter.column)}__isnull`)
|
|
125
|
+
}
|
|
126
|
+
else if (filter.condition === 'is_not_null') {
|
|
127
|
+
params.push(`${encodeURIComponent(filter.column)}__isnotnull`)
|
|
128
|
+
}
|
|
129
|
+
else if (filter.value !== null && filter.value !== undefined && filter.value !== '') {
|
|
130
|
+
params.push(`${encodeURIComponent(filter.column)}__${encodeURIComponent(filter.condition)}=${encodeURIComponent(filter.value)}`)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return params.join('&')
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Call Tabular-api to get table content
|
|
138
|
+
*/
|
|
139
|
+
export async function getData(config: PluginConfig, id: string, page: number, sortConfig?: SortConfig | null): Promise<TabularDataResponse> {
|
|
140
|
+
return fetchTabularData(config, {
|
|
141
|
+
resourceId: id,
|
|
142
|
+
page,
|
|
143
|
+
sort: sortConfig ?? undefined,
|
|
144
|
+
})
|
|
18
145
|
}
|
|
19
146
|
|
|
20
147
|
/**
|
|
@@ -22,5 +149,5 @@ export async function getData(config: PluginConfig, id: string, page: number, so
|
|
|
22
149
|
*/
|
|
23
150
|
export function useGetProfile() {
|
|
24
151
|
const config = useComponentsConfig()
|
|
25
|
-
return (id: string) => ofetch(`${config.tabularApiUrl}/api/resources/${id}/profile/`)
|
|
152
|
+
return (id: string) => ofetch<TabularProfileResponse>(`${config.tabularApiUrl}/api/resources/${id}/profile/`)
|
|
26
153
|
}
|
package/src/main.ts
CHANGED
|
@@ -13,7 +13,7 @@ import type { License } from './types/licenses'
|
|
|
13
13
|
import type { Member, MemberRole, NewOrganization, Organization, OrganizationOrSuggest, OrganizationReference, OrganizationSuggest } from './types/organizations'
|
|
14
14
|
import type { Owned, OwnedWithFullObject, OwnedWithId } from './types/owned'
|
|
15
15
|
import type { Comment, Thread } from './types/discussions'
|
|
16
|
-
import type {
|
|
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
18
|
import type { ReuseReference, NewReuse, Reuse, ReuseTopic, ReuseType } from './types/reuses'
|
|
19
19
|
import type { RegisteredSchema, Schema, SchemaDetails, SchemaField, SchemaPath, SchemaPublicationMode, SchemaResponseData, SchemaVersion, ValidataError } from './types/schemas'
|
|
@@ -23,8 +23,11 @@ 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 {
|
|
27
|
-
import {
|
|
26
|
+
import type { Chart, ChartForm, ChartForApi, FilterCondition, Filter, AndFilters, GenericFilter, XAxisType, XAxisSortBy, SortDirection, XAxis, XAxisForm, UnitPosition, YAxis, DataSeriesType, DataSeries, DataSeriesForm } from './types/visualizations'
|
|
27
|
+
import type { GlobalSearchConfig, SearchType, SearchTypeConfig, SortOption, HiddenFilter, BuiltInFilterKey, DatasetSearchConfig, DatasetSearchFilters, DataserviceSearchConfig, DataserviceSearchFilters, ReuseSearchConfig, ReuseSearchFilters, OrganizationSearchConfig, OrganizationSearchFilters, TopicSearchConfig, TopicSearchFilters } from './types/search'
|
|
28
|
+
import { getDefaultDatasetConfig, getDefaultDataserviceConfig, getDefaultReuseConfig, getDefaultOrganizationConfig, getDefaultTopicConfig, getDefaultGlobalSearchConfig, defaultDatasetSortOptions, defaultDataserviceSortOptions, defaultReuseSortOptions, defaultOrganizationSortOptions } from './types/search'
|
|
29
|
+
import { useSearchFilter } from './composables/useSearchFilter'
|
|
30
|
+
import type { UseSearchFilterOptions } from './composables/useSearchFilter'
|
|
28
31
|
|
|
29
32
|
import ActivityList from './components/ActivityList/ActivityList.vue'
|
|
30
33
|
import UserActivityList from './components/ActivityList/UserActivityList.vue'
|
|
@@ -37,6 +40,9 @@ import BrandedButton from './components/BrandedButton.vue'
|
|
|
37
40
|
import CopyButton from './components/CopyButton.vue'
|
|
38
41
|
import DataserviceCard from './components/DataserviceCard.vue'
|
|
39
42
|
import DatasetCard from './components/DatasetCard.vue'
|
|
43
|
+
import DataStructure from './components/ResourceAccordion/DataStructure.vue'
|
|
44
|
+
import Downloads from './components/ResourceAccordion/Downloads.vue'
|
|
45
|
+
import Metadata from './components/ResourceAccordion/Metadata.vue'
|
|
40
46
|
import DescriptionListTerm from './components/DescriptionListTerm.vue'
|
|
41
47
|
import DescriptionListDetails from './components/DescriptionListDetails.vue'
|
|
42
48
|
import DiscussionMessageCard from './components/DiscussionMessageCard.vue'
|
|
@@ -57,6 +63,7 @@ import LoadingBlock from './components/LoadingBlock.vue'
|
|
|
57
63
|
import MarkdownViewer from './components/MarkdownViewer.vue'
|
|
58
64
|
import OrganizationCard from './components/OrganizationCard.vue'
|
|
59
65
|
import OrganizationHorizontalCard from './components/OrganizationHorizontalCard.vue'
|
|
66
|
+
import ObjectCardOwner from './components/ObjectCardOwner.vue'
|
|
60
67
|
import OrganizationLogo from './components/OrganizationLogo.vue'
|
|
61
68
|
import OrganizationNameWithCertificate from './components/OrganizationNameWithCertificate.vue'
|
|
62
69
|
import OwnerType from './components/OwnerType.vue'
|
|
@@ -70,16 +77,16 @@ import PostCard from './components/PostCard.vue'
|
|
|
70
77
|
import ReadMore from './components/ReadMore.vue'
|
|
71
78
|
import ResourceAccordion from './components/ResourceAccordion/ResourceAccordion.vue'
|
|
72
79
|
import ResourceIcon from './components/ResourceAccordion/ResourceIcon.vue'
|
|
80
|
+
import ResourceSelector from './components/ResourceExplorer/ResourceSelector.vue'
|
|
73
81
|
import ResourceExplorer from './components/ResourceExplorer/ResourceExplorer.vue'
|
|
74
82
|
import ResourceExplorerSidebar from './components/ResourceExplorer/ResourceExplorerSidebar.vue'
|
|
75
83
|
import ResourceExplorerViewer from './components/ResourceExplorer/ResourceExplorerViewer.vue'
|
|
76
|
-
import
|
|
84
|
+
import OpenApiViewer from './components/OpenApiViewer/OpenApiViewer.vue'
|
|
77
85
|
import ReuseCard from './components/ReuseCard.vue'
|
|
78
86
|
import ReuseHorizontalCard from './components/ReuseHorizontalCard.vue'
|
|
79
87
|
import ReuseDetails from './components/ReuseDetails.vue'
|
|
80
88
|
import SchemaCard from './components/SchemaCard.vue'
|
|
81
89
|
import SimpleBanner from './components/SimpleBanner.vue'
|
|
82
|
-
import SmallChart from './components/SmallChart.vue'
|
|
83
90
|
import StatBox from './components/StatBox.vue'
|
|
84
91
|
import Tab from './components/Tabs/Tab.vue'
|
|
85
92
|
import TabGroup from './components/Tabs/TabGroup.vue'
|
|
@@ -94,16 +101,24 @@ import GlobalSearch from './components/Search/GlobalSearch.vue'
|
|
|
94
101
|
import SearchInput from './components/Search/SearchInput.vue'
|
|
95
102
|
import SearchableSelect from './components/Form/SearchableSelect.vue'
|
|
96
103
|
import SelectGroup from './components/Form/SelectGroup.vue'
|
|
104
|
+
import Listbox from './components/Form/Listbox.vue'
|
|
105
|
+
import InfiniteLoader from './components/InfiniteLoader.vue'
|
|
106
|
+
import TabularExplorer from './components/TabularExplorer/TabularExplorer.vue'
|
|
97
107
|
import type { UseFetchFunction } from './functions/api.types'
|
|
98
108
|
import { configKey, useComponentsConfig, type PluginConfig } from './config.js'
|
|
109
|
+
import { ofetch } from 'ofetch'
|
|
110
|
+
import { useTranslation } from './composables/useTranslation'
|
|
99
111
|
|
|
100
112
|
export { Toaster, toast } from 'vue-sonner'
|
|
101
113
|
|
|
102
114
|
export * from './composables/useActiveDescendant'
|
|
115
|
+
export * from './composables/useDebouncedRef'
|
|
103
116
|
export * from './composables/useMetrics'
|
|
104
117
|
export * from './composables/useReuseType'
|
|
105
118
|
export * from './composables/useTranslation'
|
|
106
119
|
export * from './composables/useHasTabularData'
|
|
120
|
+
export * from './composables/useResourceCapabilities'
|
|
121
|
+
export * from './composables/useTabularProfile'
|
|
107
122
|
|
|
108
123
|
export * from './functions/activities'
|
|
109
124
|
export * from './functions/datasets'
|
|
@@ -116,17 +131,33 @@ export * from './functions/metrics'
|
|
|
116
131
|
export * from './functions/never'
|
|
117
132
|
export * from './functions/organizations'
|
|
118
133
|
export * from './functions/owned'
|
|
119
|
-
export * from './functions/pagination'
|
|
120
134
|
export * from './functions/resources'
|
|
121
135
|
export * from './functions/reuses'
|
|
122
136
|
export * from './functions/schemas'
|
|
137
|
+
export * from './functions/tabular'
|
|
123
138
|
export * from './functions/users'
|
|
139
|
+
export * from './functions/tabularApi'
|
|
140
|
+
export * from './functions/charts'
|
|
124
141
|
export * from './types/access_types'
|
|
125
142
|
|
|
126
143
|
export type {
|
|
127
144
|
GlobalSearchConfig,
|
|
128
145
|
SearchType,
|
|
146
|
+
SearchTypeConfig,
|
|
129
147
|
SortOption,
|
|
148
|
+
HiddenFilter,
|
|
149
|
+
BuiltInFilterKey,
|
|
150
|
+
DatasetSearchConfig,
|
|
151
|
+
DatasetSearchFilters,
|
|
152
|
+
DataserviceSearchConfig,
|
|
153
|
+
DataserviceSearchFilters,
|
|
154
|
+
ReuseSearchConfig,
|
|
155
|
+
ReuseSearchFilters,
|
|
156
|
+
OrganizationSearchConfig,
|
|
157
|
+
OrganizationSearchFilters,
|
|
158
|
+
TopicSearchConfig,
|
|
159
|
+
TopicSearchFilters,
|
|
160
|
+
UseSearchFilterOptions,
|
|
130
161
|
UseFetchFunction,
|
|
131
162
|
AccessType,
|
|
132
163
|
AccessAudience,
|
|
@@ -168,7 +199,6 @@ export type {
|
|
|
168
199
|
Owned,
|
|
169
200
|
OwnedWithFullObject,
|
|
170
201
|
OwnedWithId,
|
|
171
|
-
Page,
|
|
172
202
|
PageBloc,
|
|
173
203
|
ContentBloc,
|
|
174
204
|
BlocWithTitle,
|
|
@@ -218,6 +248,23 @@ export type {
|
|
|
218
248
|
ValidataError,
|
|
219
249
|
Weight,
|
|
220
250
|
WellType,
|
|
251
|
+
Chart,
|
|
252
|
+
ChartForm,
|
|
253
|
+
ChartForApi,
|
|
254
|
+
FilterCondition,
|
|
255
|
+
Filter,
|
|
256
|
+
AndFilters,
|
|
257
|
+
GenericFilter,
|
|
258
|
+
XAxisType,
|
|
259
|
+
XAxisSortBy,
|
|
260
|
+
SortDirection,
|
|
261
|
+
XAxis,
|
|
262
|
+
XAxisForm,
|
|
263
|
+
UnitPosition,
|
|
264
|
+
YAxis,
|
|
265
|
+
DataSeriesType,
|
|
266
|
+
DataSeries,
|
|
267
|
+
DataSeriesForm,
|
|
221
268
|
}
|
|
222
269
|
|
|
223
270
|
export {
|
|
@@ -225,16 +272,43 @@ export {
|
|
|
225
272
|
getDefaultDataserviceConfig,
|
|
226
273
|
getDefaultReuseConfig,
|
|
227
274
|
getDefaultOrganizationConfig,
|
|
275
|
+
getDefaultTopicConfig,
|
|
228
276
|
getDefaultGlobalSearchConfig,
|
|
229
277
|
defaultDatasetSortOptions,
|
|
230
278
|
defaultDataserviceSortOptions,
|
|
231
279
|
defaultReuseSortOptions,
|
|
232
280
|
defaultOrganizationSortOptions,
|
|
281
|
+
useSearchFilter,
|
|
233
282
|
}
|
|
234
283
|
|
|
235
284
|
// Vue Plugin
|
|
236
285
|
const datagouv: Plugin<PluginConfig> = {
|
|
237
286
|
async install(app: App, options) {
|
|
287
|
+
// Default `$fetch` to an ofetch instance carrying the datagouv API specifics + the consumer's
|
|
288
|
+
// auth hooks, so everything downstream (the default `useFetch`, imperative helpers) can rely on
|
|
289
|
+
// a single configured fetch. A consumer that provides its own `$fetch` keeps full control.
|
|
290
|
+
if (!options.$fetch) {
|
|
291
|
+
options.$fetch = ofetch.create({
|
|
292
|
+
baseURL: options.apiBase,
|
|
293
|
+
onRequest(context) {
|
|
294
|
+
if (options.onRequest) {
|
|
295
|
+
if (Array.isArray(options.onRequest)) options.onRequest.forEach(hook => hook(context))
|
|
296
|
+
else options.onRequest(context)
|
|
297
|
+
}
|
|
298
|
+
context.options.headers.set('Content-Type', 'application/json')
|
|
299
|
+
context.options.headers.set('Accept', 'application/json')
|
|
300
|
+
if (options.devApiKey) context.options.headers.set('X-API-KEY', options.devApiKey)
|
|
301
|
+
const { locale } = useTranslation()
|
|
302
|
+
if (locale) {
|
|
303
|
+
context.options.params ??= {}
|
|
304
|
+
context.options.params['lang'] = locale
|
|
305
|
+
}
|
|
306
|
+
},
|
|
307
|
+
onRequestError: options.onRequestError,
|
|
308
|
+
onResponse: options.onResponse,
|
|
309
|
+
onResponseError: options.onResponseError,
|
|
310
|
+
})
|
|
311
|
+
}
|
|
238
312
|
app.provide(configKey, options)
|
|
239
313
|
if (!options.textClamp) {
|
|
240
314
|
const textClamp = await import('vue3-text-clamp')
|
|
@@ -256,6 +330,9 @@ export {
|
|
|
256
330
|
CopyButton,
|
|
257
331
|
DataserviceCard,
|
|
258
332
|
DatasetCard,
|
|
333
|
+
DataStructure,
|
|
334
|
+
Downloads,
|
|
335
|
+
Metadata,
|
|
259
336
|
DatasetInformationSection,
|
|
260
337
|
DatasetTemporalitySection,
|
|
261
338
|
DatasetSpatialSection,
|
|
@@ -295,15 +372,16 @@ export {
|
|
|
295
372
|
ResourceExplorer,
|
|
296
373
|
ResourceExplorerSidebar,
|
|
297
374
|
ResourceExplorerViewer,
|
|
375
|
+
ObjectCardOwner,
|
|
298
376
|
ResourceIcon,
|
|
377
|
+
ResourceSelector,
|
|
299
378
|
ReuseCard,
|
|
300
379
|
ReuseDetails,
|
|
301
380
|
ReuseHorizontalCard,
|
|
302
381
|
SchemaCard,
|
|
303
382
|
SimpleBanner,
|
|
304
|
-
SmallChart,
|
|
305
383
|
StatBox,
|
|
306
|
-
|
|
384
|
+
OpenApiViewer,
|
|
307
385
|
Tab,
|
|
308
386
|
TabGroup,
|
|
309
387
|
TabList,
|
|
@@ -318,4 +396,7 @@ export {
|
|
|
318
396
|
SearchInput,
|
|
319
397
|
SearchableSelect,
|
|
320
398
|
SelectGroup,
|
|
399
|
+
Listbox,
|
|
400
|
+
InfiniteLoader,
|
|
401
|
+
TabularExplorer,
|
|
321
402
|
}
|
|
@@ -24,6 +24,7 @@ export type BaseDataservice = Owned & WithAccessType & {
|
|
|
24
24
|
license: string | null
|
|
25
25
|
private: boolean
|
|
26
26
|
rate_limiting: string
|
|
27
|
+
rate_limiting_url: string | null
|
|
27
28
|
title: DataserviceReference['title']
|
|
28
29
|
contact_points: Array<ContactPoint>
|
|
29
30
|
}
|
|
@@ -65,6 +66,7 @@ export type Dataservice = Owned & WithAccessType & {
|
|
|
65
66
|
permissions: { edit: boolean, delete: boolean }
|
|
66
67
|
private: boolean
|
|
67
68
|
rate_limiting: string
|
|
69
|
+
rate_limiting_url: string | null
|
|
68
70
|
self_api_url: DataserviceReference['self_api_url']
|
|
69
71
|
self_web_url: DataserviceReference['self_web_url']
|
|
70
72
|
slug: string
|
package/src/types/pages.ts
CHANGED
|
@@ -2,11 +2,6 @@ import type { DatasetV2 } from './datasets'
|
|
|
2
2
|
import type { Dataservice } from './dataservices'
|
|
3
3
|
import type { Reuse } from './reuses'
|
|
4
4
|
|
|
5
|
-
export type Page = {
|
|
6
|
-
id: string
|
|
7
|
-
blocs: Array<PageBloc>
|
|
8
|
-
}
|
|
9
|
-
|
|
10
5
|
export type BlocWithTitle = {
|
|
11
6
|
title: string
|
|
12
7
|
subtitle: string | null
|
package/src/types/posts.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { Dataset } from './datasets'
|
|
2
|
-
import type {
|
|
2
|
+
import type { PageBloc } from './pages'
|
|
3
3
|
import type { Reuse } from './reuses'
|
|
4
4
|
import type { User } from './users'
|
|
5
5
|
|
|
6
6
|
export type Post = {
|
|
7
7
|
body_type: 'markdown' | 'html' | 'blocs'
|
|
8
|
+
blocs: Array<PageBloc>
|
|
8
9
|
content: string
|
|
9
|
-
content_as_page: Page | null
|
|
10
10
|
created_at: string
|
|
11
11
|
credit_to: string
|
|
12
12
|
credit_url: string
|
package/src/types/reports.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { User } from './users'
|
|
2
2
|
|
|
3
3
|
export type ReportSubject = {
|
|
4
|
-
class: 'Discussion' | 'Dataservice' | 'Dataset' | 'Organization' | 'Reuse'
|
|
4
|
+
class: 'Discussion' | 'Dataservice' | 'Dataset' | 'Organization' | 'Reuse' | 'User'
|
|
5
5
|
id: string
|
|
6
6
|
}
|
|
7
7
|
|
|
@@ -16,11 +16,15 @@ export type Report = {
|
|
|
16
16
|
id: string
|
|
17
17
|
by: User | null
|
|
18
18
|
subject: ReportSubject | null
|
|
19
|
+
subject_embed_id: string | null
|
|
19
20
|
reason: ReportReasonValue
|
|
20
21
|
message: string
|
|
21
22
|
reported_at: string
|
|
22
23
|
self_api_url: string
|
|
23
24
|
subject_deleted_at: string | null
|
|
25
|
+
subject_deleted_by: User | null
|
|
26
|
+
subject_label: string | null
|
|
24
27
|
dismissed_at: string | null
|
|
25
28
|
dismissed_by: User | null
|
|
29
|
+
callbacks_count: number
|
|
26
30
|
}
|
package/src/types/search.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
import type { Component } from 'vue'
|
|
1
2
|
import type { PaginatedArray } from './api'
|
|
2
3
|
import type { AccessType } from './access_types'
|
|
4
|
+
import type { Dataset } from './datasets'
|
|
5
|
+
import type { Dataservice } from './dataservices'
|
|
6
|
+
import type { Organization } from './organizations'
|
|
7
|
+
import type { Reuse } from './reuses'
|
|
8
|
+
import type { TopicV2 } from './topics'
|
|
3
9
|
import type {
|
|
4
10
|
CERTIFIED,
|
|
5
11
|
PUBLIC_SERVICE,
|
|
@@ -291,46 +297,86 @@ export type SortOption<Sort extends string> = {
|
|
|
291
297
|
|
|
292
298
|
export type DatasetSearchConfig = {
|
|
293
299
|
class: 'datasets'
|
|
300
|
+
key?: string
|
|
294
301
|
name?: string
|
|
302
|
+
icon?: Component | string
|
|
303
|
+
placeholder?: string | null
|
|
295
304
|
hiddenFilters?: HiddenFilter<DatasetSearchFilters>[]
|
|
296
305
|
basicFilters?: (keyof DatasetSearchFilters)[]
|
|
297
306
|
advancedFilters?: (keyof DatasetSearchFilters)[]
|
|
298
307
|
sortOptions?: SortOption<DatasetSearchSort>[]
|
|
308
|
+
defaultSort?: DatasetSearchSort
|
|
299
309
|
}
|
|
300
310
|
|
|
301
311
|
export type DataserviceSearchConfig = {
|
|
302
312
|
class: 'dataservices'
|
|
313
|
+
key?: string
|
|
303
314
|
name?: string
|
|
315
|
+
icon?: Component | string
|
|
316
|
+
placeholder?: string | null
|
|
304
317
|
hiddenFilters?: HiddenFilter<DataserviceSearchFilters>[]
|
|
305
318
|
basicFilters?: (keyof DataserviceSearchFilters)[]
|
|
306
319
|
advancedFilters?: (keyof DataserviceSearchFilters)[]
|
|
307
320
|
sortOptions?: SortOption<DataserviceSearchSort>[]
|
|
321
|
+
defaultSort?: DataserviceSearchSort
|
|
308
322
|
}
|
|
309
323
|
|
|
310
324
|
export type ReuseSearchConfig = {
|
|
311
325
|
class: 'reuses'
|
|
326
|
+
key?: string
|
|
312
327
|
name?: string
|
|
328
|
+
icon?: Component | string
|
|
329
|
+
placeholder?: string | null
|
|
313
330
|
hiddenFilters?: HiddenFilter<ReuseSearchFilters>[]
|
|
314
331
|
basicFilters?: (keyof ReuseSearchFilters)[]
|
|
315
332
|
advancedFilters?: (keyof ReuseSearchFilters)[]
|
|
316
333
|
sortOptions?: SortOption<ReuseSearchSort>[]
|
|
334
|
+
defaultSort?: ReuseSearchSort
|
|
317
335
|
}
|
|
318
336
|
|
|
319
337
|
export type OrganizationSearchConfig = {
|
|
320
338
|
class: 'organizations'
|
|
339
|
+
key?: string
|
|
321
340
|
name?: string
|
|
341
|
+
icon?: Component | string
|
|
342
|
+
placeholder?: string | null
|
|
322
343
|
hiddenFilters?: HiddenFilter<OrganizationSearchFilters>[]
|
|
323
344
|
basicFilters?: (keyof OrganizationSearchFilters)[]
|
|
324
345
|
advancedFilters?: (keyof OrganizationSearchFilters)[]
|
|
325
346
|
sortOptions?: SortOption<OrganizationSearchSort>[]
|
|
347
|
+
defaultSort?: OrganizationSearchSort
|
|
326
348
|
}
|
|
327
349
|
|
|
328
|
-
export type
|
|
350
|
+
export type TopicSearchConfig = {
|
|
351
|
+
class: 'topics'
|
|
352
|
+
key?: string
|
|
353
|
+
name?: string
|
|
354
|
+
icon?: Component | string
|
|
355
|
+
placeholder?: string | null
|
|
356
|
+
hiddenFilters?: HiddenFilter<TopicSearchFilters>[]
|
|
357
|
+
basicFilters?: (keyof TopicSearchFilters)[]
|
|
358
|
+
advancedFilters?: (keyof TopicSearchFilters)[]
|
|
359
|
+
sortOptions?: SortOption<TopicSearchSort>[]
|
|
360
|
+
defaultSort?: TopicSearchSort
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export type SearchTypeConfig = DatasetSearchConfig | DataserviceSearchConfig | ReuseSearchConfig | OrganizationSearchConfig | TopicSearchConfig
|
|
364
|
+
|
|
365
|
+
export type BuiltInFilterKey = keyof DatasetSearchFilters | keyof DataserviceSearchFilters | keyof ReuseSearchFilters | keyof OrganizationSearchFilters | keyof TopicSearchFilters
|
|
329
366
|
|
|
330
367
|
export type SearchType = SearchTypeConfig['class']
|
|
331
368
|
|
|
332
369
|
export type GlobalSearchConfig = SearchTypeConfig[]
|
|
333
370
|
|
|
371
|
+
// Maps each search class to its concrete response shape.
|
|
372
|
+
export type SearchResponseByClass = {
|
|
373
|
+
datasets: DatasetSearchResponse<Dataset>
|
|
374
|
+
dataservices: DataserviceSearchResponse<Dataservice>
|
|
375
|
+
reuses: ReuseSearchResponse<Reuse>
|
|
376
|
+
organizations: OrganizationSearchResponse<Organization>
|
|
377
|
+
topics: TopicSearchResponse<TopicV2>
|
|
378
|
+
}
|
|
379
|
+
|
|
334
380
|
// Helper functions for default configs
|
|
335
381
|
|
|
336
382
|
export const defaultDatasetSortOptions: SortOption<DatasetSearchSort>[] = [
|
|
@@ -397,11 +443,27 @@ export function getDefaultOrganizationConfig(overrides?: Partial<Omit<Organizati
|
|
|
397
443
|
}
|
|
398
444
|
}
|
|
399
445
|
|
|
446
|
+
export const defaultTopicSortOptions: SortOption<TopicSearchSort>[] = [
|
|
447
|
+
{ value: '-created', label: 'Date de création' },
|
|
448
|
+
{ value: '-last_modified', label: 'Dernière mise à jour' },
|
|
449
|
+
]
|
|
450
|
+
|
|
451
|
+
export function getDefaultTopicConfig(overrides?: Partial<Omit<TopicSearchConfig, 'class'>>): TopicSearchConfig {
|
|
452
|
+
return {
|
|
453
|
+
class: 'topics',
|
|
454
|
+
basicFilters: ['last_update_range', 'producer_type'],
|
|
455
|
+
advancedFilters: ['organization', 'tag'],
|
|
456
|
+
sortOptions: defaultTopicSortOptions,
|
|
457
|
+
...overrides,
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
400
461
|
export function getDefaultGlobalSearchConfig(): GlobalSearchConfig {
|
|
401
462
|
return [
|
|
402
463
|
getDefaultDatasetConfig(),
|
|
403
464
|
getDefaultDataserviceConfig(),
|
|
404
465
|
getDefaultReuseConfig(),
|
|
405
466
|
getDefaultOrganizationConfig(),
|
|
467
|
+
getDefaultTopicConfig(),
|
|
406
468
|
]
|
|
407
469
|
}
|
package/src/types/site.ts
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import type { PageBloc } from './pages'
|
|
2
|
+
|
|
1
3
|
export type Site = {
|
|
2
4
|
id: string
|
|
3
5
|
title: string
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
datasets_blocs: Array<PageBloc>
|
|
7
|
+
reuses_blocs: Array<PageBloc>
|
|
8
|
+
dataservices_blocs: Array<PageBloc>
|
|
7
9
|
version: string
|
|
8
10
|
metrics: {
|
|
9
11
|
'dataservices': number
|