@eodash/eodash 5.0.0-rc.3 → 5.1.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.
Files changed (155) hide show
  1. package/README.md +1 -0
  2. package/core/client/App.vue +8 -2
  3. package/core/client/asWebComponent.js +5 -5
  4. package/core/client/components/DashboardLayout.vue +42 -25
  5. package/core/client/components/EodashOverlay.vue +1 -1
  6. package/core/client/components/ErrorAlert.vue +2 -2
  7. package/core/client/components/Footer.vue +4 -4
  8. package/core/client/components/Header.vue +3 -3
  9. package/core/client/components/MobileLayout.vue +9 -10
  10. package/core/client/composables/DefineEodash.js +38 -43
  11. package/core/client/composables/DefineTemplate.js +4 -2
  12. package/core/client/composables/DefineWidgets.js +14 -8
  13. package/core/client/composables/index.js +273 -23
  14. package/core/client/eodashSTAC/EodashCollection.js +80 -47
  15. package/core/client/eodashSTAC/helpers.js +136 -27
  16. package/core/client/eodashSTAC/parquet.js +145 -0
  17. package/core/client/eodashSTAC/triggers.js +6 -3
  18. package/core/client/plugins/index.js +4 -3
  19. package/core/client/plugins/vuetify.js +3 -0
  20. package/core/client/store/actions.js +21 -4
  21. package/core/client/store/stac.js +93 -56
  22. package/core/client/store/states.js +15 -5
  23. package/core/client/types.ts +59 -43
  24. package/core/client/utils/index.js +79 -0
  25. package/core/client/utils/keys.js +2 -2
  26. package/core/client/utils/states.js +30 -5
  27. package/core/client/views/Dashboard.vue +36 -32
  28. package/core/client/vite-env.d.ts +7 -0
  29. package/dist/client/{DashboardLayout-t_PavJPO.js → DashboardLayout-ByVs1DrY.js} +23 -12
  30. package/dist/client/{DynamicWebComponent-y07rVJch.js → DynamicWebComponent-C3W7HSQm.js} +1 -1
  31. package/dist/client/{EodashDatePicker-CcOfyzGD.js → EodashDatePicker-BIAf1sMT.js} +59 -32
  32. package/dist/client/{EodashItemFilter-B9HCvIMi.js → EodashItemFilter-DPznh8UB.js} +20 -10
  33. package/dist/client/{EodashLayerControl-KStn7Nb_.js → EodashLayerControl-Bhxjw4V2.js} +29 -16
  34. package/dist/client/EodashLayoutSwitcher-C5qTEffW.js +61 -0
  35. package/dist/client/EodashMapBtns-WoGq8MuV.js +173 -0
  36. package/dist/client/{EodashStacInfo-C_hDy6Pd.js → EodashStacInfo-CSvvF2jI.js} +3 -18
  37. package/dist/client/{EodashTools-BXflvRf8.js → EodashTools-Cv1SXQ5y.js} +13 -13
  38. package/dist/client/{ExportState-C0QRemK1.js → ExportState-D-iuwaad.js} +58 -52
  39. package/dist/client/{Footer-7VGyGUAs.js → Footer-CyF0zRAk.js} +15 -13
  40. package/dist/client/{Header-BQJnXHYq.js → Header-CgD8jDKU.js} +33 -28
  41. package/dist/client/{MobileLayout-b8nQ-Vyl.js → MobileLayout-EKQ_kpSh.js} +69 -60
  42. package/dist/client/{PopUp-DgNrh9Df.js → PopUp-BsYLvWch.js} +19 -10
  43. package/dist/client/ProcessList-C2xsLU2_.js +191 -0
  44. package/dist/client/{VImg-D4eT3IQ1.js → VImg-OHe8YTs2.js} +24 -24
  45. package/dist/client/{VMain-C3hN2-H3.js → VMain-PryTLU4a.js} +7 -7
  46. package/dist/client/{VOverlay-tAeNygaA.js → VOverlay-yUn7p-Uf.js} +64 -27
  47. package/dist/client/{VTooltip-B0Q3iHMZ.js → VTooltip-DZ0fjpB3.js} +13 -10
  48. package/dist/client/{WidgetsContainer-CtDHfCYf.js → WidgetsContainer-B9LBadcC.js} +1 -1
  49. package/dist/client/asWebComponent-By_7_JjS.js +19193 -0
  50. package/dist/client/async-DkSu_u2K.js +740 -0
  51. package/dist/client/eo-dash.js +1 -1
  52. package/dist/client/{forwardRefs-CIFAqXaZ.js → forwardRefs-BXxrv98s.js} +31 -4
  53. package/dist/client/handling-CgmFXkW6.js +1212 -0
  54. package/dist/client/helpers-Dy0Q13tP.js +4534 -0
  55. package/dist/client/{index-DvcUndod.js → index-BuhOHXKv.js} +2 -4
  56. package/dist/client/{index-BQ16n4Sk.js → index-Ch_HchK3.js} +39 -32
  57. package/dist/client/{index-Cv7HBz49.js → index-Dqj4tbx2.js} +2 -2
  58. package/dist/client/index-skjhlH8u.js +376 -0
  59. package/dist/client/{ssrBoot-BP7SYRyC.js → ssrBoot-Zgc_Ttvi.js} +2 -2
  60. package/dist/client/templates.js +850 -0
  61. package/dist/client/transition-C98Yn4Vo.js +40 -0
  62. package/dist/node/cli.js +16 -6
  63. package/dist/node/types.d.ts +1 -1
  64. package/dist/types/core/client/App.vue.d.ts +2 -2
  65. package/dist/types/core/client/asWebComponent.d.ts +1 -1
  66. package/dist/types/core/client/components/DynamicWebComponent.vue.d.ts +1 -3
  67. package/dist/types/core/client/components/Footer.vue.d.ts +1 -105
  68. package/dist/types/core/client/components/IframeWrapper.vue.d.ts +1 -1
  69. package/dist/types/core/client/components/MobileLayout.vue.d.ts +1 -324
  70. package/dist/types/core/client/composables/DefineEodash.d.ts +2 -2
  71. package/dist/types/core/client/composables/DefineTemplate.d.ts +1 -1
  72. package/dist/types/core/client/composables/DefineWidgets.d.ts +4 -4
  73. package/dist/types/core/client/composables/index.d.ts +24 -2
  74. package/dist/types/core/client/eodashSTAC/EodashCollection.d.ts +9 -6
  75. package/dist/types/core/client/eodashSTAC/helpers.d.ts +20 -5
  76. package/dist/types/core/client/eodashSTAC/parquet.d.ts +2 -0
  77. package/dist/types/core/client/plugins/vuetify.d.ts +7 -4
  78. package/dist/types/core/client/store/actions.d.ts +3 -2
  79. package/dist/types/core/client/store/stac.d.ts +16 -13
  80. package/dist/types/core/client/store/states.d.ts +14 -4
  81. package/dist/types/core/client/types.d.ts +45 -30
  82. package/dist/types/core/client/utils/index.d.ts +2 -0
  83. package/dist/types/core/client/utils/keys.d.ts +4 -4
  84. package/dist/types/core/client/utils/states.d.ts +59 -47
  85. package/dist/types/core/client/views/Dashboard.vue.d.ts +2 -2
  86. package/dist/types/templates/baseConfig.d.ts +4 -0
  87. package/dist/types/templates/compare.d.ts +210 -0
  88. package/dist/types/templates/expert.d.ts +151 -0
  89. package/dist/types/templates/index.d.ts +6 -0
  90. package/dist/types/templates/light.d.ts +145 -0
  91. package/dist/types/widgets/EodashDatePicker.vue.d.ts +1 -458
  92. package/dist/types/widgets/EodashItemFilter.vue.d.ts +3 -3
  93. package/dist/types/widgets/EodashLayerControl.vue.d.ts +14 -7
  94. package/dist/types/widgets/EodashLayoutSwitcher.vue.d.ts +1 -3
  95. package/dist/types/widgets/EodashMap/index.vue.d.ts +1 -4
  96. package/dist/types/widgets/EodashMapBtns.vue.d.ts +8 -8
  97. package/dist/types/widgets/EodashProcess/ProcessList.vue.d.ts +8 -1
  98. package/dist/types/widgets/EodashProcess/index.vue.d.ts +8 -4
  99. package/dist/types/widgets/EodashProcess/methods/async.d.ts +18 -18
  100. package/dist/types/widgets/EodashProcess/methods/composables.d.ts +3 -2
  101. package/dist/types/widgets/EodashProcess/methods/custom-endpoints/chart/index.d.ts +1 -0
  102. package/dist/types/widgets/EodashProcess/methods/custom-endpoints/chart/sentinelhub-endpoint.d.ts +6 -0
  103. package/dist/types/widgets/EodashProcess/methods/custom-endpoints/chart/veda-endpoint.d.ts +4 -0
  104. package/dist/types/widgets/EodashProcess/methods/custom-endpoints/layers/eoxhub-workspaces-endpoint.d.ts +5 -0
  105. package/dist/types/widgets/EodashProcess/methods/custom-endpoints/layers/index.d.ts +1 -0
  106. package/dist/types/widgets/EodashProcess/methods/handling.d.ts +12 -5
  107. package/dist/types/widgets/EodashProcess/methods/outputs.d.ts +72 -41
  108. package/dist/types/widgets/EodashProcess/methods/utils.d.ts +41 -21
  109. package/dist/types/widgets/EodashProcess/states.d.ts +11 -0
  110. package/dist/types/widgets/EodashProcess/types.d.ts +41 -0
  111. package/dist/types/widgets/EodashStacInfo.vue.d.ts +14 -14
  112. package/dist/types/widgets/EodashTools.vue.d.ts +3 -3
  113. package/dist/types/widgets/ExportState.vue.d.ts +1 -1
  114. package/dist/types/widgets/PopUp.vue.d.ts +11 -16
  115. package/dist/types/widgets/WidgetsContainer.vue.d.ts +3 -6
  116. package/package.json +53 -45
  117. package/templates/baseConfig.js +68 -0
  118. package/templates/compare.js +162 -0
  119. package/templates/expert.js +123 -0
  120. package/templates/index.js +8 -0
  121. package/templates/light.js +130 -0
  122. package/widgets/EodashDatePicker.vue +80 -31
  123. package/widgets/EodashItemFilter.vue +26 -11
  124. package/widgets/EodashLayerControl.vue +20 -11
  125. package/widgets/EodashLayoutSwitcher.vue +6 -3
  126. package/widgets/EodashMap/index.vue +3 -8
  127. package/widgets/EodashMap/methods/create-layers-config.js +4 -3
  128. package/widgets/EodashMap/methods/index.js +33 -23
  129. package/widgets/EodashMapBtns.vue +83 -41
  130. package/widgets/EodashProcess/ProcessList.vue +34 -10
  131. package/widgets/EodashProcess/index.vue +55 -20
  132. package/widgets/EodashProcess/methods/async.js +77 -59
  133. package/widgets/EodashProcess/methods/composables.js +21 -14
  134. package/widgets/EodashProcess/methods/custom-endpoints/chart/index.js +35 -0
  135. package/widgets/EodashProcess/methods/custom-endpoints/chart/sentinelhub-endpoint.js +275 -0
  136. package/widgets/EodashProcess/methods/custom-endpoints/chart/veda-endpoint.js +116 -0
  137. package/widgets/EodashProcess/methods/custom-endpoints/layers/eoxhub-workspaces-endpoint.js +94 -0
  138. package/widgets/EodashProcess/methods/custom-endpoints/layers/index.js +33 -0
  139. package/widgets/EodashProcess/methods/handling.js +127 -80
  140. package/widgets/EodashProcess/methods/outputs.js +376 -125
  141. package/widgets/EodashProcess/methods/utils.js +398 -10
  142. package/widgets/EodashProcess/states.js +13 -0
  143. package/widgets/EodashProcess/types.ts +46 -0
  144. package/widgets/EodashStacInfo.vue +2 -17
  145. package/widgets/EodashTools.vue +13 -13
  146. package/widgets/WidgetsContainer.vue +1 -1
  147. package/core/client/eodash.js +0 -454
  148. package/dist/client/EodashLayoutSwitcher-DqeFO3RN.js +0 -52
  149. package/dist/client/EodashMapBtns-5BF27qJB.js +0 -131
  150. package/dist/client/ProcessList-C62SOVO6.js +0 -484
  151. package/dist/client/asWebComponent-BJ2NWunV.js +0 -12479
  152. package/dist/client/eo-dash.css +0 -5
  153. package/dist/client/index-Da5xXX6Q.js +0 -780
  154. package/dist/client/transition-Cdb4K27U.js +0 -37
  155. package/dist/types/core/client/eodash.d.ts +0 -8
