@startinblox/components-ds4go 3.1.4 → 3.1.6

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/index.js CHANGED
@@ -1 +1 @@
1
- import "./index-DQ-N8-vz.js";
1
+ import "./index-9p-uZ-aS.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@startinblox/components-ds4go",
3
- "version": "3.1.4",
3
+ "version": "3.1.6",
4
4
  "description": "Startin'blox DS4GO",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -314,6 +314,137 @@ export interface Asset {
314
314
  properties?: Record<string, any>;
315
315
  }
316
316
 
317
+ // DSIF-specific types
318
+ export interface DSIFRootAuthoritySector {
319
+ sectorName: string;
320
+ federatedCatalogEndpoint: string;
321
+ description: string;
322
+ lastUpdated: string;
323
+ ttlSeconds: number;
324
+ id: string;
325
+ rootAuthorityUrl?: string;
326
+ }
327
+
328
+ export interface DSIFSectorAuthority {
329
+ sector: string;
330
+ catalogType: string;
331
+ version: string;
332
+ discoveryTimestamp: string;
333
+ catalogs: DSIFSectorAuthorityCatalog[];
334
+ count: number;
335
+ }
336
+
337
+ export interface DSIFSectorAuthorityCatalog {
338
+ catalogId: string;
339
+ type: string;
340
+ sector: string;
341
+ description: string;
342
+ endpoints: {
343
+ catalog: string;
344
+ dataset?: string;
345
+ search?: string;
346
+ health?: string;
347
+ discovery?: string;
348
+ };
349
+ conformsTo: string[];
350
+ capabilities: {
351
+ search: {
352
+ q: boolean;
353
+ filters: string[];
354
+ paging: boolean;
355
+ sort: string[];
356
+ };
357
+ catalog: {
358
+ pagination: boolean;
359
+ format: string;
360
+ };
361
+ auth: {
362
+ scheme: string;
363
+ };
364
+ };
365
+ searchTemplate?: string;
366
+ searchParameters?: string[];
367
+ auth: {
368
+ scheme: string;
369
+ };
370
+ lastUpdated: string;
371
+ ttlSeconds: number;
372
+ }
373
+
374
+ export interface DSIFCatalogEntry extends Resource {
375
+ "@id": string;
376
+ "@type": string;
377
+ "dct:title": string;
378
+ "dct:description": string;
379
+ "dct:publisher"?: {
380
+ "@id": string;
381
+ "dct:title": string;
382
+ };
383
+ "dcat:dataset": DSIFDataset[];
384
+ }
385
+
386
+ export interface DSIFCatalogWithContext extends DSIFSectorAuthorityCatalog {
387
+ sectorName?: string;
388
+ sectorId?: string;
389
+ rootAuthorityUrl?: string;
390
+ sectorAuthorityUrl?: string;
391
+ }
392
+
393
+ export interface DSIFDatasetWithContext extends DSIFDataset {
394
+ catalogTitle?: string;
395
+ catalogId?: string;
396
+ sectorName?: string;
397
+ sectorId?: string;
398
+ rootAuthorityUrl?: string;
399
+ sectorAuthorityUrl?: string;
400
+ }
401
+
402
+ export interface DSIFDatasetPricing {
403
+ "dsif:costPerAPICall": number;
404
+ "dsif:setupFee": number;
405
+ "dsif:billingPeriod": string;
406
+ "dsif:currency": string;
407
+ "dsif:description": string;
408
+ }
409
+
410
+ export interface DSIFDatasetNegotiation {
411
+ "dspace:participantId": string;
412
+ "dspace:protocolEndpoint": string;
413
+ }
414
+
415
+ export interface DSIFDatasetPolicy {
416
+ "@type": string;
417
+ "odrl:permission": Array<{ "odrl:action": string }>;
418
+ "odrl:prohibition": any[];
419
+ "odrl:obligation": any[];
420
+ }
421
+
422
+ export interface DSIFDataset extends Resource {
423
+ "@id": string;
424
+ "@type": string;
425
+ "dct:title": string;
426
+ "dct:description": string;
427
+ "dcat:mediaType": string;
428
+ "dspace:assetId": string;
429
+ "dsif:pricing"?: DSIFDatasetPricing;
430
+ "dsif:previewLinks"?: Array<{ "@id": string }>;
431
+ "odrl:hasPolicy"?: DSIFDatasetPolicy;
432
+ "edc:contractDefinitionId"?: string;
433
+ "dsif:negotiation"?: DSIFDatasetNegotiation;
434
+ "dsif:originCatalogId"?: string;
435
+ "dsif:federationPath"?: any[];
436
+ "dsif:hopCount"?: number;
437
+ "foaf:thumbnail"?: {
438
+ "rdf:resource": string;
439
+ };
440
+ catalogTitle?: string;
441
+ catalogId?: string;
442
+ sectorName?: string;
443
+ sectorId?: string;
444
+ rootAuthorityUrl?: string;
445
+ sectorAuthorityUrl?: string;
446
+ }
447
+
317
448
  export declare global {
318
449
  interface Window {
319
450
  orbit: LiveOrbit;
@@ -10,6 +10,7 @@ export type DS4GOCardCatalogProps = {
10
10
  header?: string;
11
11
  content?: string;
12
12
  date?: string;
13
+ image?: string;
13
14
  };
14
15
 
15
16
  @customElement("ds4go-card-catalog")
@@ -33,6 +34,9 @@ export class DS4GOCardCatalog extends LitElement {
33
34
  @property({ attribute: false })
34
35
  tags: DS4GOCardCatalogProps["tags"] = [];
35
36
 
37
+ @property({ attribute: "image", type: String })
38
+ image: DS4GOCardCatalogProps["image"];
39
+
36
40
  private _getType() {
37
41
  const allowedTypes = ["vertical", "horizontal", "bill-image"];
38
42
  if (!allowedTypes.includes(String(this.cardType))) {
@@ -96,6 +100,16 @@ export class DS4GOCardCatalog extends LitElement {
96
100
  </div>`;
97
101
  }
98
102
 
103
+ private renderImage() {
104
+ if (this.image) {
105
+ return html`<header
106
+ class="image"
107
+ style="background-image: url(&quot;${this.image}&quot;)"
108
+ ></header>`;
109
+ }
110
+ return nothing;
111
+ }
112
+
99
113
  render() {
100
114
  const classes = {
101
115
  ...this._getType(),
@@ -103,6 +117,7 @@ export class DS4GOCardCatalog extends LitElement {
103
117
 
104
118
  if (this.cardType === "horizontal") {
105
119
  return html`<article class=${classMap(classes)}>
120
+ ${this.renderImage()}
106
121
  <main>
107
122
  ${this.renderTags()}
108
123
  ${this.renderContent()}
@@ -112,6 +127,7 @@ export class DS4GOCardCatalog extends LitElement {
112
127
 
113
128
  if (this.cardType === "bill-image") {
114
129
  return html`<article class=${classMap(classes)}>
130
+ ${this.renderImage()}
115
131
  <main>
116
132
  ${this.renderTags()}
117
133
  ${this.renderContent()}
@@ -121,6 +137,7 @@ export class DS4GOCardCatalog extends LitElement {
121
137
  }
122
138
 
123
139
  return html`<article class=${classMap(classes)}>
140
+ ${this.renderImage()}
124
141
  <main>
125
142
  ${this.renderDate()}
126
143
  ${this.renderContent()}
@@ -0,0 +1,324 @@
1
+ import {
2
+ filterObjectByDateAfter,
3
+ filterObjectById,
4
+ filterObjectByInterval,
5
+ filterObjectByNamedValue,
6
+ filterObjectByType,
7
+ filterObjectByValue,
8
+ formatCase,
9
+ formatDate,
10
+ } from "@helpers";
11
+ import { msg } from "@lit/localize";
12
+ import type {
13
+ DSIFCatalogEntry,
14
+ DSIFCatalogWithContext,
15
+ DSIFDataset,
16
+ DSIFDatasetWithContext,
17
+ DSIFRootAuthoritySector,
18
+ Resource,
19
+ SearchObject,
20
+ UnknownResource,
21
+ } from "@src/component";
22
+ import { css, html, LitElement, nothing, type PropertyValues } from "lit";
23
+ import { customElement, property, state } from "lit/decorators.js";
24
+
25
+ type holderTypeArray = (
26
+ | DSIFRootAuthoritySector
27
+ | DSIFCatalogWithContext
28
+ | DSIFDatasetWithContext
29
+ )[];
30
+
31
+ type holderType = DSIFCatalogEntry | holderTypeArray;
32
+
33
+ @customElement("ds4go-dsif-explorer-poc-holder")
34
+ export class Ds4goDsifExplorerPocHolder extends LitElement {
35
+ @property({ attribute: false })
36
+ objects?: holderType = [];
37
+
38
+ static styles = css`
39
+ .card-grid {
40
+ display: flex;
41
+ flex-direction: row;
42
+ flex-wrap: wrap;
43
+ gap: 20px;
44
+ }
45
+ .card-grid-vertical {
46
+ justify-content: stretch;
47
+ }
48
+ .card-grid-vertical ds4go-card-catalog {
49
+ width: 354px;
50
+ height: auto;
51
+ }
52
+ ds4go-card-catalog.cursor-pointer {
53
+ cursor: pointer;
54
+ }
55
+ tems-division {
56
+ margin-bottom: var(--scale-900);
57
+ }
58
+ `;
59
+
60
+ @state()
61
+ search: SearchObject[] = [];
62
+
63
+ @state()
64
+ protected _displayObjects: holderType = [];
65
+
66
+ protected filter(
67
+ objects: holderType,
68
+ filters: SearchObject[] = [],
69
+ ): holderType {
70
+ if (Array.isArray(objects)) {
71
+ if (
72
+ !filters ||
73
+ filters.length === 0 ||
74
+ !objects ||
75
+ objects.length === 0
76
+ ) {
77
+ return objects;
78
+ }
79
+
80
+ const groupedFilters = new Map<string, SearchObject[]>();
81
+ for (const filter of filters) {
82
+ const groupKey = filter.name;
83
+ const group = groupedFilters.get(groupKey) || [];
84
+ group.push(filter);
85
+ groupedFilters.set(groupKey, group);
86
+ }
87
+
88
+ let currentFilteredObjects = [...objects];
89
+
90
+ for (const filterGroup of groupedFilters.values()) {
91
+ if (currentFilteredObjects.length === 0) {
92
+ break;
93
+ }
94
+
95
+ const tempResults: UnknownResource[] = [];
96
+ for (const filter of filterGroup) {
97
+ switch (filter.type) {
98
+ case "interval":
99
+ tempResults.push(
100
+ filterObjectByInterval(
101
+ currentFilteredObjects,
102
+ filter.name,
103
+ filter.value,
104
+ ),
105
+ );
106
+ break;
107
+ case "dateAfter":
108
+ tempResults.push(
109
+ filterObjectByDateAfter(
110
+ currentFilteredObjects,
111
+ filter.name,
112
+ filter.value,
113
+ ),
114
+ );
115
+ break;
116
+ case "matchId":
117
+ tempResults.push(
118
+ filterObjectById(
119
+ currentFilteredObjects,
120
+ filter.name,
121
+ filter.value,
122
+ ),
123
+ );
124
+ break;
125
+ case "matchType":
126
+ tempResults.push(
127
+ filterObjectByType(currentFilteredObjects, filter.value),
128
+ );
129
+ break;
130
+ case "exact":
131
+ tempResults.push(
132
+ filterObjectByNamedValue(
133
+ currentFilteredObjects,
134
+ filter.name,
135
+ filter.value,
136
+ ),
137
+ );
138
+ break;
139
+ default:
140
+ tempResults.push(
141
+ filterObjectByValue(currentFilteredObjects, filter.value),
142
+ );
143
+ }
144
+ }
145
+ currentFilteredObjects = [...tempResults.flat()] as holderTypeArray;
146
+ }
147
+
148
+ return currentFilteredObjects;
149
+ }
150
+ return {
151
+ ...(objects as holderType),
152
+ "dcat:dataset": this.filter(
153
+ objects["dcat:dataset"],
154
+ filters,
155
+ ) as DSIFDataset[],
156
+ };
157
+ }
158
+
159
+ protected _handleClickEvent(originalObj: Resource) {
160
+ this.dispatchEvent(new CustomEvent("clicked", { detail: originalObj }));
161
+ }
162
+
163
+ willUpdate(changedProperties: PropertyValues) {
164
+ if (changedProperties.has("objects") || changedProperties.has("search")) {
165
+ if (this.objects) {
166
+ this._displayObjects = this.filter(this.objects, this.search);
167
+ } else {
168
+ this._displayObjects = [];
169
+ }
170
+ this.dispatchEvent(
171
+ new CustomEvent("result-count", {
172
+ detail: this._displayObjects.length,
173
+ }),
174
+ );
175
+ }
176
+ }
177
+
178
+ private _getDatasetTags(dataset: DSIFDatasetWithContext) {
179
+ const tags: Array<{ name: string; type?: string }> = [];
180
+
181
+ if (dataset["dsif:pricing"]) {
182
+ const pricing = dataset["dsif:pricing"];
183
+ const cost =
184
+ pricing["dsif:costPerAPICall"] > 0
185
+ ? `${pricing["dsif:costPerAPICall"]} ${pricing["dsif:currency"]}/call`
186
+ : "Free";
187
+ tags.push({
188
+ name: cost,
189
+ type: pricing["dsif:costPerAPICall"] > 0 ? "warning" : "success",
190
+ });
191
+ }
192
+
193
+ if (dataset["dspace:assetId"]) {
194
+ tags.push({
195
+ name:
196
+ dataset["dspace:assetId"].split(":").pop() ||
197
+ dataset["dspace:assetId"],
198
+ type: "info",
199
+ });
200
+ }
201
+
202
+ if (dataset.sectorName) {
203
+ tags.push({ name: formatCase(dataset.sectorName), type: "neutral" });
204
+ }
205
+
206
+ if (
207
+ dataset["dsif:previewLinks"] &&
208
+ dataset["dsif:previewLinks"].length > 0
209
+ ) {
210
+ tags.push({
211
+ name: `${dataset["dsif:previewLinks"].length} previews`,
212
+ type: "info",
213
+ });
214
+ }
215
+
216
+ return tags;
217
+ }
218
+
219
+ private _getDatasetThumbnail(dataset: DSIFDatasetWithContext): string {
220
+ if (dataset["foaf:thumbnail"]?.["rdf:resource"]) {
221
+ return dataset["foaf:thumbnail"]["rdf:resource"];
222
+ }
223
+
224
+ return "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='354' height='200' viewBox='0 0 354 200'%3E%3Crect width='354' height='200' fill='%23f0f0f0'/%3E%3Ctext x='50%25' y='50%25' dominant-baseline='middle' text-anchor='middle' font-family='sans-serif' font-size='14' fill='%23999'%3ENo Thumbnail%3C/text%3E%3C/svg%3E";
225
+ }
226
+
227
+ private _getCatalogTags(catalog: DSIFCatalogWithContext) {
228
+ const tags: Array<{ name: string; type?: string }> = [];
229
+
230
+ if (catalog.type) {
231
+ tags.push({
232
+ name: catalog.type.toUpperCase(),
233
+ type: catalog.type === "ic" ? "success" : "info",
234
+ });
235
+ }
236
+
237
+ if (catalog.sectorName) {
238
+ tags.push({ name: formatCase(catalog.sectorName), type: "neutral" });
239
+ }
240
+
241
+ return tags;
242
+ }
243
+
244
+ private _getSectorTags(sector: DSIFRootAuthoritySector) {
245
+ const tags: Array<{ name: string; type?: string }> = [];
246
+
247
+ if (sector.sectorName) {
248
+ tags.push({ name: formatCase(sector.sectorName), type: "neutral" });
249
+ }
250
+
251
+ return tags;
252
+ }
253
+
254
+ render() {
255
+ if (!this._displayObjects || this._displayObjects.length === 0) {
256
+ return html`<p>
257
+ ${msg(
258
+ "No data available, data source may be temporarily unavailable.",
259
+ )}
260
+ </p>
261
+ ${this.sectorId || this.catalogId
262
+ ? html`<tems-button
263
+ type="primary"
264
+ label=${msg("Back")}
265
+ @click=${this.parent._back}
266
+ ></tems-button>`
267
+ : html`<tems-button
268
+ type="primary"
269
+ label=${msg("Retry")}
270
+ @click=${this.parent.requestUpdate}
271
+ ></tems-button>`}`;
272
+ }
273
+ return html`<div>
274
+ ${this.catalogId && this.catalogId !== "*"
275
+ ? html`<tems-division type="body-m"
276
+ >${(this._displayObjects as DSIFCatalogEntry)[
277
+ "dct:description"
278
+ ]}</tems-division
279
+ >`
280
+ : nothing}
281
+ <div class="card-grid card-grid-vertical">
282
+ ${this.catalogId
283
+ ? html`${(this._displayObjects as DSIFCatalogEntry)[
284
+ "dcat:dataset"
285
+ ].map(
286
+ (dataset: DSIFDatasetWithContext) =>
287
+ html`<ds4go-card-catalog
288
+ .object=${import.meta.env.DEV ? dataset : nothing}
289
+ .header=${dataset["dct:title"] || nothing}
290
+ .content=${dataset["dct:description"] || nothing}
291
+ .tags=${this._getDatasetTags(dataset)}
292
+ .image=${this._getDatasetThumbnail(dataset)}
293
+ ></ds4go-card-catalog>`,
294
+ )}`
295
+ : this.sectorId
296
+ ? html`${(this._displayObjects as DSIFCatalogWithContext[]).map(
297
+ (catalog: DSIFCatalogWithContext) =>
298
+ html`<ds4go-card-catalog
299
+ class="cursor-pointer"
300
+ .object=${import.meta.env.DEV ? catalog : nothing}
301
+ .header=${catalog.catalogId || nothing}
302
+ .content=${catalog.description || nothing}
303
+ .tags=${this._getCatalogTags(catalog)}
304
+ date=${formatDate(catalog.lastUpdated) || nothing}
305
+ @click=${() =>
306
+ this.parent._selectCatalog(catalog.catalogId)}
307
+ ></ds4go-card-catalog>`,
308
+ )}`
309
+ : html`${(this._displayObjects as DSIFRootAuthoritySector[]).map(
310
+ (sector: DSIFRootAuthoritySector) =>
311
+ html`<ds4go-card-catalog
312
+ class="cursor-pointer"
313
+ .object=${import.meta.env.DEV ? sector : nothing}
314
+ .header=${sector.id || nothing}
315
+ .content=${sector.description || nothing}
316
+ .tags=${this._getSectorTags(sector)}
317
+ date=${formatDate(sector.lastUpdated) || nothing}
318
+ @click=${() => this.parent._selectSector(sector.id)}
319
+ ></ds4go-card-catalog>`,
320
+ )}`}
321
+ </div>
322
+ </div>`;
323
+ }
324
+ }
@@ -58,6 +58,14 @@ export class Ds4goFactBundleModal extends OrbitComponent {
58
58
  @state()
59
59
  negotiations: ExtendedContractNegotiation[] = [];
60
60
 
61
+ @state()
62
+ showTechnicalInfo = false;
63
+
64
+ _toggleTechnicalInfo(e: Event) {
65
+ e.preventDefault();
66
+ this.showTechnicalInfo = !this.showTechnicalInfo;
67
+ }
68
+
61
69
  _getResource = new Task(this, {
62
70
  task: async () => {
63
71
  if (!this.object) return;
@@ -180,18 +188,29 @@ export class Ds4goFactBundleModal extends OrbitComponent {
180
188
  </div>
181
189
  </div></tems-division
182
190
  >
183
- <tems-division type="h4"
184
- ><div>${msg("Technical informations")}</div></tems-division
185
- >
186
- ${this.contracts && this.contracts.length > 0
187
- ? html`${this.contracts.map(
188
- (contract: ContractDefinition) =>
189
- html`<ds4go-contract-modal-part
190
- .contract=${contract}
191
- .assets=${this.assets}
192
- .policies=${this.policies}
193
- ></ds4go-contract-modal-part>`,
194
- )}`
191
+ <tems-button
192
+ @click=${this._toggleTechnicalInfo}
193
+ type="outline-gray"
194
+ label=${this.showTechnicalInfo
195
+ ? msg("Hide Technical Informations")
196
+ : msg("Show Technical Informations")}
197
+ ></tems-button>
198
+ ${this.showTechnicalInfo
199
+ ? html`
200
+ <tems-division type="h4"
201
+ >${msg("Technical informations")}</tems-division
202
+ >
203
+ ${this.contracts && this.contracts.length > 0
204
+ ? html`${this.contracts.map(
205
+ (contract: ContractDefinition) =>
206
+ html`<ds4go-contract-modal-part
207
+ .contract=${contract}
208
+ .assets=${this.assets}
209
+ .policies=${this.policies}
210
+ ></ds4go-contract-modal-part>`,
211
+ )}`
212
+ : nothing}
213
+ `
195
214
  : nothing}
196
215
  ${this.negotiations && this.negotiations.length > 0
197
216
  ? html`<ds4go-negotiations-modal-part