@startinblox/components-ds4go 3.2.2 → 3.3.1

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.
@@ -196,17 +196,21 @@ export class Ds4goCustomerModal extends OrbitComponent {
196
196
  .map(([negotiationId]) => negotiationId);
197
197
 
198
198
  // Filter negotiations where counterPartyId === participant_id OR participant is in agreements
199
- this.negotiations = allNegotiations.filter((n: ContractNegotiation) => {
200
- const counterPartyId = n.counterPartyId;
201
- if (counterPartyId) {
202
- const counterPartyParticipantId = counterPartyId.split("/").pop();
203
- if (counterPartyParticipantId?.startsWith(participantId)) {
204
- return true;
199
+ this.negotiations = allNegotiations.filter(
200
+ (n: ContractNegotiation) => {
201
+ const counterPartyId = n.counterPartyId;
202
+ if (counterPartyId) {
203
+ const counterPartyParticipantId = counterPartyId
204
+ .split("/")
205
+ .pop();
206
+ if (counterPartyParticipantId?.startsWith(participantId)) {
207
+ return true;
208
+ }
205
209
  }
206
- }
207
- // Also include negotiations that have agreements where participant is consumer or provider
208
- return negotiationIdsWithParticipant.includes(n["@id"]);
209
- });
210
+ // Also include negotiations that have agreements where participant is consumer or provider
211
+ return negotiationIdsWithParticipant.includes(n["@id"]);
212
+ },
213
+ );
210
214
 
211
215
  // Load agreements for filtered negotiations for display
212
216
  await Promise.all(
@@ -224,7 +228,9 @@ export class Ds4goCustomerModal extends OrbitComponent {
224
228
  (n: ExtendedContractNegotiation) => {
225
229
  if (!n.agreement) return false;
226
230
  if (!n.agreement.providerId) return false;
227
- const providerParticipantId = n.agreement.providerId.split("/").pop();
231
+ const providerParticipantId = n.agreement.providerId
232
+ .split("/")
233
+ .pop();
228
234
  return providerParticipantId?.startsWith(participantId);
229
235
  },
230
236
  );
@@ -233,15 +239,21 @@ export class Ds4goCustomerModal extends OrbitComponent {
233
239
  (n: ExtendedContractNegotiation) => {
234
240
  if (!n.agreement) return false;
235
241
  if (!n.agreement.consumerId) return false;
236
- const consumerParticipantId = n.agreement.consumerId.split("/").pop();
242
+ const consumerParticipantId = n.agreement.consumerId
243
+ .split("/")
244
+ .pop();
237
245
  return consumerParticipantId?.startsWith(participantId);
238
246
  },
239
247
  );
240
248
  }
241
249
  } else {
242
- console.warn(
243
- "DSP Connector not found. Please ensure the DSP Connector is properly initialized.",
244
- );
250
+ const listener = () => {
251
+ this.caching++;
252
+ this.requestUpdate();
253
+ document.removeEventListener("dsp-connector-ready", listener);
254
+ };
255
+ document.addEventListener("dsp-connector-ready", listener);
256
+ return;
245
257
  }
246
258
 
247
259
  return this.object;
@@ -286,9 +298,12 @@ export class Ds4goCustomerModal extends OrbitComponent {
286
298
  </div></tems-division
287
299
  >`
288
300
  : nothing}
289
- ${this.providerNegotiations && this.providerNegotiations.length > 0
301
+ ${this.providerNegotiations &&
302
+ this.providerNegotiations.length > 0
290
303
  ? html`<tems-division type="h4"
291
- ><div>${msg("Provider Negotiations")}</div></tems-division
304
+ ><div>
305
+ ${msg("Provider Negotiations")}
306
+ </div></tems-division
292
307
  >
293
308
  <div class="card-grid card-grid-vertical">
294
309
  ${this.providerNegotiations.map(
@@ -313,9 +328,12 @@ export class Ds4goCustomerModal extends OrbitComponent {
313
328
  )}
314
329
  </div>`
315
330
  : nothing}
316
- ${this.consumerNegotiations && this.consumerNegotiations.length > 0
331
+ ${this.consumerNegotiations &&
332
+ this.consumerNegotiations.length > 0
317
333
  ? html`<tems-division type="h4"
318
- ><div>${msg("Customer Negotiations")}</div></tems-division
334
+ ><div>
335
+ ${msg("Customer Negotiations")}
336
+ </div></tems-division
319
337
  >
320
338
  <div class="card-grid card-grid-vertical">
321
339
  ${this.consumerNegotiations.map(
@@ -116,9 +116,13 @@ export class Ds4goFactBundleModal extends OrbitComponent {
116
116
  }
117
117
  });
118
118
  } else {
119
- console.warn(
120
- "DSP Connector not found. Please ensure the DSP Connector is properly initialized.",
121
- );
119
+ const listener = () => {
120
+ this.caching++;
121
+ this.requestUpdate();
122
+ document.removeEventListener("dsp-connector-ready", listener);
123
+ };
124
+ document.addEventListener("dsp-connector-ready", listener);
125
+ return;
122
126
  }
123
127
 
124
128
  return this.object;
@@ -0,0 +1,234 @@
1
+ import * as utils from "@helpers";
2
+ import { msg, str } from "@lit/localize";
3
+ import { Task } from "@lit/task";
4
+ import type {
5
+ Resource,
6
+ OrbitComponent as OrbitComponentConfig,
7
+ } from "@src/component";
8
+ import {
9
+ OrbitDSPComponent,
10
+ type TemsSearchObject,
11
+ } from "@startinblox/solid-tems-shared";
12
+ import { css, html, nothing } from "lit";
13
+ import { customElement, property, state } from "lit/decorators.js";
14
+
15
+ export interface DSPProviderConfig {
16
+ name: string;
17
+ address: string;
18
+ color?: string;
19
+ participantId?: string;
20
+ }
21
+
22
+ @customElement("solid-dsp-catalog")
23
+ export class DSPCatalog extends OrbitDSPComponent {
24
+ constructor() {
25
+ super();
26
+ utils.setupCacheInvalidation(this, {
27
+ keywords: ["groups", "objects", "dsp"],
28
+ });
29
+ }
30
+
31
+ static styles = css`
32
+ .modal {
33
+ position: fixed;
34
+ top: 0;
35
+ left: 0;
36
+ right: 0;
37
+ bottom: 0;
38
+ background-color: rgba(0, 2, 49, 0.2);
39
+ z-index: 9999;
40
+ display: flex;
41
+ justify-content: center;
42
+ align-items: center;
43
+ }
44
+ `;
45
+
46
+ @state()
47
+ dspConnector: OrbitComponentConfig | undefined;
48
+
49
+ @property({ attribute: "header", type: String })
50
+ header?: string = "DSP Catalog";
51
+
52
+ @state()
53
+ search: TemsSearchObject[] = [];
54
+
55
+ @state()
56
+ resultCount = this.objects?.length || 0;
57
+
58
+ async _afterAttach() {
59
+ // use this.dspConnector.instance to reach the connector
60
+ this.dspConnector = this.orbit?.components.find(
61
+ (c) => c.type === "dsp-connector",
62
+ );
63
+
64
+ return Promise.resolve();
65
+ }
66
+
67
+ _getResource = new Task(this, {
68
+ task: async ([objSrc]) => {
69
+ if (
70
+ !this.orbit ||
71
+ (!this.noRouter &&
72
+ this.route &&
73
+ this.currentRoute &&
74
+ !this.route.startsWith(this.currentRoute))
75
+ )
76
+ return;
77
+
78
+ if (this.dspConnector?.instance) {
79
+ await this.dspConnector.instance.loadAll();
80
+ this.datas = this.dspConnector.instance.datas;
81
+ this.providers = this.dspConnector.instance.providers;
82
+ } else {
83
+ const listener = () => {
84
+ this.caching++;
85
+ this.requestUpdate();
86
+ document.removeEventListener("dsp-connector-ready", listener);
87
+ };
88
+ document.addEventListener("dsp-connector-ready", listener);
89
+ return;
90
+ }
91
+
92
+ if (objSrc) {
93
+ this.object = this.datas.find((obj: Resource) => obj["@id"] === objSrc);
94
+ } else {
95
+ this.object = undefined;
96
+ }
97
+
98
+ return this.datas;
99
+ },
100
+ args: () => [this.dataSrc, this.caching, this.currentRoute],
101
+ });
102
+
103
+ _search(e: Event) {
104
+ e.preventDefault();
105
+ this.search = e.detail;
106
+ this.filterCount = this.search.filter((s) => s.name !== "search").length;
107
+ }
108
+
109
+ _openModal(e: Event) {
110
+ e.preventDefault();
111
+ if (this.route) {
112
+ if ("use-id" in (this.component.routeAttributes || {})) {
113
+ utils.requestNavigation(this.route, e.detail["@id"]);
114
+ } else {
115
+ const rdfType = e.detail["@type"]?.at(-1) ?? e.detail["@type"];
116
+ if (rdfType) {
117
+ const compatibleComponents = window.orbit?.components?.filter(
118
+ (c) => c?.routeAttributes?.["rdf-type"] === rdfType,
119
+ );
120
+
121
+ if (compatibleComponents?.[0]?.route) {
122
+ utils.requestNavigation(
123
+ compatibleComponents[0]?.route,
124
+ e.detail["@id"],
125
+ );
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ _closeModal(e: Event) {
133
+ e.preventDefault();
134
+ if (this.route) utils.requestNavigation(this.route, this.defaultDataSrc);
135
+ }
136
+
137
+ _closeModalFromBackground(e: Event) {
138
+ e.preventDefault();
139
+ if (this.route && e.target?.classList.contains("modal"))
140
+ utils.requestNavigation(this.route, this.defaultDataSrc);
141
+ }
142
+
143
+ _resultCountUpdate(e: Event) {
144
+ this.resultCount = e.detail ?? 0;
145
+ }
146
+
147
+ render() {
148
+ // Can't use gatekeeper as dataSrc can be none here
149
+ if (
150
+ !this.orbit ||
151
+ (!this.noRouter &&
152
+ this.route &&
153
+ this.currentRoute &&
154
+ !this.route.startsWith(this.currentRoute))
155
+ ) {
156
+ return nothing;
157
+ }
158
+
159
+ return this._getResource.render({
160
+ pending: () => html`<solid-loader></solid-loader>`,
161
+ error: (e) => html`<p>${e}</p>`,
162
+ complete: (datas) => {
163
+ if (!datas || !this.providers) {
164
+ return nothing;
165
+ }
166
+ return html`<tems-viewport>
167
+ <tems-header slot="header" heading=${this.header}></tems-header>
168
+ <div slot="content">
169
+ ${this.providers.length > 0
170
+ ? html`<div
171
+ style="background: white; padding: 1rem; border-radius: 8px; margin-bottom: 1rem;"
172
+ >
173
+ <h3 style="margin: 0 0 1rem 0;">
174
+ ${msg("Provider Statistics")}
175
+ </h3>
176
+ <div
177
+ style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 1rem;"
178
+ >
179
+ ${this.providers.map((provider: DSPProviderConfig) => {
180
+ const providerDatasets = datas.filter(
181
+ (d: Resource) => d._provider === provider.name,
182
+ );
183
+ return html`
184
+ <div
185
+ style="background: #f5f5f5; padding: 1rem; border-radius: 4px; border-left: 4px solid ${provider.color ||
186
+ "#1976d2"};"
187
+ >
188
+ <div
189
+ style="font-weight: bold; margin-bottom: 0.5rem;"
190
+ >
191
+ ${provider.name}
192
+ </div>
193
+ <div style="font-size: 1.125rem; color: #1976d2;">
194
+ ${msg(str`${providerDatasets.length} datasets`)}
195
+ </div>
196
+ </div>
197
+ `;
198
+ })}
199
+ </div>
200
+ </div>`
201
+ : nothing}
202
+ <tems-catalog-filter-holder
203
+ .displayFiltering=${false}
204
+ @search=${this._search}
205
+ .search=${this.search}
206
+ .view=${"card"}
207
+ .objects=${datas}
208
+ .resultCount=${this.resultCount}
209
+ .filterCount=${this.filterCount}
210
+ ></tems-catalog-filter-holder>
211
+ <ds4go-catalog-data-holder
212
+ .view=${"card"}
213
+ .objects=${datas}
214
+ .search=${this.search}
215
+ @clicked=${this._openModal}
216
+ @result-count=${this._resultCountUpdate}
217
+ ></ds4go-catalog-data-holder>
218
+ ${this.object
219
+ ? html`<div
220
+ class="modal"
221
+ @click=${this._closeModalFromBackground}
222
+ >
223
+ <ds4go-catalog
224
+ .object=${this.object}
225
+ @close=${this._closeModal}
226
+ ></ds4go-catalog>
227
+ </div>`
228
+ : nothing}
229
+ </div>
230
+ </tems-viewport>`;
231
+ },
232
+ });
233
+ }
234
+ }
@@ -20,6 +20,14 @@ export class SolidDspConnector extends OrbitDSPComponent {
20
20
  await super._afterAttach();
21
21
  await this.loadAll();
22
22
  this.setupAutoRefresh();
23
+
24
+ this.dispatchEvent(
25
+ new CustomEvent("dsp-connector-ready", {
26
+ bubbles: true,
27
+ composed: true,
28
+ }),
29
+ );
30
+
23
31
  return Promise.resolve();
24
32
  }
25
33
 
@@ -0,0 +1,215 @@
1
+ @mixin card-content-max-height($height) {
2
+ max-height: $height;
3
+ tems-division {
4
+ max-height: $height;
5
+ }
6
+ }
7
+
8
+ :host {
9
+ box-sizing: border-box;
10
+ display: flex;
11
+ width: 100%;
12
+ max-width: 100%;
13
+ height: fit-content;
14
+ }
15
+
16
+ article {
17
+ border-radius: var(--border-radius-lg);
18
+ border: var(--border-width-sm) solid var(--color-border-primary);
19
+ width: 100%;
20
+ display: flex;
21
+ font-family: var(--font-family-body);
22
+ &.vertical {
23
+ min-width: 295px;
24
+ .card-content {
25
+ max-height: 180px;
26
+ tems-division {
27
+ max-height: 180px;
28
+ }
29
+ }
30
+ }
31
+ &.horizontal,
32
+ &.billImage {
33
+ header {
34
+ width: auto;
35
+ border-radius: var(--border-radius-lg) 0 0 var(--border-radius-lg);
36
+ }
37
+ header.image {
38
+ flex-shrink: 0;
39
+ width: 33%;
40
+ height: 100%;
41
+ }
42
+ main {
43
+ flex-grow: 1;
44
+ .card-content {
45
+ max-height: 78px;
46
+ tems-division {
47
+ max-height: 78px;
48
+ }
49
+ }
50
+ }
51
+ }
52
+ &.billImage {
53
+ header.image {
54
+ width: 50%;
55
+ }
56
+ .card-content {
57
+ max-height: 206px;
58
+ tems-division {
59
+ max-height: 206px;
60
+ }
61
+ }
62
+ }
63
+ header {
64
+ display: flex;
65
+ background-repeat: no-repeat;
66
+ background-size: cover;
67
+ background-position: center center;
68
+ box-sizing: border-box;
69
+ width: 100%;
70
+ padding: 16px;
71
+ }
72
+ main {
73
+ display: flex;
74
+ flex-direction: column;
75
+ gap: var(--scale-400);
76
+ flex: 1;
77
+ .content {
78
+ flex: 1;
79
+ }
80
+ .orgLogo {
81
+ background-repeat: no-repeat;
82
+ background-size: contain;
83
+ background-position: center center;
84
+ width: 48px;
85
+ height: 48px;
86
+ }
87
+ .card-content {
88
+ flex-grow: 1;
89
+ overflow: hidden;
90
+ text-overflow: ellipsis;
91
+ width: 100%;
92
+ }
93
+ .address-line {
94
+ display: flex;
95
+ flex-direction: row;
96
+ justify-content: space-between;
97
+ align-items: end;
98
+ width: 100%;
99
+ > div:first-child {
100
+ flex: 1;
101
+ display: flex;
102
+ gap: 16px;
103
+ flex-direction: column;
104
+ }
105
+ }
106
+ .lang-date {
107
+ width: fit-content;
108
+ display: flex;
109
+ gap: 24px;
110
+ flex-direction: row;
111
+ color: var(--color-text-disabled-on);
112
+ font-size: var(--typography-size-body-sm);
113
+
114
+ font-weight: var(--font-weight-regular);
115
+ line-height: var(--line-height-body-sm);
116
+ text-transform: uppercase;
117
+ }
118
+ .address,
119
+ .source-logo {
120
+ display: flex;
121
+ flex-direction: row;
122
+ align-items: center;
123
+ gap: var(--scale-200);
124
+ color: var(--color-text-information);
125
+ font-size: var(--typography-size-body-sm);
126
+ font-style: normal;
127
+ font-weight: var(--font-weight-regular);
128
+ line-height: var(--line-height-body-sm);
129
+ text-decoration: underline;
130
+ a {
131
+ color: var(--color-text-information);
132
+ }
133
+ svg {
134
+ color: var(--color-text-information);
135
+ width: var(--icon-size-sm);
136
+ height: var(--icon-size-sm);
137
+ display: flex;
138
+ }
139
+ .source,
140
+ .logo {
141
+ display: flex;
142
+ flex-direction: row;
143
+ align-items: center;
144
+ gap: var(--scale-200);
145
+ }
146
+ // logo image in source block
147
+ .logo {
148
+ margin-left: auto;
149
+ background-repeat: no-repeat;
150
+ background-size: contain;
151
+ background-position: center center;
152
+ width: 76px;
153
+ height: 24px;
154
+ }
155
+ }
156
+ }
157
+ .tags,
158
+ .action {
159
+ display: flex;
160
+ flex-direction: row;
161
+ flex-wrap: wrap;
162
+ align-items: flex-start;
163
+ gap: var(--scale-200);
164
+ }
165
+ .action ::slotted(*) {
166
+ width: 100%;
167
+ padding: var(--scale-400);
168
+ border-top: var(--border-width-sm) solid var(--color-border-primary);
169
+ }
170
+ .action slot:not(:has-slotted) {
171
+ display: none;
172
+ }
173
+
174
+ &.vertical {
175
+ flex-direction: column;
176
+ header {
177
+ width: 100%;
178
+ border-bottom: var(--border-width-sm) solid var(--color-border-primary);
179
+ border-radius: var(--border-radius-lg) var(--border-radius-lg) 0 0;
180
+ &.image {
181
+ height: 167px;
182
+ }
183
+ }
184
+ main {
185
+ padding: var(--scale-600);
186
+ padding-bottom: var(--scale-800);
187
+ }
188
+
189
+ }
190
+
191
+ &.vertical,
192
+ &.billImage {
193
+ .lang-date {
194
+ width: 100%;
195
+ justify-content: space-between;
196
+ }
197
+ }
198
+
199
+ &.horizontal,
200
+ &.billImage {
201
+
202
+ main {
203
+ padding: var(--scale-600);
204
+ padding-bottom: var(--scale-800);
205
+
206
+
207
+ .source-logo .logo {
208
+ margin-left: 0px;
209
+ }
210
+ }
211
+ }
212
+ div:has(slot:not(:has-slotted)) {
213
+ display: none;
214
+ }
215
+ }