@@ -1,4 +1,3 @@
1
- import { mapEl } from "@/store/states";
2
1
  import { initProcess } from "./handling";
3
2
  import { useEventBus } from "@vueuse/core";
4
3
  import { nextTick, onMounted, watch } from "vue";
@@ -11,7 +10,7 @@ import { useOnLayersUpdate } from "@/composables";
11
10
  * @export
12
11
  * @async
13
12
  * @param {Object} params
14
- * @param {import("vue").Ref<import("stac-ts").StacCollection>} params.selectedStac
13
+ * @param {import("vue").Ref<import("stac-ts").StacCollection | null>} params.selectedStac
15
14
  * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} params.jsonformEl
16
15
  * @param {import("vue").Ref<Record<string,any> | null>} params.jsonformSchema
17
16
  * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"] | null>} params.chartSpec
@@ -19,6 +18,7 @@ import { useOnLayersUpdate } from "@/composables";
19
18
  * @param {import("vue").Ref<boolean>} params.isProcessed
20
19
  * @param {import("vue").Ref<boolean>} params.loading
21
20
  * @param {import("vue").Ref<boolean>} params.isPolling
21
+ * @param {import("@eox/map").EOxMap | null} params.mapElement
22
22
  */
23
23
  export const useInitProcess = ({
24
24
  selectedStac,
@@ -29,13 +29,15 @@ export const useInitProcess = ({
29
29
  processResults,
30
30
  loading,
31
31
  isPolling,
32
+ mapElement,
32
33
  }) => {
33
34
  const layersEvents = useEventBus(eoxLayersKey);
34
35
 
35
36
  onMounted(async () => {
36
37
  // wait for the layers to be rendered
37
- if (mapEl.value?.layers.length > 1) {
38
+ if ((mapElement?.layers.length ?? 0) > 1) {
38
39
  await initProcess({
40
+ enableCompare: mapElement?.id === "compare",
39
41
  selectedStac,
40
42
  jsonformEl,
41
43
  jsonformSchema,
@@ -48,6 +50,7 @@ export const useInitProcess = ({
48
50
  } else {
49
51
  layersEvents.once(async () => {
50
52
  await initProcess({
53
+ enableCompare: mapElement?.id === "compare",
51
54
  selectedStac,
52
55
  jsonformEl,
53
56
  jsonformSchema,
@@ -61,19 +64,23 @@ export const useInitProcess = ({
61
64
  }
62
65
  });
63
66
 
67
+ const evtKey =
68
+ mapElement?.id === "compare" ? "compareLayers:updated" : "layers:updated";
64
69
  useOnLayersUpdate(async (evt, _payload) => {
65
- if (evt === "layers:updated") {
66
- await initProcess({
67
- selectedStac,
68
- jsonformEl,
69
- jsonformSchema,
70
- chartSpec,
71
- isProcessed,
72
- processResults,
73
- loading,
74
- isPolling,
75
- });
70
+ if (evt !== evtKey) {
71
+ return;
76
72
  }
73
+ await initProcess({
74
+ enableCompare: mapElement?.id === "compare",
75
+ selectedStac,
76
+ jsonformEl,
77
+ jsonformSchema,
78
+ chartSpec,
79
+ isProcessed,
80
+ processResults,
81
+ loading,
82
+ isPolling,
83
+ });
77
84
  });
78
85
  };
79
86
 
@@ -0,0 +1,35 @@
1
+ import log from "loglevel";
2
+ import { handleSentinelHubProcess } from "./sentinelhub-endpoint";
3
+ import { handleVedaEndpoint } from "./veda-endpoint";
4
+
5
+ export const handleChartCustomEndpoints = createCustomChartEndpointsHandler([
6
+ handleSentinelHubProcess,
7
+ handleVedaEndpoint,
8
+ ]);
9
+ /**
10
+ * @param {((input:import("^/EodashProcess/types").CustomEnpointInput)=> Promise<any[] | undefined | null>)[]} callbacks
11
+ */
12
+ function createCustomChartEndpointsHandler(callbacks) {
13
+ /**
14
+ * @param {import("^/EodashProcess/types").CustomEnpointInput} inputs
15
+ * */
16
+ return async (inputs) => {
17
+ for (const callback of callbacks) {
18
+ const data = await callback(inputs);
19
+ log.debug(
20
+ "Custom endpoint data:",
21
+ data,
22
+ "for callback:",
23
+ callback.name,
24
+ "inputs:",
25
+ inputs,
26
+ );
27
+ const isNotValid = !data || !data.length || data.some((item) => !item);
28
+ if (isNotValid) {
29
+ continue;
30
+ }
31
+ return data;
32
+ }
33
+ return null;
34
+ };
35
+ }
@@ -0,0 +1,275 @@
1
+ import axios from "@/plugins/axios";
2
+ import { currentUrl, currentCompareUrl } from "@/store/states";
3
+ import { generateTimePairs, getBboxProperty } from "../../utils";
4
+ import { extractCollectionUrls } from "@/eodashSTAC/helpers";
5
+
6
+ /**
7
+ *
8
+ * @param {import("^/EodashProcess/types").CustomEnpointInput} inputs
9
+ * @returns
10
+ */
11
+ export async function handleSentinelHubProcess({
12
+ links,
13
+ jsonformValue,
14
+ jsonformSchema,
15
+ selectedStac,
16
+ enableCompare = false,
17
+ }) {
18
+ const sentinelHubLink = links.find(
19
+ (link) => link.rel === "service" && link.endpoint === "sentinelhub",
20
+ );
21
+ if (!sentinelHubLink) {
22
+ return;
23
+ }
24
+ const evalScriptLink = await getEvalScriptLink(
25
+ selectedStac,
26
+ enableCompare ? currentCompareUrl.value : currentUrl.value,
27
+ );
28
+ if (!evalScriptLink) {
29
+ console.error(
30
+ "[eodash] evalscript link for sentinel hub not found in indicator",
31
+ evalScriptLink,
32
+ );
33
+ return;
34
+ }
35
+ if (!sentinelHubLink) {
36
+ return;
37
+ }
38
+ const endpoint = sentinelHubLink.href;
39
+ const bboxProperty = getBboxProperty(jsonformSchema);
40
+ const bbox = jsonformValue[bboxProperty];
41
+
42
+ const clientId = process.env.EODASH_SENTINELHUB_CLIENT_ID;
43
+ const clientSecret = process.env.EODASH_SENTINELHUB_CLIENT_SECRET;
44
+
45
+ const bearer = await sentinelHubAuth(clientId, clientSecret);
46
+ if (!bearer) {
47
+ console.error(
48
+ "[eodash] Error while fetching bearer token from sentinel hub",
49
+ );
50
+ return;
51
+ }
52
+ // generate 30 dates from the start and end date of the selected stac
53
+ // generate time pairs from the selected stac temporal extent
54
+ const timePairs = generateTimePairs(
55
+ selectedStac.extent.temporal.interval[0],
56
+ [jsonformValue["start_date"], jsonformValue["end_date"]],
57
+ jsonformValue["distribution"],
58
+ );
59
+
60
+ // fetch data from sentinel hub
61
+ return await Promise.all(
62
+ timePairs.map(([to, from]) => {
63
+ return fetchSentinelHubData({
64
+ url: endpoint,
65
+ bearer,
66
+ bbox,
67
+ from,
68
+ to,
69
+ exampleLink: evalScriptLink,
70
+ }).catch((err) =>
71
+ console.error(
72
+ "[eodash] Error while fetching data from sentinel hub endpoint:",
73
+ err,
74
+ ),
75
+ );
76
+ }),
77
+ ).then((data) => data.flat().map((data) => data.outputs.data));
78
+ }
79
+
80
+ /**
81
+ * @param {string} [clientId]
82
+ * @param {string} [clientSecret]
83
+ * @returns {Promise<string | void>}
84
+ */
85
+ async function sentinelHubAuth(clientId, clientSecret) {
86
+ if (!clientId || !clientSecret) {
87
+ console.error(
88
+ "[eodash] Error (sentinelhub): client id or secret not found",
89
+ );
90
+ return;
91
+ }
92
+
93
+ const sessionToken = sessionStorage.getItem("sentinelhub_token");
94
+ const sessionTokenTime = /** @type {string} */ (
95
+ sessionStorage.getItem("sentinelhub_token_time")
96
+ );
97
+ const isValid = Date.now() - Number(sessionTokenTime) < 3600 * 1000;
98
+
99
+ // if the token is still valid, return it
100
+ if (sessionToken && isValid) {
101
+ sessionStorage.setItem("sentinelhub_token_time", Date.now().toString());
102
+ return sessionToken;
103
+ }
104
+ const token = await retrieveSentinelHubToken(clientId, clientSecret);
105
+ if (!token) {
106
+ return;
107
+ }
108
+ sessionStorage.setItem("sentinelhub_token_time", Date.now().toString());
109
+ sessionStorage.setItem("sentinelhub_token", token);
110
+ return token;
111
+ }
112
+ /**
113
+ * @param {string} clientId
114
+ * @param {string} clientSecret
115
+ * @returns {Promise<string | void>}
116
+ */
117
+ async function retrieveSentinelHubToken(clientId, clientSecret) {
118
+ const url = "https://services.sentinel-hub.com/oauth/token";
119
+ const headers = {
120
+ "Content-Type": "application/x-www-form-urlencoded",
121
+ };
122
+ const body = new URLSearchParams({
123
+ client_id: clientId,
124
+ client_secret: clientSecret,
125
+ response_type: "token",
126
+ grant_type: "client_credentials",
127
+ });
128
+ return await axios
129
+ .post(url, body, { headers })
130
+ .then((resp) => resp.data.access_token);
131
+ }
132
+ /**
133
+ *
134
+ * @param {object} param0
135
+ * @param {string} param0.url - url to the sentinel hub endpoint
136
+ * @param {string} param0.bearer - bearer token for authentication
137
+ * @param {number[]} param0.bbox - bounding box of the area of interest
138
+ * @param {string} param0.from - start date of the time range
139
+ * @param {string} param0.to - end date of the time range
140
+ * @param {number} [param0.timeout = 20000] - timeout for the request
141
+ * @param {import("stac-ts").StacLink} param0.exampleLink - example link containing evalscript to use for the request
142
+ * @returns
143
+ */
144
+ async function fetchSentinelHubData({
145
+ url,
146
+ bearer,
147
+ bbox,
148
+ from,
149
+ to,
150
+ timeout = 20000,
151
+ exampleLink,
152
+ }) {
153
+ if (!exampleLink) {
154
+ console.error(
155
+ "[eodash] Error (sentinelhub): example link not found in indicator",
156
+ );
157
+ return;
158
+ }
159
+ if (!bbox) {
160
+ console.error("[eodash] Error (sentinelhub): bbox not found");
161
+ return;
162
+ }
163
+ if (!from || !to || new Date(from) > new Date(to)) {
164
+ console.error(
165
+ "[eodash] Error (sentinelhub): time range is faulty or not found",
166
+ from,
167
+ to,
168
+ );
169
+ return;
170
+ }
171
+ const evalscript = await axios
172
+ .get(exampleLink.href, { responseType: "text" })
173
+ .then((resp) => resp.data);
174
+
175
+ if (!evalscript || evalscript.error) {
176
+ console.error(
177
+ "[eodash] Error (sentinelhub): evalscript not found",
178
+ evalscript,
179
+ );
180
+ return;
181
+ }
182
+ const body = {
183
+ input: {
184
+ bounds: {
185
+ bbox,
186
+ },
187
+
188
+ data: [
189
+ {
190
+ dataFilter: {},
191
+ type: exampleLink.dataId,
192
+ },
193
+ ],
194
+ },
195
+ aggregation: {
196
+ evalscript,
197
+ timeRange: {
198
+ from,
199
+ to,
200
+ },
201
+ aggregationInterval: {
202
+ of: "P1D",
203
+ },
204
+ width: 100,
205
+ height: 100,
206
+ },
207
+ calculations: {
208
+ default: {},
209
+ },
210
+ };
211
+ const config = {
212
+ headers: {
213
+ Authorization: `Bearer ${bearer}`,
214
+ "Content-Type": "application/json",
215
+ },
216
+ params: {
217
+ credentials: "same-origin",
218
+ },
219
+ timeout,
220
+ };
221
+
222
+ return await axios
223
+ .post(url, body, config)
224
+ .then((resp) => {
225
+ const fetched = resp.data.data;
226
+ //@ts-expect-error TODO
227
+ fetched.forEach((dataItem) => {
228
+ dataItem.outputs.data.date = from;
229
+ });
230
+ return fetched;
231
+ })
232
+ .catch((err) => {
233
+ if (err.response?.status === 401) {
234
+ console.error(
235
+ "[eodash] Error (sentinelhub): bearer token expired, please try again",
236
+ );
237
+ sessionStorage.removeItem("sentinelhub_token");
238
+ sessionStorage.removeItem("sentinelhub_token_time");
239
+ return;
240
+ }
241
+
242
+ console.error(
243
+ "[eodash] Error (sentinelhub): error while fetching data from sentinel hub",
244
+ err.response?.data,
245
+ );
246
+
247
+ return [];
248
+ });
249
+ }
250
+ /**
251
+ * @param {import("stac-ts").StacCollection} selectedStac
252
+ * @param {string} absoluteUrl
253
+ */
254
+ async function getEvalScriptLink(selectedStac, absoluteUrl) {
255
+ const evalScriptLink = selectedStac.links.find(
256
+ (link) => link.rel === "example" && link.title === "evalscript",
257
+ );
258
+ if (evalScriptLink) {
259
+ return evalScriptLink;
260
+ }
261
+ // retrieve the first example link from the indicator children
262
+ for (const link of extractCollectionUrls(selectedStac, absoluteUrl)) {
263
+ const scriptLink = axios
264
+ .get(link)
265
+ .then((resp) =>
266
+ /** @type {import("stac-ts").StacCollection} */ (resp.data).links.find(
267
+ (link) => link.rel === "example" && link.title === "evalscript",
268
+ ),
269
+ );
270
+
271
+ if (scriptLink) {
272
+ return scriptLink;
273
+ }
274
+ }
275
+ }
@@ -0,0 +1,116 @@
1
+ import axios from "@/plugins/axios";
2
+ import { getBboxProperty } from "../../utils";
3
+ import { toAbsolute } from "stac-js/src/http.js";
4
+ import { currentCompareUrl, currentUrl } from "@/store/states";
5
+ import { getDatetimeProperty } from "@/eodashSTAC/helpers";
6
+
7
+ /**
8
+ * @param {import("^/EodashProcess/types").CustomEnpointInput} inputs
9
+ */
10
+ export async function handleVedaEndpoint({
11
+ links,
12
+ jsonformSchema,
13
+ jsonformValue,
14
+ selectedStac,
15
+ enableCompare = false,
16
+ }) {
17
+ const vedaLink = links.find(
18
+ (link) => link.rel === "service" && link.endpoint === "veda",
19
+ );
20
+ if (!vedaLink) {
21
+ return;
22
+ }
23
+ const vedaEndpoint = vedaLink?.href;
24
+ const bboxProperty = getBboxProperty(jsonformSchema);
25
+ // this should be type geojson
26
+ const bboxGeoJSON = JSON.parse(jsonformValue[bboxProperty]);
27
+
28
+ const configs = await fetchVedaCOGsConfig(
29
+ selectedStac,
30
+ enableCompare ? currentCompareUrl.value : currentUrl.value,
31
+ );
32
+ // TODO: convert jsonform bbox type to geojson in the schema to avoid the conversion here
33
+ return await Promise.all(
34
+ configs.map(({ endpoint, datetime }) => {
35
+ return axios
36
+ .post(vedaEndpoint + `?url=${endpoint}`, {
37
+ ...{
38
+ type: "Feature",
39
+ properties: {},
40
+ geometry: bboxGeoJSON,
41
+ },
42
+ })
43
+ .then((resp) => {
44
+ const fetchedSats = resp.data.properties.statistics;
45
+ fetchedSats.date = datetime;
46
+ return fetchedSats;
47
+ })
48
+ .catch((resp) =>
49
+ console.error(
50
+ "[eodash] Error while fetching data from veda endpoint:",
51
+ resp,
52
+ ),
53
+ );
54
+ }),
55
+ );
56
+ }
57
+
58
+ /**
59
+ * Fetches the COGs endpoints from the STAC collections
60
+ * @param {import("stac-ts").StacCollection} selectedStac
61
+ * @param {string} absoluteUrl
62
+ */
63
+ async function fetchVedaCOGsConfig(selectedStac, absoluteUrl) {
64
+ // retrieve the collections from the indicator
65
+ const collectionLinks = selectedStac.links.filter(
66
+ (link) => link.rel == "child",
67
+ );
68
+ /** @type {import("stac-ts").StacCollection[]} */
69
+ const collections = [];
70
+ if (!collectionLinks.length) {
71
+ collections.push(selectedStac);
72
+ } else {
73
+ collections.push(
74
+ ...(await Promise.all(
75
+ collectionLinks.map((link) =>
76
+ axios
77
+ .get(toAbsolute(link.href, absoluteUrl))
78
+ .then((resp) => resp.data),
79
+ ),
80
+ )),
81
+ );
82
+ }
83
+ /** @type {{endpoint:string; datetime:string}[]} */
84
+ const configs = [];
85
+ for (const collection of collections) {
86
+ const datetimeProperty = /** @type string **/ (
87
+ getDatetimeProperty(collection.links)
88
+ );
89
+ let itemLinks = collection.links.filter((link) => link.rel == "item");
90
+ configs.push(
91
+ ...itemLinks.map((link) => ({
92
+ endpoint: /** @type {string} */ (link["cog_href"]),
93
+ datetime: /** @type string **/ (link[datetimeProperty]),
94
+ })),
95
+ );
96
+ }
97
+
98
+ // Sort by date ascending
99
+ configs.sort(
100
+ (a, b) => new Date(a.datetime).getTime() - new Date(b.datetime).getTime(),
101
+ );
102
+
103
+ const maxConfigs = 50;
104
+ if (configs.length <= maxConfigs) {
105
+ return configs;
106
+ }
107
+ // we need to sample if the number of configs are more than 50
108
+ const totalSize = configs.length;
109
+ const sampledConfigs = [];
110
+ for (let i = 0; i < maxConfigs; i++) {
111
+ // Calculate the index to pick, ensuring distribution and inclusion of first/last
112
+ const index = Math.floor((i * (totalSize - 1)) / (maxConfigs - 1));
113
+ sampledConfigs.push(configs[index]);
114
+ }
115
+ return sampledConfigs;
116
+ }
@@ -0,0 +1,94 @@
1
+ import axios from "@/plugins/axios";
2
+ import { compareIndicator, indicator } from "@/store/states";
3
+ import mustache from "mustache";
4
+ import {
5
+ pollProcessStatus,
6
+ updateJobsStatus,
7
+ } from "^/EodashProcess/methods/async";
8
+ import {
9
+ creatAsyncProcessLayerDefinitions,
10
+ extractAsyncResults,
11
+ } from "../../utils";
12
+
13
+ /**
14
+ *
15
+ * @param {import("^/EodashProcess/types").CustomEnpointInput} param0
16
+ */
17
+
18
+ export async function handleEOxHubEndpoint({
19
+ links,
20
+ jsonformValue,
21
+ isPolling,
22
+ selectedStac,
23
+ jobs,
24
+ enableCompare = false,
25
+ }) {
26
+ if (!isPolling) {
27
+ return;
28
+ }
29
+ const eoxhubLinks = links.filter(
30
+ (link) => link.rel === "service" && link.endpoint === "eoxhub_workspaces",
31
+ );
32
+ const layers = [];
33
+ for (const link of eoxhubLinks) {
34
+ // TODO: prove of concept, needs to be reworked for sure
35
+ // Special handling for eoxhub workspace process endpoints
36
+ const postBody = await axios
37
+ .get(/** @type {string} */ (link["body"]), { responseType: "text" })
38
+ .then((resp) => resp.data);
39
+ const jsonData = JSON.parse(
40
+ mustache.render(postBody, { ...(jsonformValue ?? {}) }),
41
+ );
42
+ const currentIndicator = enableCompare ? compareIndicator : indicator;
43
+ try {
44
+ const responseProcess = await axios.post(link.href, jsonData, {
45
+ headers: {
46
+ "Content-Type": "application/json",
47
+ },
48
+ });
49
+
50
+ // We save the process status url into localstorage assigning it to the indicator id
51
+ const currentJobs = JSON.parse(
52
+ localStorage.getItem(currentIndicator.value) || "[]",
53
+ );
54
+ currentJobs.push(responseProcess.headers.location);
55
+ localStorage.setItem(currentIndicator.value, JSON.stringify(currentJobs));
56
+
57
+ const processResults = await pollProcessStatus({
58
+ jobs,
59
+ processUrl: responseProcess.headers.location,
60
+ isPolling,
61
+ enableCompare,
62
+ })
63
+ .then((resultItem) => {
64
+ return extractAsyncResults(resultItem);
65
+ })
66
+ .catch((error) => {
67
+ if (error instanceof Error) {
68
+ console.error("Polling failed:", error.message);
69
+ } else {
70
+ console.error("Unknown error occurred during polling:", error);
71
+ }
72
+ return [];
73
+ });
74
+ await updateJobsStatus(jobs, currentIndicator.value);
75
+
76
+ layers.push(
77
+ ...(await creatAsyncProcessLayerDefinitions(
78
+ processResults,
79
+ link,
80
+ selectedStac,
81
+ )),
82
+ );
83
+ } catch (error) {
84
+ await updateJobsStatus(jobs, currentIndicator.value);
85
+ if (error instanceof Error) {
86
+ console.error("Error sending POST request:", error.message);
87
+ } else {
88
+ console.error("Unknown error occurred:", error);
89
+ }
90
+ }
91
+ }
92
+
93
+ return layers;
94
+ }
@@ -0,0 +1,33 @@
1
+ import { handleEOxHubEndpoint } from "./eoxhub-workspaces-endpoint";
2
+
3
+ export const handleLayersCustomEndpoints = createCustomLayersEndpointsHandler([
4
+ handleEOxHubEndpoint,
5
+ ]);
6
+
7
+ /**
8
+ * @param {((input:import("^/EodashProcess/types").CustomEnpointInput)=> Promise<Record<string,any>[] | undefined | null>)[]} callbacks
9
+ * @returns {(input: import("^/EodashProcess/types").CustomEnpointInput) => Promise<import("@eox/map/.").EoxLayer[]>}
10
+ */
11
+ function createCustomLayersEndpointsHandler(callbacks) {
12
+ return async (inputs) => {
13
+ // this allows multiple endpoints links to exist
14
+ // and return multiple layers
15
+ return await Promise.all(
16
+ callbacks.map((callback) => callback(inputs)),
17
+ ).then((asyncProcessesLayers) => {
18
+ const layers = [];
19
+ for (const processLayers of asyncProcessesLayers) {
20
+ layers.push(...(processLayers?.filter(isValidEoxLayer) ?? []));
21
+ }
22
+ return layers;
23
+ });
24
+ };
25
+ }
26
+
27
+ /**
28
+ * @param {any} layer
29
+ * @returns {layer is import("@eox/map/.").EoxLayer}
30
+ */
31
+ function isValidEoxLayer(layer) {
32
+ return !!layer && !!layer.type && (!!layer.source || !!layer.layers);
33
+ }