@startinblox/components-ds4go 3.3.6 โ†’ 3.3.8

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.
@@ -24,15 +24,9 @@ export class Ds4goCatalogModal extends TemsObjectHandler {
24
24
  @property({ attribute: false })
25
25
  dspStore?: any;
26
26
 
27
- @property({ attribute: false })
28
- apiGatewayConfig?: any;
29
-
30
27
  @property({ attribute: false })
31
28
  participantId?: string;
32
29
 
33
- @property({ attribute: false, type: Boolean })
34
- displayServiceTest = true;
35
-
36
30
  @state()
37
31
  negotiationStatus:
38
32
  | "idle"
@@ -60,33 +54,9 @@ export class Ds4goCatalogModal extends TemsObjectHandler {
60
54
  @state()
61
55
  maxAttempts?: number;
62
56
 
63
- @state()
64
- apiGatewayToken?: string;
65
-
66
- @state()
67
- apiGatewayError?: string;
68
-
69
- @state()
70
- gettingToken = false;
71
-
72
- @state()
73
- testingService = false;
74
-
75
- @state()
76
- testResult?: any;
77
-
78
57
  @state()
79
58
  existingAgreementChecked = false;
80
59
 
81
- @state()
82
- transferId?: string;
83
-
84
- @state()
85
- edrToken?: string;
86
-
87
- @state()
88
- edrEndpoint?: string;
89
-
90
60
  @state()
91
61
  showPolicySelection = false;
92
62
 
@@ -96,29 +66,6 @@ export class Ds4goCatalogModal extends TemsObjectHandler {
96
66
  @state()
97
67
  availablePolicies?: any[];
98
68
 
99
- @state()
100
- transferError?: string;
101
-
102
- @state()
103
- gettingEDR = false;
104
-
105
- @state()
106
- accessingData = false;
107
-
108
- @state()
109
- dataAccessAttempt?: number;
110
-
111
- @state()
112
- dataAccessMaxAttempts?: number;
113
-
114
- @state()
115
- countdown?: number;
116
-
117
- @state()
118
- dataResult?: any;
119
-
120
- @state()
121
- dataAccessError?: string;
122
69
 
123
70
  /**
124
71
  * Check for existing agreement when component connects
@@ -435,11 +382,6 @@ export class Ds4goCatalogModal extends TemsObjectHandler {
435
382
  this.contractId = undefined;
436
383
  this.negotiationId = undefined;
437
384
  this.negotiationError = undefined;
438
- this.apiGatewayToken = undefined;
439
- this.apiGatewayError = undefined;
440
- this.gettingToken = false;
441
- this.testingService = false;
442
- this.testResult = undefined;
443
385
  this.existingAgreementChecked = false;
444
386
  this.requestUpdate();
445
387
  }
@@ -833,415 +775,6 @@ export class Ds4goCatalogModal extends TemsObjectHandler {
833
775
  this.requestUpdate();
834
776
  }
835
777
 
836
- /**
837
- * Get the current OIDC access token from the session.
838
- * This retrieves the token from localStorage where oidc-client stores it.
839
- */
840
- _getOidcAccessToken(apiGatewayConfig: any): string {
841
- const { oidcAuthority, oidcClientId } = apiGatewayConfig;
842
-
843
- if (!oidcAuthority || !oidcClientId) {
844
- throw new Error(
845
- "OIDC configuration (oidcAuthority, oidcClientId) required for API Gateway",
846
- );
847
- }
848
-
849
- // The OIDC library stores the user session in localStorage
850
- const storageKey = `oidc.user:${oidcAuthority}:${oidcClientId}`;
851
- const stored = localStorage.getItem(storageKey);
852
-
853
- if (!stored) {
854
- throw new Error("No OIDC session found. Please log in first.");
855
- }
856
-
857
- try {
858
- const oidcUser = JSON.parse(stored);
859
-
860
- // Check if token is expired
861
- if (oidcUser.expires_at && oidcUser.expires_at * 1000 < Date.now()) {
862
- throw new Error("OIDC token has expired. Please log in again.");
863
- }
864
-
865
- if (!oidcUser.access_token) {
866
- throw new Error("No access token in OIDC session");
867
- }
868
-
869
- return oidcUser.access_token;
870
- } catch (e) {
871
- if (e instanceof SyntaxError) {
872
- throw new Error("Failed to parse OIDC session data");
873
- }
874
- throw e;
875
- }
876
- }
877
-
878
- async _getApiGatewayToken(
879
- apiGatewayConfig: any,
880
- accessToken: string,
881
- contractAgreementId: string,
882
- ): Promise<string> {
883
- const { apiGatewayBaseUrl } = apiGatewayConfig;
884
-
885
- if (!apiGatewayBaseUrl) {
886
- throw new Error("API Gateway base URL not configured");
887
- }
888
-
889
- // Use the TEMS API Gateway token endpoint
890
- const tokenUrl = `${apiGatewayBaseUrl}/temsapigateway/token`;
891
-
892
- const response = await fetch(tokenUrl, {
893
- method: "POST",
894
- headers: {
895
- "Content-Type": "application/json",
896
- Authorization: `Bearer ${accessToken}`,
897
- },
898
- body: JSON.stringify({
899
- agreementId: contractAgreementId,
900
- }),
901
- });
902
-
903
- if (!response.ok) {
904
- const errorText = await response.text();
905
- console.error("โŒ Failed to get API Gateway token:", {
906
- status: response.status,
907
- statusText: response.statusText,
908
- errorText,
909
- });
910
- throw new Error(
911
- `Failed to get API Gateway token: ${response.status} - ${errorText}`,
912
- );
913
- }
914
-
915
- const data = await response.json();
916
- // Support multiple possible field names for the token
917
- const token = data.apiGatewayToken || data.token || data.access_token;
918
-
919
- if (!token) {
920
- console.error("โŒ No token found in response:", data);
921
- throw new Error(
922
- "API Gateway response did not contain a token. Response keys: " +
923
- Object.keys(data).join(", "),
924
- );
925
- }
926
-
927
- return token;
928
- }
929
-
930
- async _getGatewayToken() {
931
- try {
932
- this.gettingToken = true;
933
- this.apiGatewayError = undefined;
934
- this.requestUpdate();
935
-
936
- // Use API Gateway configuration passed as property
937
- if (!this.apiGatewayConfig) {
938
- throw new Error(
939
- "API Gateway not configured. Please provide api-gateway-config attribute.",
940
- );
941
- }
942
-
943
- const apiGatewayConfig = this.apiGatewayConfig;
944
-
945
- if (!this.contractId) {
946
- throw new Error(
947
- "No contract ID available. Please complete contract negotiation first.",
948
- );
949
- }
950
-
951
- // Step 1: Get access token from current OIDC session
952
- const oidcAccessToken = this._getOidcAccessToken(apiGatewayConfig);
953
-
954
- // Step 2: Get API Gateway token using the contract agreement ID
955
- const apiGatewayToken = await this._getApiGatewayToken(
956
- apiGatewayConfig,
957
- oidcAccessToken,
958
- this.contractId,
959
- );
960
-
961
- this.apiGatewayToken = apiGatewayToken;
962
- this.requestUpdate();
963
- } catch (error) {
964
- console.error("Failed to get API Gateway token:", error);
965
- this.apiGatewayError = (error as Error).message;
966
- } finally {
967
- this.gettingToken = false;
968
- this.requestUpdate();
969
- }
970
- }
971
-
972
- async _testService() {
973
- try {
974
- this.testingService = true;
975
- this.apiGatewayError = undefined;
976
- this.testResult = undefined;
977
- this.requestUpdate();
978
-
979
- // Check if we have the API Gateway token
980
- if (!this.apiGatewayToken) {
981
- throw new Error(
982
- 'No API Gateway token available. Please click "Get gateway token" first.',
983
- );
984
- }
985
-
986
- const apiGatewayToken = this.apiGatewayToken;
987
-
988
- // Step 3: Access the service via API Gateway
989
- // The service endpoint URL from dcat:endpointURL already includes the full API Gateway path
990
- const serviceEndpointUrl = (this.object as any).url;
991
-
992
- if (!serviceEndpointUrl) {
993
- throw new Error(
994
- "No service endpoint URL found in service object. " +
995
- "The dcat:service in the self-description must include a dcat:endpointURL field. " +
996
- 'Example: "dcat:endpointURL": "https://participant-a.tems-dataspace.eu/apigateway/v2/store/inventory"',
997
- );
998
- }
999
-
1000
- // The dcat:endpointURL already points to the correct URL with API Gateway included
1001
- // No need to reconstruct - use it directly
1002
-
1003
- const response = await fetch(serviceEndpointUrl, {
1004
- method: "GET",
1005
- headers: {
1006
- "X-API-Gateway-Token": apiGatewayToken,
1007
- },
1008
- });
1009
-
1010
- if (!response.ok) {
1011
- const errorText = await response.text();
1012
- throw new Error(
1013
- `Failed to fetch data via API Gateway: ${response.status} - ${errorText}`,
1014
- );
1015
- }
1016
-
1017
- const data = await response.json();
1018
- this.testResult = data;
1019
- } catch (error) {
1020
- console.error("โŒ Service test failed:", error);
1021
- this.apiGatewayError = (error as Error).message;
1022
- } finally {
1023
- this.testingService = false;
1024
- this.requestUpdate();
1025
- }
1026
- }
1027
-
1028
- // ============================================================================
1029
- // EDR (Endpoint Data Reference) Data Access Methods
1030
- // ============================================================================
1031
- // These methods provide UI coordination for EDR-based data access when no
1032
- // API Gateway is configured. They delegate business logic to the
1033
- // DataspaceConnectorStore (sib-core) and focus on UI state management.
1034
- //
1035
- // Architecture:
1036
- // - tems-modal: UI layer (state, progress, errors, user interaction)
1037
- // - dspStore (DataspaceConnectorStore): Business logic (HTTP calls, polling, auth)
1038
- //
1039
- // Flow:
1040
- // 1. _initiateEDRTransfer() โ†’ dspStore.initiateEDRTransfer() + getEDRToken()
1041
- // 2. _accessData() โ†’ _fetchDataWithLongPolling() โ†’ dspStore.fetchWithEDRToken()
1042
- // ============================================================================
1043
-
1044
- /**
1045
- * Initiate EDR transfer for HTTP Pull data access
1046
- * Delegates to the DataspaceConnectorStore
1047
- */
1048
- async _initiateEDRTransfer() {
1049
- try {
1050
- this.gettingEDR = true;
1051
- this.transferError = undefined;
1052
- this.requestUpdate();
1053
-
1054
- // Use the DSP store passed as property
1055
- if (!this.dspStore) {
1056
- throw new Error("DSP connector not configured.");
1057
- }
1058
-
1059
- const obj = this.object as any;
1060
- const assetId = obj.datasetId || obj.assetId;
1061
- const counterPartyAddress = obj.counterPartyAddress;
1062
-
1063
- if (!assetId) {
1064
- throw new Error("No asset ID found in service object");
1065
- }
1066
-
1067
- if (!counterPartyAddress) {
1068
- throw new Error("No provider endpoint address found");
1069
- }
1070
-
1071
- if (!this.contractId) {
1072
- throw new Error(
1073
- "No contract agreement available. Please complete contract negotiation first.",
1074
- );
1075
- }
1076
-
1077
- // Get providerParticipantId to properly key the agreement mapping
1078
- const providerId =
1079
- obj.counterPartyId || obj._providerParticipantId || obj._provider || "";
1080
-
1081
- // Store delegates to DataspaceConnectorStore.initiateEDRTransfer()
1082
- // which handles the transfer process creation
1083
- const transferId = await this.dspStore.initiateEDRTransfer(
1084
- assetId,
1085
- counterPartyAddress,
1086
- this.contractId,
1087
- providerId,
1088
- );
1089
-
1090
- // Store delegates to DataspaceConnectorStore.getEDRToken()
1091
- // which handles polling (10 attempts ร— 2s) and returns EDR data address
1092
- const edrDataAddress = await this.dspStore.getEDRToken(transferId);
1093
-
1094
- if (!edrDataAddress) {
1095
- throw new Error("Failed to retrieve EDR token");
1096
- }
1097
-
1098
- // Transform localhost endpoint to public provider address if needed
1099
- let transformedEndpoint = edrDataAddress.endpoint;
1100
- if (
1101
- transformedEndpoint.includes("localhost") ||
1102
- transformedEndpoint.includes("127.0.0.1")
1103
- ) {
1104
- const providerBase = counterPartyAddress.replace("/protocol", "");
1105
- const localUrl = new URL(transformedEndpoint);
1106
- transformedEndpoint = `${providerBase}${localUrl.pathname}${localUrl.search}`;
1107
- }
1108
-
1109
- // Store the EDR information for data access
1110
- this.transferId = transferId;
1111
- this.edrToken = edrDataAddress.authorization;
1112
- this.edrEndpoint = transformedEndpoint;
1113
- } catch (error) {
1114
- console.error("โŒ EDR transfer failed:", error);
1115
- this.transferError = (error as Error).message;
1116
- } finally {
1117
- this.gettingEDR = false;
1118
- this.requestUpdate();
1119
- }
1120
- }
1121
-
1122
- /**
1123
- * Access data using EDR token with long-polling strategy
1124
- * Delegates to the DataspaceConnectorStore for actual data fetching
1125
- */
1126
- async _accessData() {
1127
- try {
1128
- this.accessingData = true;
1129
- this.dataAccessError = undefined;
1130
- this.dataResult = undefined;
1131
- this.requestUpdate();
1132
-
1133
- if (!this.dspStore) {
1134
- throw new Error("DSP connector not configured.");
1135
- }
1136
-
1137
- if (!this.edrToken || !this.edrEndpoint) {
1138
- throw new Error(
1139
- 'No EDR token available. Please click "Get EDR Token" first.',
1140
- );
1141
- }
1142
-
1143
- const obj = this.object as any;
1144
- const counterPartyAddress = obj.counterPartyAddress;
1145
-
1146
- // Transform localhost endpoint to public provider address if needed
1147
- let transformedEndpoint = this.edrEndpoint;
1148
- if (
1149
- transformedEndpoint.includes("localhost") ||
1150
- transformedEndpoint.includes("127.0.0.1")
1151
- ) {
1152
- const providerBase = counterPartyAddress.replace("/protocol", "");
1153
- const localUrl = new URL(transformedEndpoint);
1154
- transformedEndpoint = `${providerBase}${localUrl.pathname}${localUrl.search}`;
1155
- }
1156
-
1157
- // Build EDR data address object for the store
1158
- const edrDataAddress = {
1159
- endpoint: transformedEndpoint,
1160
- authorization: this.edrToken,
1161
- authType: "bearer",
1162
- type: "https://w3id.org/idsa/v4.1/HTTP",
1163
- endpointType: "https://w3id.org/idsa/v4.1/HTTP",
1164
- };
1165
-
1166
- // Implement UI-level long-polling with progress feedback
1167
- // The store's fetchWithEDRToken handles the actual HTTP request
1168
- const data = await this._fetchDataWithLongPolling(edrDataAddress);
1169
-
1170
- this.dataResult = data;
1171
- } catch (error) {
1172
- console.error("โŒ Data access failed:", error);
1173
- this.dataAccessError = (error as Error).message;
1174
- } finally {
1175
- this.accessingData = false;
1176
- this.dataAccessAttempt = undefined;
1177
- this.dataAccessMaxAttempts = undefined;
1178
- this.countdown = undefined;
1179
- this.requestUpdate();
1180
- }
1181
- }
1182
-
1183
- /**
1184
- * Fetch data with long-polling retry logic and UI progress updates
1185
- * Delegates actual fetching to DataspaceConnectorStore.fetchWithEDRToken()
1186
- */
1187
- async _fetchDataWithLongPolling(
1188
- edrDataAddress: any,
1189
- maxAttempts = 12, // 12 attempts over 1 minute
1190
- pollInterval = 5000, // 5 seconds between attempts
1191
- ): Promise<any> {
1192
- this.dataAccessMaxAttempts = maxAttempts;
1193
-
1194
- for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1195
- this.dataAccessAttempt = attempt;
1196
- this.requestUpdate();
1197
-
1198
- try {
1199
- // Delegate to store's fetchWithEDRToken method
1200
- // Store handles the actual HTTP request with proper headers
1201
- const data = await this.dspStore.fetchWithEDRToken(edrDataAddress);
1202
-
1203
- if (data) {
1204
- return data;
1205
- }
1206
- } catch (error) {
1207
- const errorMessage = (error as Error).message;
1208
- console.warn(
1209
- `โš ๏ธ Data access attempt ${attempt}/${maxAttempts} failed:`,
1210
- errorMessage,
1211
- );
1212
-
1213
- // Check for specific error types that might resolve with waiting
1214
- const isRetryableError =
1215
- errorMessage.includes("404") ||
1216
- errorMessage.includes("503") ||
1217
- errorMessage.includes("502") ||
1218
- errorMessage.includes("timeout") ||
1219
- errorMessage.includes("not ready") ||
1220
- errorMessage.includes("processing");
1221
-
1222
- // If this is the last attempt or not a retryable error, throw
1223
- if (attempt === maxAttempts || !isRetryableError) {
1224
- console.error(`โŒ Final data access attempt failed: ${errorMessage}`);
1225
- throw error;
1226
- }
1227
- }
1228
-
1229
- // Wait before next attempt (except on the last iteration)
1230
- if (attempt < maxAttempts) {
1231
- // Show countdown in UI during wait
1232
- for (let countdown = pollInterval / 1000; countdown > 0; countdown--) {
1233
- this.countdown = countdown;
1234
- this.requestUpdate();
1235
- await new Promise((resolve) => setTimeout(resolve, 1000));
1236
- }
1237
- this.countdown = undefined;
1238
- }
1239
- }
1240
-
1241
- throw new Error(
1242
- `Data access failed after ${maxAttempts} attempts over ${(maxAttempts * pollInterval) / 1000} seconds`,
1243
- );
1244
- }
1245
778
 
1246
779
  _renderBoolean(field: boolean): TemplateResultOrSymbol {
1247
780
  if (field) {
@@ -1545,155 +1078,16 @@ export class Ds4goCatalogModal extends TemsObjectHandler {
1545
1078
  </div>`;
1546
1079
  }
1547
1080
 
1548
- _renderApiAccessGuide(): TemplateResultOrSymbol {
1549
- // Only show for services with API Gateway configuration
1550
- if (!this.apiGatewayConfig) {
1551
- return nothing;
1552
- }
1553
-
1554
- const obj = this.object as any;
1555
- const serviceUrl = obj.url;
1556
- const agreementId = this.contractId || "<your-agreement-id>";
1557
-
1558
- const { keycloakUrl, realm, clientId, apiGatewayBaseUrl } =
1559
- this.apiGatewayConfig;
1560
-
1561
- return html`
1562
- <div style="margin-top: 16px; padding: 16px; background: #f5f5f5; border-radius: 8px; font-family: monospace; font-size: 0.9em;">
1563
- ${this._renderDivision("h4", msg("API Access Guide"))}
1564
-
1565
- <div style="margin-bottom: 16px;">
1566
- <strong>Step 1: Get Keycloak Access Token</strong>
1567
- <pre style="background: #fff; padding: 12px; border-radius: 4px; overflow-x: auto; margin-top: 8px;"><code>curl -X POST '${keycloakUrl}/realms/${realm}/protocol/openid-connect/token' \\
1568
- -H 'Content-Type: application/x-www-form-urlencoded' \\
1569
- -d 'grant_type=password' \\
1570
- -d 'client_id=${clientId}' \\
1571
- -d 'client_secret=<your-client-secret>' \\
1572
- -d 'username=<your-username>' \\
1573
- -d 'password=<your-password>' \\
1574
- -d 'scope=openid'</code></pre>
1575
- <div style="margin-top: 8px; color: #666; font-size: 0.9em;">
1576
- Response: <code>{ "access_token": "eyJhbGc...", ... }</code>
1577
- </div>
1578
- </div>
1579
-
1580
- <div style="margin-bottom: 16px;">
1581
- <strong>Step 2: Get API Gateway Token</strong>
1582
- <pre style="background: #fff; padding: 12px; border-radius: 4px; overflow-x: auto; margin-top: 8px;"><code>curl -X POST '${apiGatewayBaseUrl}/token' \\
1583
- -H 'Content-Type: application/json' \\
1584
- -H 'Authorization: Bearer <access_token_from_step_1>' \\
1585
- -d '{
1586
- "agreementId": "${agreementId}"
1587
- }'</code></pre>
1588
- <div style="margin-top: 8px; color: #666; font-size: 0.9em;">
1589
- Response: <code>{ "apiGatewayToken": "xxx...", ... }</code>
1590
- </div>
1591
- </div>
1592
-
1593
- <div style="margin-bottom: 16px;">
1594
- <strong>Step 3: Call the Service</strong>
1595
- <pre style="background: #fff; padding: 12px; border-radius: 4px; overflow-x: auto; margin-top: 8px;"><code>curl -X GET '${serviceUrl || "<service-endpoint>"}' \\
1596
- -H 'X-API-Gateway-Token: <apiGatewayToken_from_step_2>'</code></pre>
1597
- <div style="margin-top: 8px; color: #666; font-size: 0.9em;">
1598
- ${
1599
- this.negotiationStatus === "granted" && this.contractId
1600
- ? html`โœ… <strong>Agreement ID:</strong>
1601
- <code>${this.contractId}</code>`
1602
- : html`โš ๏ธ You need to complete contract negotiation first to get
1603
- an agreement ID.`
1604
- }
1605
- </div>
1606
- </div>
1607
-
1608
- ${
1609
- this.apiGatewayToken
1610
- ? html`
1611
- <div
1612
- style="margin-top: 16px; padding: 12px; background: #e8f5e9; border-radius: 4px;"
1613
- >
1614
- <strong>๐ŸŽ‰ Your Current Session:</strong>
1615
- <div style="margin-top: 8px;">
1616
- <code
1617
- style="word-break: break-all; display: block; background: #fff; padding: 8px; border-radius: 4px;"
1618
- >
1619
- X-API-Gateway-Token:
1620
- ${this.apiGatewayToken.substring(0, 40)}...
1621
- </code>
1622
- </div>
1623
- </div>
1624
- `
1625
- : nothing
1626
- }
1627
- </div>
1628
- `;
1629
- }
1630
1081
 
1631
1082
  _renderServiceSpecificModal(): TemplateResultOrSymbol {
1632
1083
  return html` ${this._renderColumns(
1633
- html`${this.renderTemplateWhenWith(["long_description"], () =>
1634
- this._renderTitleValueDivision(
1635
- msg("Features & Functionalities"),
1636
- this.object.long_description,
1637
- ),
1638
- )}${this.renderTemplateWhenWith(
1639
- [["is_in_app", "is_external", "is_api"]],
1640
- () =>
1641
- html`${this._renderDivision("h4", msg("Installation Possible"))}
1642
- <div class="badges">
1643
- ${this.renderTemplateWhenWith(
1644
- ["is_in_app"],
1645
- () =>
1646
- html`${this._renderBadge("success", msg("In-App"))}</div>`,
1647
- )}
1648
- ${this.renderTemplateWhenWith(
1649
- ["is_external"],
1650
- () =>
1651
- html`${this._renderBadge("success", msg("External"))}</div>`,
1652
- )}
1653
- ${this.renderTemplateWhenWith(
1654
- ["is_api"],
1655
- () => html`${this._renderBadge("success", msg("API"))}</div>`,
1656
- )}
1657
- </div>`,
1658
- )}${this.renderTemplateWhenWith(
1659
- ["developper", "developper.url"],
1660
- () =>
1661
- html`${this._renderDivision("h4", msg("Developper"))}
1662
- <img
1663
- src="${this.object.developper.url}"
1664
- alt=${this.object.developper.name}
1665
- class="default-img"
1666
- />`,
1667
- )}${this.renderTemplateWhenWith(["release_date"], () =>
1084
+ html`${this.renderTemplateWhenWith(["release_date"], () =>
1668
1085
  this._renderTitleValueDivision(
1669
1086
  msg("Release Date"),
1670
1087
  formatDate(this.object.release_date),
1671
1088
  ),
1672
- )}${this.renderTemplateWhenWith(["last_update"], () =>
1673
- this._renderTitleValueDivision(
1674
- msg("Last Update"),
1675
- formatDate(this.object.last_update),
1676
- ),
1677
- )}${this.renderTemplateWhenWith(["url"], () =>
1678
- this._renderButton(
1679
- undefined,
1680
- "sm",
1681
- "Access the service",
1682
- "outline-gray",
1683
- this.object.url,
1684
- ),
1685
- )}${this.renderTemplateWhenWith(["documentation_url"], () =>
1686
- this._renderButton(
1687
- undefined,
1688
- "sm",
1689
- "Read the full documentation",
1690
- "outline-gray",
1691
- this.object.documentation_url,
1692
- ),
1693
1089
  )}
1694
- ${this._renderPolicyDescription()} ${this._renderAgreementInfo()}
1695
- ${this._renderApiAccessGuide()} ${this._renderApiTestingSection()}
1696
- ${this._renderEDRDataAccessSection()}`,
1090
+ ${this._renderPolicyDescription()} ${this._renderAgreementInfo()}`,
1697
1091
  )}`;
1698
1092
  }
1699
1093
 
@@ -1871,294 +1265,6 @@ export class Ds4goCatalogModal extends TemsObjectHandler {
1871
1265
  `;
1872
1266
  }
1873
1267
 
1874
- _renderEDRDataAccessSection(): TemplateResultOrSymbol {
1875
- // Only show for services with negotiated access and NO API Gateway config
1876
- if (this.negotiationStatus !== "granted" || this.apiGatewayConfig) {
1877
- return nothing;
1878
- }
1879
-
1880
- const storedInfo = this._loadAgreementInfo();
1881
- const agreementDate = storedInfo?.timestamp
1882
- ? new Date(storedInfo.timestamp).toLocaleString()
1883
- : null;
1884
-
1885
- return html`
1886
- <div
1887
- style="margin-top: 24px; padding: 16px; background: #f5f5f5; border-radius: 8px;"
1888
- >
1889
- ${this._renderDivision("h4", msg("EDR Data Access (HTTP Pull)"))}
1890
- ${this.contractId
1891
- ? html`
1892
- <div
1893
- style="font-size: 0.85em; opacity: 0.8; padding: 8px; background: rgba(0,128,0,0.05); border-radius: 4px; margin-bottom: 12px;"
1894
- >
1895
- <div><strong>Agreement ID:</strong> ${this.contractId}</div>
1896
- ${agreementDate
1897
- ? html`<div style="margin-top: 4px;">
1898
- <strong>Agreed on:</strong> ${agreementDate}
1899
- </div>`
1900
- : nothing}
1901
- ${this.transferId
1902
- ? html`<div style="margin-top: 4px;">
1903
- <strong>Transfer ID:</strong> ${this.transferId}
1904
- </div>`
1905
- : nothing}
1906
- </div>
1907
- `
1908
- : nothing}
1909
-
1910
- <div style="display: flex; flex-direction: column; gap: 8px;">
1911
- <!-- Step 1: Get EDR Token -->
1912
- ${this.gettingEDR
1913
- ? html`<tems-button disabled="">
1914
- <span
1915
- style="display: inline-block; animation: spin 1s linear infinite;"
1916
- >โณ</span
1917
- >
1918
- ${msg("Getting EDR token...")}
1919
- </tems-button>`
1920
- : !this.edrToken
1921
- ? html`<tems-button
1922
- @click=${this._initiateEDRTransfer}
1923
- type="outline-gray"
1924
- >
1925
- ๐Ÿš€ ${msg("Get EDR Token")}
1926
- </tems-button>`
1927
- : html`
1928
- <div
1929
- style="color: green; font-size: 0.85em; padding: 8px; background: rgba(0,128,0,0.05); border-radius: 4px;"
1930
- >
1931
- <strong>โœ… ${msg("EDR Token Ready")}</strong>
1932
- ${this.edrEndpoint
1933
- ? html`<div
1934
- style="margin-top: 4px; font-family: monospace; font-size: 0.8em; word-break: break-all;"
1935
- >
1936
- <strong>Endpoint:</strong> ${this.edrEndpoint}
1937
- </div>`
1938
- : nothing}
1939
- </div>
1940
- `}
1941
- ${this.transferError
1942
- ? html`
1943
- <div
1944
- style="color: red; font-size: 0.85em; padding: 8px; background: rgba(255,0,0,0.05); border-radius: 4px;"
1945
- >
1946
- โš ๏ธ ${this.transferError}
1947
- <tems-button
1948
- @click=${this._initiateEDRTransfer}
1949
- type="outline-gray"
1950
- style="margin-top: 8px;"
1951
- >
1952
- ๐Ÿ”„ ${msg("Retry")}
1953
- </tems-button>
1954
- </div>
1955
- `
1956
- : nothing}
1957
-
1958
- <!-- Step 2: Access Data -->
1959
- ${this.edrToken
1960
- ? this.accessingData
1961
- ? html`<tems-button disabled="">
1962
- <span
1963
- style="display: inline-block; animation: spin 1s linear infinite;"
1964
- >๐Ÿ“ก</span
1965
- >
1966
- ${msg("Accessing data")}
1967
- ${this.dataAccessAttempt
1968
- ? ` (${this.dataAccessAttempt}/${this.dataAccessMaxAttempts})`
1969
- : "..."}
1970
- ${this.countdown
1971
- ? html`<br /><span style="font-size: 0.8em;"
1972
- >โณ Next retry in ${this.countdown}s</span
1973
- >`
1974
- : nothing}
1975
- </tems-button>`
1976
- : html`<tems-button @click=${this._accessData} type="primary">
1977
- ๐Ÿ“ ${msg("Access Data")}
1978
- </tems-button>`
1979
- : nothing}
1980
- ${this.dataAccessError
1981
- ? html`
1982
- <div
1983
- style="color: red; font-size: 0.85em; padding: 8px; background: rgba(255,0,0,0.05); border-radius: 4px;"
1984
- >
1985
- โš ๏ธ ${this.dataAccessError}
1986
- </div>
1987
- `
1988
- : nothing}
1989
- ${this.dataResult
1990
- ? html`
1991
- <div
1992
- style="color: green; font-size: 0.85em; padding: 8px; background: rgba(0,128,0,0.05); border-radius: 4px; max-height: 300px; overflow-y: auto;"
1993
- >
1994
- <strong>โœ… ${msg("Data retrieved successfully:")}</strong>
1995
- <pre
1996
- style="margin-top: 8px; font-size: 0.9em; white-space: pre-wrap; word-wrap: break-word; background: white; padding: 8px; border-radius: 4px;"
1997
- >
1998
- ${JSON.stringify(this.dataResult, null, 2)}</pre
1999
- >
2000
- </div>
2001
- `
2002
- : nothing}
2003
- </div>
2004
-
2005
- <div
2006
- style="margin-top: 16px; padding: 12px; background: rgba(0,0,0,0.05); border-radius: 4px; font-size: 0.85em;"
2007
- >
2008
- <div style="margin-bottom: 4px;">
2009
- <strong>โ„น๏ธ ${msg("About EDR (Endpoint Data Reference)")}</strong>
2010
- </div>
2011
- <div>
2012
- ${msg(
2013
- "EDR is the Eclipse Dataspace Protocol's HTTP Pull mechanism for accessing data. The EDR token provides temporary, authorized access to the provider's data endpoint.",
2014
- )}
2015
- </div>
2016
- </div>
2017
-
2018
- ${storedInfo
2019
- ? html`
2020
- <div
2021
- style="margin-top: 12px; padding-top: 12px; border-top: 1px solid rgba(0,0,0,0.1);"
2022
- >
2023
- <button
2024
- @click=${this._renewContract}
2025
- style="font-size: 0.85em; color: #666; background: none; border: none; cursor: pointer; text-decoration: underline; padding: 0;"
2026
- >
2027
- ๐Ÿ”„ ${msg("Renegotiate contract")}
2028
- </button>
2029
- </div>
2030
- `
2031
- : nothing}
2032
- </div>
2033
-
2034
- <style>
2035
- @keyframes spin {
2036
- 0% {
2037
- transform: rotate(0deg);
2038
- }
2039
- 100% {
2040
- transform: rotate(360deg);
2041
- }
2042
- }
2043
- </style>
2044
- `;
2045
- }
2046
-
2047
- _renderApiTestingSection(): TemplateResultOrSymbol {
2048
- // Only show for services with negotiated access AND API Gateway config
2049
- if (this.negotiationStatus !== "granted" || !this.apiGatewayConfig) {
2050
- return nothing;
2051
- }
2052
-
2053
- const storedInfo = this._loadAgreementInfo();
2054
- const agreementDate = storedInfo?.timestamp
2055
- ? new Date(storedInfo.timestamp).toLocaleString()
2056
- : null;
2057
-
2058
- return html`
2059
- <div
2060
- style="margin-top: 24px; padding: 16px; background: #f5f5f5; border-radius: 8px;"
2061
- >
2062
- ${this._renderDivision("h4", msg("API Testing"))}
2063
- ${this.contractId
2064
- ? html`
2065
- <div
2066
- style="font-size: 0.85em; opacity: 0.8; padding: 8px; background: rgba(0,128,0,0.05); border-radius: 4px; margin-bottom: 12px;"
2067
- >
2068
- <div><strong>Agreement ID:</strong> ${this.contractId}</div>
2069
- ${agreementDate
2070
- ? html`<div style="margin-top: 4px;">
2071
- <strong>Agreed on:</strong> ${agreementDate}
2072
- </div>`
2073
- : nothing}
2074
- </div>
2075
- `
2076
- : nothing}
2077
-
2078
- <div style="display: flex; flex-direction: column; gap: 8px;">
2079
- <!-- Button 1: Get Gateway Token -->
2080
- ${this.gettingToken
2081
- ? html`<tems-button disabled="">
2082
- ${msg("Getting token...")}
2083
- </tems-button>`
2084
- : html`<tems-button
2085
- @click=${this._getGatewayToken}
2086
- type="outline-gray"
2087
- ?disabled=${!!this.apiGatewayToken}
2088
- >
2089
- ๐Ÿ”‘ ${msg("Get gateway token")}
2090
- </tems-button>`}
2091
-
2092
- <!-- Button 2: Test Service (only if displayServiceTest is enabled) -->
2093
- ${this.displayServiceTest
2094
- ? this.testingService
2095
- ? html`<tems-button disabled="">
2096
- ${msg("Testing service...")}
2097
- </tems-button>`
2098
- : html`<tems-button
2099
- @click=${this._testService}
2100
- type="primary"
2101
- ?disabled=${!this.apiGatewayToken}
2102
- >
2103
- ๐Ÿงช ${msg("Test service")}
2104
- </tems-button>`
2105
- : nothing}
2106
- ${this.apiGatewayError
2107
- ? html`
2108
- <div style="color: red; font-size: 0.85em;">
2109
- โš ๏ธ ${this.apiGatewayError}
2110
- </div>
2111
- `
2112
- : nothing}
2113
- ${this.apiGatewayToken
2114
- ? html`
2115
- <div
2116
- style="color: green; font-size: 0.85em; padding: 8px; background: rgba(0,128,0,0.05); border-radius: 4px;"
2117
- >
2118
- <div style="margin-bottom: 4px;">
2119
- <strong>โœ… ${msg("API Gateway token obtained")}</strong>
2120
- </div>
2121
- <div
2122
- style="word-break: break-all; font-family: monospace; font-size: 0.9em;"
2123
- >
2124
- <strong>X-API-Gateway-Token:</strong><br />
2125
- ${this.apiGatewayToken}
2126
- </div>
2127
- </div>
2128
- `
2129
- : nothing}
2130
- ${this.displayServiceTest && this.testResult
2131
- ? html`
2132
- <div
2133
- style="color: green; font-size: 0.85em; padding: 8px; background: rgba(0,128,0,0.05); border-radius: 4px; max-height: 200px; overflow-y: auto;"
2134
- >
2135
- <strong>โœ… ${msg("Service response:")}</strong>
2136
- <pre
2137
- style="margin-top: 4px; font-size: 0.9em; white-space: pre-wrap; word-wrap: break-word;"
2138
- >
2139
- ${JSON.stringify(this.testResult, null, 2)}</pre
2140
- >
2141
- </div>
2142
- `
2143
- : nothing}
2144
- ${storedInfo
2145
- ? html`
2146
- <div
2147
- style="margin-top: 8px; padding-top: 8px; border-top: 1px solid rgba(0,0,0,0.1);"
2148
- >
2149
- <button
2150
- @click=${this._renewContract}
2151
- style="font-size: 0.85em; color: #666; background: none; border: none; cursor: pointer; text-decoration: underline; padding: 0;"
2152
- >
2153
- ๐Ÿ”„ ${msg("Renegotiate contract")}
2154
- </button>
2155
- </div>
2156
- `
2157
- : nothing}
2158
- </div>
2159
- </div>
2160
- `;
2161
- }
2162
1268
 
2163
1269
  _closeModal() {
2164
1270
  this.dispatchEvent(new CustomEvent("close"));