Skip to content

Commit b6cd5ad

Browse files
author
Hofstetter Benjamin
committed
Update dcat-ap-ch adapters
1 parent a508ffd commit b6cd5ad

File tree

5 files changed

+263
-62
lines changed

5 files changed

+263
-62
lines changed

opendata.swiss/ui/app/components/dataset-detail/model/dcat-ap-ch-v2-dataset-adapter.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -215,9 +215,6 @@ export class DcatApChV2DatasetAdapter {
215215
return this.#dataset.getOdsAccrualPeriodicity;
216216
}
217217

218-
219-
220-
221218
get propertyTable() {
222219
const rootNode = this.#dataset.getPropertyTable;
223220
if (!rootNode) {

opendata.swiss/ui/app/components/dataset-detail/model/dcat-ap-ch-v2-distribution-adapter.ts

Lines changed: 144 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import type { TableEntry } from './table-entry';
77
type EnhancedDistribution = Dataset['getDistributions'][number]
88

99

10-
export class DcatApChV2DistributionAdapter implements EnhancedDistribution {
10+
export class DcatApChV2DistributionAdapter {
1111
#distribution: EnhancedDistribution | undefined;
1212
#dataset: DcatApChV2DatasetAdapter;
1313

1414
constructor(d: EnhancedDistribution, dataset: DcatApChV2DatasetAdapter) {
1515
this.#distribution = d;
1616
this.#dataset = dataset;
17+
18+
console.log('id', this.#distribution?.id);
1719
}
1820

1921
/**
@@ -93,7 +95,7 @@ export class DcatApChV2DistributionAdapter implements EnhancedDistribution {
9395

9496
// Try to parse the byte size as a number.
9597
// Piveau returns it as a string with dots as thousands separators which is not valid for Number()
96-
const byteSizeNumber = Number(byteSizeValue.replace(/\./g, '')); // Remove dots for thousands separators
98+
const byteSizeNumber = Number(byteSizeValue.replace(/\./g, '').replace(/,/g, '').replace(/\s+/g, '')); // Remove spaces for thousands separators
9799

98100
if (isNaN(byteSizeNumber)) {
99101
return byteSizeValue; // Return the raw value if parsing fails
@@ -115,45 +117,166 @@ export class DcatApChV2DistributionAdapter implements EnhancedDistribution {
115117
return `${size % 1 === 0 ? size : size.toFixed(2)} ${units[unitIndex]}`;
116118
}
117119

118-
119-
120-
get getPropertyTable() {
121-
return this.#distribution?.getPropertyTable || [];
122-
}
123-
124-
120+
/**
121+
* Get the download URLs of the distribution.
122+
*
123+
* From dcat-ap-ch:
124+
* Property download URL
125+
* Requirement level Optional
126+
* Cardinality 0..n
127+
* URI dcat:downloadURL
128+
* Range rdfs:Resource
129+
* Usage Note
130+
* - In case of a downloadable file, it is good practice to repeat the mandatory accessURL in this more specific property,
131+
* to indicate to the data user that the distribution has this extra characteristic of being downloadable. The downloadURLs
132+
* MAY thus be the same as the accessURLs but they MAY also differ.
133+
*/
125134
get downloadUrls() {
126135
return this.#distribution?.downloadUrls || [];
127136
}
128137

138+
/**
139+
* Get the access URLs of the distribution.
140+
*
141+
* From dcat-ap-ch:
142+
* Property access URL
143+
* Requirement level Mandatory
144+
* Cardinality 1..n
145+
* URI dcat:accessURL
146+
* Range rdfs:Resource
147+
* Usage Note
148+
* - This property contains a URL that gives access to a Distribution of the Dataset. The resource at the access URL may contain
149+
* information about how to get the Dataset.
150+
*/
129151
get accessUrls() {
130152
return this.#distribution?.accessUrls || [];
131153
}
132154

133-
get format() {
134-
return this.#distribution?.format ?? '';
155+
/**
156+
* Get the format of the distribution.
157+
*
158+
* From dcat-ap-ch:
159+
* Property format
160+
* Requirement level Recommended
161+
* Cardinality 0..1
162+
* URI dct:format
163+
* Range dct:MediaTypeOrExtent
164+
* Usage Note
165+
* - This property refers to the file format of the Distribution.CV to be used: [VOCAB-EU-FILE-TYPE]
166+
* - CV to be used: [VOCAB-EU-FILE-TYPE]
167+
* - If a format is not available:
168+
* a) media type ([IANA-MEDIA-TYPES]) should be used
169+
* b) If necessary, a discussion to evaluate the adoption within the EU should be launched (Contact point: [VOCAB-EU-OP-CONTACT]).
170+
*/
171+
get format(): string {
172+
const format = this.#distribution?.format
173+
if (format) {
174+
return format;
175+
}
176+
// Fallback: get mediaType from property table
177+
const mediaTypeNode = this.#distribution?.getPropertyTable.find(node => node.id === 'mediaType');
178+
if (!mediaTypeNode || !mediaTypeNode.data?.length) {
179+
return '';
180+
}
181+
const mediaType = mediaTypeNode?.data[0]?.data ?? '';
182+
if (typeof mediaType !== 'string') {
183+
return '';
184+
}
185+
return mediaType;
135186
}
136187

188+
/**
189+
* Get the license of the distribution if available
190+
*
191+
* From dcat-ap-ch:
192+
* Property license
193+
* Requirement level Mandatory
194+
* Cardinality 1..1
195+
* URI dct:license
196+
* Range dct:LicenseDocument
197+
* Usage Note
198+
* This property refers to the licence under which the Distribution is made available.
199+
* CV to used: [VOCAB-CH-LICENSE]
200+
*/
137201
get license() {
138-
return this.#distribution?.license;
202+
const lic = this.#distribution?.license;
203+
const licIri = lic?.resource
204+
if (!licIri) {
205+
return undefined;
206+
}
207+
return licIri
139208
}
140209

141-
get issued() {
142-
return this.#distribution?.issued || '';
210+
211+
/**
212+
* Get the release date of the distribution if available
213+
* Property release date
214+
* Requirement level Optional
215+
* Cardinality 0..1
216+
* URI dct:issued
217+
* Range rdfs:Literal (typed as as xsd:date, xsd:dateTime, xsd:gYear or xsd:gYearMonth)
218+
* Usage Note
219+
* - This property contains the date of formal issuance (e.g., publication) of the Distribution.
220+
* - Date of formal issuance (publication) of the distribution
221+
* - UsageThe first time issuance of the distribution.
222+
*
223+
* @returns {Date | undefined} The release date as a Date object, or undefined if not available or invalid.
224+
*/
225+
get releaseDate() {
226+
const releaseDateString = this.#distribution?.issued || '';
227+
if (!releaseDateString) {
228+
return undefined;
229+
}
230+
const releaseDate = new Date(releaseDateString);
231+
return isNaN(releaseDate.getTime()) ? undefined : releaseDate;
143232
}
144233

234+
/**
235+
* Get the modified date of the distribution if available
236+
*
237+
* from dcat-ap-ch:
238+
* Property: update/modification date
239+
* This property contains the most recent date on which the Distribution was changed or modified.
240+
* Property update/ modification date
241+
* Requirement level Recommended
242+
* Cardinality 0..1
243+
* URI dct:modified
244+
* Range rdfs:Literal (typed as as xsd:date, xsd:dateTime, xsd:gYear or xsd:gYearMonth)
245+
* Usage Note
246+
*
247+
* @returns {Date | undefined} The modified date as a Date object, or undefined if not available or invalid.
248+
*/
145249
get modified() {
146-
return this.#distribution?.modified || '';
250+
const modifiedDateString = this.#distribution?.modified || '';
251+
if (!modifiedDateString) {
252+
return undefined;
253+
}
254+
const modifiedDate = new Date(modifiedDateString);
255+
return isNaN(modifiedDate.getTime()) ? undefined : modifiedDate;
147256
}
148257

258+
/**
259+
* Get the id of the distribution
260+
*
261+
* Note: This is not part of dcat-ap-ch, but added by piveau
262+
*/
149263
get id() {
150264
return this.#distribution?.id || '';
151265
}
152266

153-
get created() {
154-
return this.#distribution?.created;
155-
}
156-
267+
/**
268+
* Property Language
269+
* Requirement level Optional
270+
* Cardinality 0..n
271+
* URI dct:language
272+
* Range rdfs:Literal
273+
* Usage Note
274+
* - This property refers to a language used in the Distribution.
275+
* - This property can be repeated if the metadata is provided in multiple languages.
276+
* - The property MUST be set if the distribution is language-dependent or if it is given in some of the languages
277+
* German, French, Italian and English but not in all four languages.
278+
* - CV to be used: [VOCAB-EU-LANGUAGE]
279+
*/
157280
get languages() {
158281
return this.#distribution?.languages || [];
159282
}
@@ -170,18 +293,14 @@ export class DcatApChV2DistributionAdapter implements EnhancedDistribution {
170293

171294

172295
get propertyTable() {
173-
const rootNode = this.#dataset.getPropertyTable;
296+
const rootNode = this.#distribution?.getPropertyTable;
174297
if (!rootNode) {
175298
return [];
176299
}
177300

178-
// const ignoredNode = ['catalogRecord'];
179-
const ignoredNode: string[] = []
301+
const ignoredNode = ['byteSize'];
180302
const nodesToConsider = rootNode.filter(n => n.data).filter(n => !ignoredNode.includes(n.id));
181303

182-
console.log('flatNodes', nodesToConsider);
183-
184-
185304
const table: TableEntry[] = [];
186305
for (const node of nodesToConsider) {
187306

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<template>
2+
<ul class="download-items">
3+
<li v-for="url in props.downloadUrls" :key="url">
4+
<OdsDownloadListItem :download-url="url" :name="props.name" :format="props.format" :languages="props.languages" :byte-size="props.byteSize" />
5+
</li>
6+
</ul>
7+
8+
</template>
9+
10+
11+
<script setup lang="ts">
12+
import { defineProps } from 'vue';
13+
import OdsDownloadListItem from './OdsDownloadListItem.vue';
14+
15+
16+
const props = defineProps({
17+
downloadUrls: {
18+
type: Array as PropType<string[]>,
19+
required: true
20+
},
21+
format : {
22+
type: String,
23+
required: false,
24+
default: ''
25+
},
26+
name : {
27+
type: String,
28+
required: true
29+
},
30+
languages: {
31+
type: Array as PropType<string[]>,
32+
required: false,
33+
default: () => []
34+
},
35+
byteSize: {
36+
type: String,
37+
required: false,
38+
default: ''
39+
}
40+
});
41+
42+
</script>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<template>
2+
<div>
3+
<a class="download-item" :href="props.downloadUrl" target="_blank">
4+
<svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" class="icon icon--xl icon--Download download-item__icon">
5+
<path xmlns="http://www.w3.org/2000/svg" d="m19.419 13.698-.375-.649-6.294 3.634v-12.228h-.75v12.228l-6.294-3.634-.375.649 7.044 4.067z" />
6+
<path xmlns="http://www.w3.org/2000/svg" d="m6.00576 19.91649h12.76855v.75h-12.76855z"/>
7+
</svg>
8+
<div>
9+
<h2 class="download-item__title">{{ props.name }}</h2>
10+
<p class="meta-info download-item__meta-info">
11+
<span class="meta-info__item">{{ props.format }}</span>
12+
<span class="meta-info__item">{{ props.byteSize }}</span>
13+
<span class="meta-info__item">{{ props.languages.join(', ') }}</span>
14+
</p>
15+
</div>
16+
</a>
17+
</div>
18+
</template>
19+
20+
<script setup lang="ts">
21+
22+
import { defineProps } from 'vue';
23+
24+
const props = defineProps({
25+
downloadUrl: {
26+
type: String,
27+
required: true
28+
},
29+
name: {
30+
type: String,
31+
required: true
32+
},
33+
format : {
34+
type: String,
35+
required: false,
36+
default: ''
37+
},
38+
languages: {
39+
type: Array as PropType<string[]>,
40+
required: false,
41+
default: () => []
42+
},
43+
byteSize: {
44+
type: String,
45+
required: false,
46+
default: ''
47+
}
48+
});
49+
</script>
50+
51+
<style scoped lang="scss">
52+
a {
53+
overflow-x: hidden;
54+
word-break: break-all;
55+
}
56+
57+
.download-item__title {
58+
text-overflow: hidden;
59+
overflow-x: hidden;
60+
word-break: break-all;
61+
}
62+
</style>

0 commit comments

Comments
 (0)