@startinblox/components-ds4go 2.2.3 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/locales/en.xlf CHANGED
@@ -23,6 +23,81 @@
23
23
  <trans-unit id="sd3682395cf86f913">
24
24
  <source>Bundle updated on</source>
25
25
  </trans-unit>
26
+ <trans-unit id="s20acf344316637a0">
27
+ <source>All Catalogs</source>
28
+ </trans-unit>
29
+ <trans-unit id="s67269ab6dc51ec41">
30
+ <source>Error while loading catalog <x id="0" equiv-text="${this.catalogId}"/></source>
31
+ </trans-unit>
32
+ <trans-unit id="s0b88896b7338837d">
33
+ <source>All Datasets</source>
34
+ </trans-unit>
35
+ <trans-unit id="s541d9cd11a5bc840">
36
+ <source>Datasets from</source>
37
+ </trans-unit>
38
+ <trans-unit id="s01ceffa02fa6bd7f">
39
+ <source>All Sectors</source>
40
+ </trans-unit>
41
+ <trans-unit id="s4aaac20ff7887391">
42
+ <source>Catalogs available in</source>
43
+ </trans-unit>
44
+ <trans-unit id="sa89a60c3e1230cec">
45
+ <source>Root Authority</source>
46
+ </trans-unit>
47
+ <trans-unit id="se5784a16a6799dad">
48
+ <source>Back to <x id="0" equiv-text="${this.catalogId ? this.sectorId : &quot;Root Authority&quot;}"/></source>
49
+ </trans-unit>
50
+ <trans-unit id="s6665daa6d6147db0">
51
+ <source>No data available, data source may be temporarily unavailable.</source>
52
+ </trans-unit>
53
+ <trans-unit id="sc16e00a7a8b2fde2">
54
+ <source>Back</source>
55
+ </trans-unit>
56
+ <trans-unit id="s2c8189544e3ea679">
57
+ <source>Retry</source>
58
+ </trans-unit>
59
+ <trans-unit id="seb1a452f2df70baf">
60
+ <source>Create bundle</source>
61
+ </trans-unit>
62
+ <trans-unit id="sed5b6ae54e00125c">
63
+ <source>Bundle name</source>
64
+ </trans-unit>
65
+ <trans-unit id="s11099da36cbc3173">
66
+ <source>Bundle description</source>
67
+ </trans-unit>
68
+ <trans-unit id="sac1b0231875ff056">
69
+ <source><x id="0" equiv-text="${selectedFactsCount}"/> selected fact<x id="1" equiv-text="${selectedFactsCount &gt; 1 ? &quot;s&quot; : &quot;&quot;}"/></source>
70
+ </trans-unit>
71
+ <trans-unit id="s8272d3578b7c78d5">
72
+ <source>Displaying <x id="0" equiv-text="${splicedDatas.length}"/> of <x id="1" equiv-text="${datas.length}"/> result<x id="2" equiv-text="${datas.length &gt; 1 ? &quot;s&quot; : &quot;&quot;}"/></source>
73
+ </trans-unit>
74
+ <trans-unit id="sa40e7f4f2a43e2f7">
75
+ <source>Show more results</source>
76
+ </trans-unit>
77
+ <trans-unit id="sacf246e0fa11730d">
78
+ <source>Show all results</source>
79
+ </trans-unit>
80
+ <trans-unit id="s9094c0cde8fb5058">
81
+ <source>No results found</source>
82
+ </trans-unit>
83
+ <trans-unit id="sc7e3b594ffcd9d61">
84
+ <source>Open access</source>
85
+ </trans-unit>
86
+ <trans-unit id="sefcf950b3cc4fc3b">
87
+ <source>Language</source>
88
+ </trans-unit>
89
+ <trans-unit id="s6ae6714aac4ba43d">
90
+ <source>Language code (en, de, es, fr...)</source>
91
+ </trans-unit>
92
+ <trans-unit id="s21fb127cabcd5617">
93
+ <source>Comma-separated, eg.: en,de,es,fr)</source>
94
+ </trans-unit>
95
+ <trans-unit id="sa6ef22f7e7e95e2b">
96
+ <source>Access policy</source>
97
+ </trans-unit>
98
+ <trans-unit id="s6de61424bb681993">
99
+ <source>Contract policy</source>
100
+ </trans-unit>
26
101
  </body>
27
102
  </file>
28
103
  </xliff>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@startinblox/components-ds4go",
3
- "version": "2.2.3",
3
+ "version": "2.3.0",
4
4
  "description": "Startin'blox DS4GO",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -33,10 +33,10 @@ export class Ds4goFactBundleModal extends ComponentObjectHandler {
33
33
  <div class="modal-box">
34
34
  <div class="modal-content">
35
35
  <tems-division type="h3"
36
- ><div>${String(this.object.name)}</div></tems-division
36
+ ><div>${String(this.object.name || "")}</div></tems-division
37
37
  >
38
38
  <tems-division type="body-m"
39
- ><div>${String(this.object.description)}</div></tems-division
39
+ ><div>${String(this.object.description || "")}</div></tems-division
40
40
  >
41
41
  <tems-division type="h4"
42
42
  ><div>${msg("All facts in this bundle")}</div></tems-division
@@ -2,68 +2,24 @@ import {
2
2
  filterObjectByValue,
3
3
  formatDate,
4
4
  OrbitComponent,
5
+ requestNavigation,
5
6
  sort,
6
7
  } from "@helpers";
7
8
  import { msg, str } from "@lit/localize";
8
9
  import { Task } from "@lit/task";
9
- import type { PropertiesPicker, Resource } from "@src/component";
10
- import FlexHelpers from "@styles/_helpers/flex.scss?inline";
11
- import { css, html, nothing, unsafeCSS } from "lit";
10
+ import type {
11
+ OdrlPolicy,
12
+ OrbitComponent as OrbitComponentConfig,
13
+ PropertiesPicker,
14
+ Resource,
15
+ } from "@src/component";
16
+ import ComponentStyles from "@styles/fact-bundle-creation.scss?inline";
17
+ import { html, nothing, unsafeCSS } from "lit";
12
18
  import { customElement, property, state } from "lit/decorators.js";
13
19
 
14
20
  @customElement("solid-fact-bundle-creation")
15
21
  export class SolidFactBundle extends OrbitComponent {
16
- static styles = [
17
- unsafeCSS(FlexHelpers),
18
- css`
19
- [slot="content"] {
20
- height: 100%;
21
- }
22
- section {
23
- gap: var(--scale-400);
24
- padding: var(--scale-900) 0;
25
- height: calc(100% - var(--scale-900) * 2);
26
- }
27
- section > div {
28
- height: 100%;
29
- display: flex;
30
- flex-direction: column;
31
- gap: var(--scale-400);
32
- flex: 1;
33
- }
34
- section > div:first-child {
35
- max-width: 400px;
36
- }
37
- .card-grid {
38
- flex: 1;
39
- overflow-y: scroll;
40
- display: flex;
41
- flex-direction: row;
42
- flex-wrap: wrap;
43
- gap: 20px;
44
- align-content: flex-start;
45
- }
46
- .card-grid-vertical {
47
- justify-content: stretch;
48
- }
49
- .card-grid-vertical tems-card-catalog {
50
- width: 354px;
51
- height: fit-content;
52
- }
53
- tems-card-catalog {
54
- cursor: pointer;
55
- }
56
- tems-card-catalog[selected] {
57
- --color-border-primary: var(--color-surface-action-solid);
58
- }
59
- tems-search-bar {
60
- --scale-900: 0;
61
- }
62
- .gap-400 {
63
- gap: var(--scale-400);
64
- }
65
- `,
66
- ];
22
+ static styles = [unsafeCSS(ComponentStyles)];
67
23
 
68
24
  @property({ attribute: "header", type: String })
69
25
  header?: string = "DS4GO Fact Bundling Creation";
@@ -80,12 +36,48 @@ export class SolidFactBundle extends OrbitComponent {
80
36
  @state()
81
37
  bundleDescription = "";
82
38
 
39
+ @state()
40
+ bundleLanguage = "en";
41
+
42
+ policyTemplates: { id: string; name: string; policy: OdrlPolicy }[] = [
43
+ {
44
+ id: "policy-open-access",
45
+ name: msg("Open access"),
46
+ policy: {
47
+ "@type": "Set",
48
+ permission: [
49
+ {
50
+ action: "use",
51
+ },
52
+ ],
53
+ prohibition: [],
54
+ obligation: [],
55
+ },
56
+ },
57
+ ];
58
+
59
+ @state()
60
+ bundleAccessPolicy = this.policyTemplates[0].id;
61
+
62
+ @state()
63
+ bundleContractPolicy = this.policyTemplates[0].id;
64
+
83
65
  @state()
84
66
  filterFactText = "";
85
67
 
86
68
  @state()
87
69
  spliceLength = 0;
88
70
 
71
+ @state()
72
+ dspConnector: OrbitComponentConfig | undefined;
73
+
74
+ async _afterAttach() {
75
+ // use this.dspConnector.instance to reach the connector
76
+ this.dspConnector = this.orbit?.getComponent("dsp-connector");
77
+
78
+ return Promise.resolve();
79
+ }
80
+
89
81
  cherryPickedProperties: PropertiesPicker[] = [
90
82
  { key: "created_at", value: "created_at", cast: formatDate },
91
83
  { key: "updated_at", value: "updated_at", cast: formatDate },
@@ -184,7 +176,9 @@ export class SolidFactBundle extends OrbitComponent {
184
176
  "@type": ["ldp:Container", "ds4go:FactBundle"],
185
177
  name: this.bundleName,
186
178
  description: this.bundleDescription || "",
187
- "ldp:contains": this.selectedFacts.map((fact: Resource) => ({"@id": fact["@id"]})),
179
+ "ldp:contains": this.selectedFacts.map((fact: Resource) => ({
180
+ "@id": fact["@id"],
181
+ })),
188
182
  };
189
183
 
190
184
  const newFactBundleId = await window.sibStore.post(
@@ -205,6 +199,109 @@ export class SolidFactBundle extends OrbitComponent {
205
199
  bubbles: true,
206
200
  }),
207
201
  );
202
+
203
+ if (this.dspConnector) {
204
+ const idFromBundleId = await window.crypto.subtle
205
+ .digest("SHA-256", new TextEncoder().encode(newFactBundleId))
206
+ .then((hash) => {
207
+ return `sha-256:${Array.from(new Uint8Array(hash))
208
+ .map((b) => b.toString(16).padStart(2, "0"))
209
+ .join("")}`;
210
+ });
211
+
212
+ await this.dspConnector.instance?.createAsset({
213
+ "@id": `urn:asset-id:${idFromBundleId}`,
214
+ properties: {
215
+ name: this.bundleName,
216
+ description: this.bundleDescription,
217
+ contenttype: "application/ld+json",
218
+ language: this.bundleLanguage,
219
+ },
220
+ dataAddress: {
221
+ "@type": "DataAddress",
222
+ type: "HttpData",
223
+ baseUrl: newFactBundleId,
224
+ },
225
+ });
226
+
227
+ await Promise.all([
228
+ this.dspConnector.instance?.createPolicy({
229
+ "@id": `urn:access-policy-id:${idFromBundleId}`,
230
+ "@type": "PolicyDefinition",
231
+ policy: {
232
+ "@context": "http://www.w3.org/ns/odrl.jsonld",
233
+ ...this.policyTemplates.find(
234
+ (p) => p.id === this.bundleAccessPolicy,
235
+ )?.policy,
236
+ },
237
+ }),
238
+ this.dspConnector.instance?.createPolicy({
239
+ "@id": `urn:contract-policy-id:${idFromBundleId}`,
240
+ "@type": "PolicyDefinition",
241
+ policy: {
242
+ "@context": "http://www.w3.org/ns/odrl.jsonld",
243
+ ...this.policyTemplates.find(
244
+ (p) => p.id === this.bundleContractPolicy,
245
+ )?.policy,
246
+ },
247
+ }),
248
+ this.dspConnector.instance?.createContract({
249
+ "@id": `urn:contract-id:${idFromBundleId}`,
250
+ "@type": "ContractDefinition",
251
+ accessPolicyId: `urn:access-policy-id:${idFromBundleId}`,
252
+ contractPolicyId: `urn:contract-policy-id:${idFromBundleId}`,
253
+ assetsSelector: [
254
+ {
255
+ "@type": "Criterion",
256
+ operandLeft: "https://w3id.org/edc/v0.0.1/ns/id",
257
+ operator: "=",
258
+ operandRight: `urn:asset-id:${idFromBundleId}`,
259
+ },
260
+ ],
261
+ }),
262
+ ]);
263
+
264
+ // TODO: Do it from the other side, Adele
265
+ const TemsAssetManagement = document.querySelector(
266
+ "solid-tems-assets-management",
267
+ );
268
+ if (TemsAssetManagement) {
269
+ TemsAssetManagement.loadAssets();
270
+ }
271
+
272
+ const TemsPoliciesManagement = document.querySelector(
273
+ "solid-tems-policies-management",
274
+ );
275
+ if (TemsPoliciesManagement) {
276
+ TemsPoliciesManagement.loadPolicies();
277
+ }
278
+
279
+ const TemsContractsManagement = document.querySelector(
280
+ "solid-tems-contracts-management",
281
+ );
282
+ if (TemsContractsManagement) {
283
+ TemsContractsManagement.loadData();
284
+ }
285
+ }
286
+
287
+ this.bundleName = "";
288
+ this.bundleDescription = "";
289
+ this.selectedFacts = [];
290
+
291
+ const factbundleComponent: any = this.orbit?.getComponent("fact-bundle");
292
+
293
+ document.dispatchEvent(
294
+ new CustomEvent("save", {
295
+ detail: { resource: { "@id": factbundleComponent?.defaultDataSrc } },
296
+ bubbles: true,
297
+ }),
298
+ );
299
+ if (factbundleComponent) {
300
+ requestNavigation(
301
+ factbundleComponent?.route,
302
+ factbundleComponent?.defaultDataSrc,
303
+ );
304
+ }
208
305
  }
209
306
 
210
307
  _updateBundleName(e: Event) {
@@ -215,6 +312,24 @@ export class SolidFactBundle extends OrbitComponent {
215
312
  this.bundleDescription = e.detail.value;
216
313
  }
217
314
 
315
+ _updateBundleLanguage(e: Event) {
316
+ this.bundleLanguage = e.detail.value;
317
+ }
318
+
319
+ _selectBundleAccessPolicy(e: Event) {
320
+ e.preventDefault();
321
+ if (e.target) {
322
+ this.bundleAccessPolicy = e.target.value;
323
+ }
324
+ }
325
+
326
+ _selectBundleContractPolicy(e: Event) {
327
+ e.preventDefault();
328
+ if (e.target) {
329
+ this.bundleContractPolicy = e.target.value;
330
+ }
331
+ }
332
+
218
333
  _toggleFactSelection(fact: Resource) {
219
334
  if (this.selectedFacts.includes(fact)) {
220
335
  this.selectedFacts = this.selectedFacts.filter((f) => f !== fact);
@@ -241,7 +356,12 @@ export class SolidFactBundle extends OrbitComponent {
241
356
 
242
357
  const splicedDatas = datas.slice(0, this.spliceLength);
243
358
  const selectedFactsCount = this.selectedFacts.length;
244
- const allowCreation = !!this.bundleName && selectedFactsCount > 0;
359
+ const allowCreation =
360
+ !!this.bundleName &&
361
+ selectedFactsCount > 0 &&
362
+ !!this.bundleLanguage &&
363
+ !!this.bundleAccessPolicy &&
364
+ !!this.bundleContractPolicy;
245
365
 
246
366
  return html`<tems-viewport>
247
367
  <tems-header slot="header" heading=${this.header}>
@@ -276,6 +396,43 @@ export class SolidFactBundle extends OrbitComponent {
276
396
  @change=${this._updateBundleDescription}
277
397
  ></tems-textarea>
278
398
  </div>
399
+ <div>
400
+ <tems-input
401
+ type="text"
402
+ label=${msg("Language")}
403
+ placeholder=${msg("Language code (en, de, es, fr...)")}
404
+ hint=${msg("Comma-separated, eg.: en,de,es,fr)")}
405
+ required=""
406
+ .value=${this.bundleLanguage}
407
+ @change=${this._updateBundleLanguage}
408
+ ></tems-input>
409
+ </div>
410
+ <div class="select">
411
+ <tems-label label=${msg("Access policy")}></tems-label>
412
+ <select @change=${this._selectBundleAccessPolicy}>
413
+ ${this.policyTemplates.map((policy) => {
414
+ return html`<option
415
+ value="${policy.id}"
416
+ ?selected="${policy.id === this.bundleAccessPolicy}"
417
+ >
418
+ ${policy.name}
419
+ </option>`;
420
+ })}
421
+ </select>
422
+ </div>
423
+ <div class="select">
424
+ <tems-label label=${msg("Contract policy")}></tems-label>
425
+ <select @change=${this._selectBundleContractPolicy}>
426
+ ${this.policyTemplates.map((policy) => {
427
+ return html`<option
428
+ value="${policy.id}"
429
+ ?selected="${policy.id === this.bundleContractPolicy}"
430
+ >
431
+ ${policy.name}
432
+ </option>`;
433
+ })}
434
+ </select>
435
+ </div>
279
436
  ${selectedFactsCount > 0
280
437
  ? html`<tems-division type="h4">
281
438
  <div>
@@ -386,7 +543,10 @@ export class SolidFactBundle extends OrbitComponent {
386
543
  </div>
387
544
  </div>`
388
545
  : nothing}`
389
- : html`${msg("No results found")} ${this.filterFactText ? `for "${this.filterFactText}".` : ""}`}
546
+ : html`${msg("No results found")}
547
+ ${this.filterFactText
548
+ ? `for "${this.filterFactText}".`
549
+ : ""}`}
390
550
  </div>`
391
551
  : nothing}
392
552
  </section>
@@ -1,4 +1,10 @@
1
- import { formatDate, OrbitComponent, requestNavigation, setupCacheInvalidation, sort } from "@helpers";
1
+ import {
2
+ formatDate,
3
+ OrbitComponent,
4
+ requestNavigation,
5
+ setupCacheInvalidation,
6
+ sort,
7
+ } from "@helpers";
2
8
  import { msg } from "@lit/localize";
3
9
  import { Task } from "@lit/task";
4
10
  import type {
@@ -12,13 +18,6 @@ import { customElement, property, state } from "lit/decorators.js";
12
18
 
13
19
  @customElement("solid-fact-bundle")
14
20
  export class SolidFactBundle extends OrbitComponent {
15
- constructor() {
16
- super();
17
- setupCacheInvalidation(this, {
18
- keywords: ["factbundles"],
19
- });
20
- }
21
-
22
21
  static styles = css`
23
22
  .modal {
24
23
  position: fixed;
@@ -88,6 +87,10 @@ export class SolidFactBundle extends OrbitComponent {
88
87
  }
89
88
 
90
89
  async _afterAttach() {
90
+ setupCacheInvalidation(this, {
91
+ keywords: ["factbundles"],
92
+ });
93
+
91
94
  this.menuComponent = document.querySelector(
92
95
  `[uniq="${this.orbit?.getComponent("menu")?.uniq}"]`,
93
96
  );
@@ -102,7 +105,7 @@ export class SolidFactBundle extends OrbitComponent {
102
105
  _getResource = new Task(this, {
103
106
  task: async ([dataSrc, objSrc]) => {
104
107
  if (
105
- (!dataSrc && !objSrc) ||
108
+ !dataSrc ||
106
109
  !this.orbit ||
107
110
  (!this.noRouter &&
108
111
  this.route &&
@@ -136,7 +139,13 @@ export class SolidFactBundle extends OrbitComponent {
136
139
  this.objects = [];
137
140
  }
138
141
 
139
- this.object = this.objects.find((obj: Resource) => obj["@id"] === objSrc);
142
+ if (objSrc) {
143
+ this.object = this.objects.find(
144
+ (obj: Resource) => obj["@id"] === objSrc,
145
+ );
146
+ } else {
147
+ this.dataSrc = dataSrc;
148
+ }
140
149
 
141
150
  return sort(this.objects, "name", "asc");
142
151
  },
@@ -232,9 +241,8 @@ export class SolidFactBundle extends OrbitComponent {
232
241
  @clicked=${this._openModal}
233
242
  @result-count=${this._resultCountUpdate}
234
243
  ></ds4go-fact-bundle-holder>
235
- ${
236
- this.object
237
- ? html`<div
244
+ ${this.object
245
+ ? html`<div
238
246
  class="modal"
239
247
  @click=${this._closeModalFromBackground}
240
248
  >
@@ -243,8 +251,7 @@ export class SolidFactBundle extends OrbitComponent {
243
251
  @close=${this._closeModal}
244
252
  ></ds4go-fact-bundle-modal>
245
253
  </div>`
246
- : nothing
247
- }
254
+ : nothing}
248
255
  </div>
249
256
  </tems-viewport>`;
250
257
  },
@@ -0,0 +1,102 @@
1
+ @use "sass:meta";
2
+
3
+ @include meta.load-css("./_helpers/flex");
4
+
5
+ [slot="content"] {
6
+ height: 100%;
7
+ }
8
+
9
+ section {
10
+ gap: var(--scale-400);
11
+ padding: var(--scale-900) 0;
12
+ height: calc(100% - var(--scale-900) * 2);
13
+
14
+ > div {
15
+ height: 100%;
16
+ display: flex;
17
+ flex-direction: column;
18
+ gap: var(--scale-400);
19
+ flex: 1;
20
+
21
+ &:first-child {
22
+ max-width: 400px;
23
+ }
24
+ }
25
+ }
26
+
27
+ .card-grid {
28
+ flex: 1;
29
+ overflow-y: scroll;
30
+ display: flex;
31
+ flex-direction: row;
32
+ flex-wrap: wrap;
33
+ gap: 20px;
34
+ align-content: flex-start;
35
+ }
36
+
37
+ .card-grid-vertical {
38
+ justify-content: stretch;
39
+
40
+ tems-card-catalog {
41
+ width: 354px;
42
+ height: fit-content;
43
+ }
44
+ }
45
+
46
+ tems-card-catalog {
47
+ cursor: pointer;
48
+
49
+ &[selected] {
50
+ --color-border-primary: var(--color-surface-action-solid);
51
+ }
52
+ }
53
+
54
+ tems-search-bar {
55
+ --scale-900: 0;
56
+ }
57
+
58
+ .gap-400 {
59
+ gap: var(--scale-400);
60
+ }
61
+
62
+ div.select {
63
+ align-items: flex-start;
64
+ display: flex;
65
+ flex-direction: column;
66
+ gap: var(--scale-200);
67
+ width: 100%;
68
+ }
69
+
70
+ select {
71
+ width: 100%;
72
+ background-color: var(--color-surface-primary);
73
+ border: var(--border-width-sm) solid var(--color-border-primary);
74
+ border-radius: var(--border-radius-md);
75
+ color: var(--color-text-body);
76
+ font-family: var(--font-family-body);
77
+ font-size: var(--typography-size-body-sm);
78
+ font-style: normal;
79
+ font-weight: var(--font-weight-regular);
80
+ line-height: var(--line-height-body-sm);
81
+ letter-spacing: var(--font-letter-spacing-default);
82
+ padding: var(--scale-100) var(--scale-300);
83
+ appearance: none;
84
+ cursor: pointer;
85
+
86
+ &:hover {
87
+ border: var(--border-width-sm) solid var(--color-border-action);
88
+ }
89
+
90
+ option {
91
+ background-color: var(--color-surface-primary);
92
+ color: var(--color-text-body);
93
+ font-family: var(--font-family-body);
94
+ font-size: var(--typography-size-body-sm);
95
+ font-style: normal;
96
+ font-weight: var(--font-weight-regular);
97
+ line-height: var(--line-height-body-sm);
98
+ letter-spacing: var(--font-letter-spacing-default);
99
+ padding: var(--scale-100) var(--scale-300);
100
+ cursor: pointer;
101
+ }
102
+ }