@eodash/eodash 5.0.0-alpha.2.25 → 5.0.0-alpha.2.27

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 (108) hide show
  1. package/core/client/asWebComponent.js +2 -3
  2. package/core/client/components/DashboardLayout.vue +35 -13
  3. package/core/client/components/Loading.vue +6 -9
  4. package/core/client/components/MobileLayout.vue +16 -14
  5. package/core/client/composables/DefineEodash.js +13 -3
  6. package/core/client/composables/DefineTemplate.js +67 -0
  7. package/core/client/composables/DefineWidgets.js +3 -2
  8. package/core/client/composables/EodashMap.js +39 -14
  9. package/core/client/composables/EodashProcess.js +574 -0
  10. package/core/client/composables/index.js +54 -11
  11. package/core/client/eodash.js +383 -125
  12. package/core/client/{utils/eodashSTAC.js → eodashSTAC/EodashCollection.js} +75 -41
  13. package/core/client/{utils → eodashSTAC}/createLayers.js +12 -7
  14. package/core/client/{utils → eodashSTAC}/helpers.js +47 -75
  15. package/core/client/eodashSTAC/triggers.js +43 -0
  16. package/core/client/plugins/vuetify.js +2 -1
  17. package/core/client/store/{Actions.js → actions.js} +16 -2
  18. package/core/client/store/index.js +4 -18
  19. package/core/client/store/stac.js +4 -4
  20. package/core/client/store/{States.js → states.js} +2 -0
  21. package/{dist/types/core/client/types.d.ts → core/client/types.ts} +47 -8
  22. package/core/client/utils/keys.js +2 -0
  23. package/core/client/utils/states.js +8 -3
  24. package/core/client/views/Dashboard.vue +6 -4
  25. package/core/client/vite-env.d.ts +1 -16
  26. package/dist/client/{DashboardLayout-jpgby4Eh.js → DashboardLayout-232tRmjz.js} +23 -25
  27. package/dist/client/{DynamicWebComponent-Bwrmh0sP.js → DynamicWebComponent-Cl4LqHU6.js} +1 -1
  28. package/dist/client/{EodashDatePicker-Dv9_y547.js → EodashDatePicker-Pok6bZwU.js} +78 -165
  29. package/dist/client/EodashItemFilter-16eMMjTV.js +151 -0
  30. package/dist/client/{EodashLayerControl-iRPRTWaC.js → EodashLayerControl-De7IlCm_.js} +19 -11
  31. package/dist/client/EodashLayoutSwitcher-C-3-jjn5.js +52 -0
  32. package/dist/client/{EodashMap-G1xNg6jB.js → EodashMap-CMvbfI6-.js} +116 -39
  33. package/dist/client/EodashMapBtns-BeknGDtc.js +107 -0
  34. package/dist/client/EodashProcess-BwKAa9Ee.js +1476 -0
  35. package/dist/client/EodashStacInfo-_BfonNUG.js +85 -0
  36. package/dist/client/EodashTools-PD3XPYuR.js +103 -0
  37. package/dist/client/{ExportState-CDovKW7n.js → ExportState-DOrT7M15.js} +5 -5
  38. package/dist/client/{Footer-B1O4tw8o.js → Footer-CCigxYBo.js} +1 -1
  39. package/dist/client/{Header-DDLdUYod.js → Header-C2cdx4gb.js} +3 -3
  40. package/dist/client/{MobileLayout-B3QtXpa0.js → MobileLayout-BdiFjHg7.js} +28 -31
  41. package/dist/client/{PopUp-BMd-trL0.js → PopUp--_xn1Cms.js} +37 -9
  42. package/dist/client/{VImg-knszc_IF.js → VImg-9xu2l99m.js} +2 -2
  43. package/dist/client/{VMain-ClWkSR7S.js → VMain-BUs3kDTd.js} +1 -1
  44. package/dist/client/{VOverlay-CRTrjcqf.js → VOverlay-D89omJis.js} +3 -3
  45. package/dist/client/VTooltip-CDu3bErh.js +86 -0
  46. package/dist/client/{WidgetsContainer-D4mWWQgi.js → WidgetsContainer-aFG9yFT6.js} +1 -1
  47. package/dist/client/{asWebComponent-Cc5OdWN5.js → asWebComponent-BRGyP_j5.js} +1497 -1141
  48. package/dist/client/{style.css → eo-dash.css} +2 -2
  49. package/dist/client/eo-dash.js +1 -1
  50. package/dist/client/{forwardRefs-DqVLK6M0.js → forwardRefs-CYrR6bMw.js} +1 -1
  51. package/dist/client/{index-CuOyaGAl.js → index-BZwk0V42.js} +1 -1
  52. package/dist/client/{transition-gjF7vk5X.js → transition-DG9nRSW4.js} +1 -1
  53. package/dist/node/cli.js +3 -3
  54. package/package.json +56 -34
  55. package/widgets/EodashDatePicker.vue +68 -54
  56. package/widgets/EodashItemFilter.vue +60 -105
  57. package/widgets/EodashLayerControl.vue +19 -8
  58. package/widgets/EodashLayoutSwitcher.vue +36 -0
  59. package/widgets/EodashMap.vue +27 -28
  60. package/widgets/EodashMapBtns.vue +41 -4
  61. package/widgets/EodashProcess.vue +143 -0
  62. package/widgets/EodashStacInfo.vue +82 -0
  63. package/widgets/EodashTools.vue +83 -0
  64. package/widgets/ExportState.vue +3 -3
  65. package/widgets/PopUp.vue +24 -2
  66. package/core/client/asWebComponent.d.ts +0 -23
  67. package/core/client/types.d.ts +0 -279
  68. package/dist/client/EodashItemFilter-CZ5Hdn0p.js +0 -194
  69. package/dist/client/EodashMapBtns-DOiv-00v.js +0 -66
  70. package/dist/types/core/client/App.vue.d.ts +0 -7
  71. package/dist/types/core/client/asWebComponent.d.ts +0 -9
  72. package/dist/types/core/client/components/DashboardLayout.vue.d.ts +0 -2
  73. package/dist/types/core/client/components/DynamicWebComponent.vue.d.ts +0 -18
  74. package/dist/types/core/client/components/ErrorAlert.vue.d.ts +0 -2
  75. package/dist/types/core/client/components/Footer.vue.d.ts +0 -2
  76. package/dist/types/core/client/components/Header.vue.d.ts +0 -2
  77. package/dist/types/core/client/components/IframeWrapper.vue.d.ts +0 -7
  78. package/dist/types/core/client/components/Loading.vue.d.ts +0 -2
  79. package/dist/types/core/client/components/MobileLayout.vue.d.ts +0 -2
  80. package/dist/types/core/client/composables/DefineEodash.d.ts +0 -2
  81. package/dist/types/core/client/composables/DefineWidgets.d.ts +0 -14
  82. package/dist/types/core/client/composables/EodashMap.d.ts +0 -5
  83. package/dist/types/core/client/composables/index.d.ts +0 -29
  84. package/dist/types/core/client/eodash.d.ts +0 -8
  85. package/dist/types/core/client/main.d.ts +0 -2
  86. package/dist/types/core/client/plugins/axios.d.ts +0 -2
  87. package/dist/types/core/client/plugins/index.d.ts +0 -3
  88. package/dist/types/core/client/plugins/vuetify.d.ts +0 -82
  89. package/dist/types/core/client/render.d.ts +0 -1
  90. package/dist/types/core/client/store/Actions.d.ts +0 -11
  91. package/dist/types/core/client/store/States.d.ts +0 -21
  92. package/dist/types/core/client/store/index.d.ts +0 -2
  93. package/dist/types/core/client/store/stac.d.ts +0 -25
  94. package/dist/types/core/client/utils/createLayers.d.ts +0 -45
  95. package/dist/types/core/client/utils/eodashSTAC.d.ts +0 -82
  96. package/dist/types/core/client/utils/helpers.d.ts +0 -84
  97. package/dist/types/core/client/utils/index.d.ts +0 -2
  98. package/dist/types/core/client/utils/keys.d.ts +0 -6
  99. package/dist/types/core/client/utils/states.d.ts +0 -14
  100. package/dist/types/core/client/views/Dashboard.vue.d.ts +0 -9
  101. package/dist/types/widgets/EodashDatePicker.vue.d.ts +0 -7
  102. package/dist/types/widgets/EodashItemFilter.vue.d.ts +0 -33
  103. package/dist/types/widgets/EodashLayerControl.vue.d.ts +0 -7
  104. package/dist/types/widgets/EodashMap.vue.d.ts +0 -7
  105. package/dist/types/widgets/EodashMapBtns.vue.d.ts +0 -9
  106. package/dist/types/widgets/ExportState.vue.d.ts +0 -7
  107. package/dist/types/widgets/PopUp.vue.d.ts +0 -14
  108. package/dist/types/widgets/WidgetsContainer.vue.d.ts +0 -7
@@ -0,0 +1,574 @@
1
+ import { isMulti } from "@eox/jsonform/src/custom-inputs/spatial/utils";
2
+ import { nextTick, onMounted, watch } from "vue";
3
+ import mustache from "mustache";
4
+ import axios from "axios";
5
+ import { extractLayerConfig } from "@/eodashSTAC/helpers";
6
+ import log from "loglevel";
7
+ import { getLayers } from "@/store/actions";
8
+ import { mapEl } from "@/store/states";
9
+
10
+ /**
11
+ * Polls the process status and fetches a result item when the process is successful.
12
+ *
13
+ * @param {Object} params - Parameters for polling the process status.
14
+ * @param {string} params.processUrl - The URL of the process JSON report.
15
+ * @param {import("vue").Ref<boolean>} params.isPolling - checks wether the polling should continue
16
+ * @param {number} [params.pollInterval=5000] - The interval (in milliseconds) between polling attempts.
17
+ * @param {number} [params.maxRetries=60] - The maximum number of polling attempts.
18
+ * @returns {Promise<JSON>} The fetched results JSON.
19
+ * @throws {Error} If the process does not complete successfully within the maximum retries.
20
+ */
21
+ export async function pollProcessStatus({
22
+ processUrl,
23
+ isPolling,
24
+ pollInterval = 5000,
25
+ maxRetries = 60,
26
+ }) {
27
+ let retries = 0;
28
+ isPolling.value = true;
29
+ while (retries < maxRetries && isPolling.value) {
30
+ try {
31
+ // Fetch the process JSON report
32
+ const cacheBuster = new Date().getTime(); // Add a timestamp for cache busting
33
+ const response = await axios.get(`${processUrl}?t=${cacheBuster}`);
34
+ const processReport = response.data;
35
+
36
+ // Check if the status is "successful"
37
+ if (processReport.status === "successful") {
38
+ console.log("Process completed successfully. Fetching result item...");
39
+
40
+ // Extract the result item URL
41
+ const resultsUrl = processReport.links[1].href;
42
+ if (!resultsUrl) {
43
+ throw new Error(`Result links not found in the process report.`);
44
+ }
45
+
46
+ // Fetch the result item
47
+ const resultResponse = await axios.get(resultsUrl);
48
+ console.log("Result file fetched successfully:", resultResponse.data);
49
+ return resultResponse.data; // Return the json result list
50
+ }
51
+
52
+ // Log the current status if not successful
53
+ console.log(
54
+ `Status: ${processReport.status}. Retrying in ${pollInterval / 1000} seconds...`,
55
+ );
56
+ } catch (error) {
57
+ if (error instanceof Error) {
58
+ console.error("Error while polling process status:", error.message);
59
+ } else {
60
+ console.error("Unknown error occurred:", error);
61
+ }
62
+ }
63
+
64
+ // Wait for the next poll
65
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
66
+ retries++;
67
+ }
68
+ if (!isPolling.value) {
69
+ console.warn("Polling was stopped before the process was completed.");
70
+ return JSON.parse("{}");
71
+ }
72
+
73
+ throw new Error(
74
+ "Max retries reached. Process did not complete successfully.",
75
+ );
76
+ }
77
+
78
+ /**
79
+ * Auto execute the process when the jsonform has the execute option
80
+ *
81
+ * @param {import("vue").Ref<boolean>} autoExec
82
+ * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} jsonformEl
83
+ * @param {import("vue").Ref<Record<string,any> | null>} jsonformSchema
84
+ * @param {() => Promise<void>} startProcess
85
+ **/
86
+ export function useAutoExec(
87
+ autoExec,
88
+ jsonformEl,
89
+ jsonformSchema,
90
+ startProcess,
91
+ ) {
92
+ /**
93
+ * @param {CustomEvent} _e
94
+ **/
95
+ const onJsonFormChange = async (_e) => {
96
+ await startProcess();
97
+ };
98
+
99
+ const addEventListener = async () => {
100
+ await nextTick(() => {
101
+ //@ts-expect-error TODO
102
+ jsonformEl.value?.addEventListener("change", onJsonFormChange);
103
+ });
104
+ };
105
+ const removeEventListener = () => {
106
+ //@ts-expect-error TODO
107
+ jsonformEl.value?.removeEventListener("change", onJsonFormChange);
108
+ };
109
+
110
+ watch(jsonformSchema, (updatedSchema) => {
111
+ autoExec.value = updatedSchema?.options?.["execute"] || false;
112
+ });
113
+
114
+ onMounted(() => {
115
+ watch(
116
+ autoExec,
117
+ async (exec) => {
118
+ if (exec) {
119
+ await addEventListener();
120
+ } else {
121
+ removeEventListener();
122
+ }
123
+ },
124
+ { immediate: true },
125
+ );
126
+ });
127
+ }
128
+
129
+ /**
130
+ * @param {Record<string,any> |null} [jsonformSchema]
131
+ **/
132
+ export function getBboxProperty(jsonformSchema) {
133
+ return /** @type {string} */ (
134
+ Object.keys(jsonformSchema?.properties ?? {}).find(
135
+ (key) => jsonformSchema?.properties[key].format === "bounding-box",
136
+ )
137
+ );
138
+ }
139
+
140
+ /**
141
+ * Extracts the keys of type "geojson" from the jsonform schema
142
+ * @param {Record<string,any> |null} [jsonformSchema]
143
+ **/
144
+ export function getGeoJsonProperties(jsonformSchema) {
145
+ return /** @type {string[]} */ (
146
+ Object.keys(jsonformSchema?.properties ?? {}).filter(
147
+ (key) => jsonformSchema?.properties[key].type === "geojson",
148
+ )
149
+ );
150
+ }
151
+
152
+ /**
153
+ * Converts jsonform geojson values to stringified geometries
154
+ * @param {Record<string,any> |null} [jsonformSchema]
155
+ * @param {Record<string,any>} jsonformValue
156
+ **/
157
+ export function extractGeometries(jsonformValue, jsonformSchema) {
158
+ const geojsonKeys = getGeoJsonProperties(jsonformSchema);
159
+
160
+ for (const key of geojsonKeys) {
161
+ if (!jsonformValue[key]) {
162
+ continue;
163
+ }
164
+
165
+ if (isMulti(jsonformSchema?.properties[key])) {
166
+ // jsonformValue[key] is a feature collection
167
+ jsonformValue[key] =
168
+ /** @type {import("ol/format/GeoJSON").GeoJSONFeatureCollection} */ (
169
+ jsonformValue[key]
170
+ ).features.map((feature) => JSON.stringify(feature.geometry));
171
+ } else {
172
+ // jsonformValue[key] is a single feature
173
+ jsonformValue[key] = JSON.stringify(jsonformValue[key].geometry);
174
+ }
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Injects CSS to remove the borders of the jsonform from inside the shadowRoot
180
+ * @param {import("@eox/jsonform").EOxJSONForm | null} jsonFormEl
181
+ **/
182
+ export function injectJsonformCSS(jsonFormEl) {
183
+ if (!jsonFormEl?.shadowRoot) {
184
+ console.error("jsonform has no shadowRoot");
185
+ return;
186
+ }
187
+ const stylesheet = new CSSStyleSheet();
188
+ stylesheet.replaceSync(`.je-indented-panel {
189
+ border: none !important;
190
+ }`);
191
+ jsonFormEl.shadowRoot.adoptedStyleSheets = [stylesheet];
192
+ }
193
+
194
+ /**
195
+ * @param {import("stac-ts").StacLink[] | undefined} links
196
+ * @param {Record<string,any>|undefined} jsonformValue
197
+ * @param {number[]} origBbox
198
+ */
199
+ export function processImage(links, jsonformValue, origBbox) {
200
+ if (!links) return;
201
+ const imageLinks = links.filter(
202
+ (link) => link.rel === "service" && link.type === "image/png",
203
+ );
204
+ const layers = [];
205
+ for (const link of imageLinks) {
206
+ layers.push({
207
+ type: "Image",
208
+ properties: {
209
+ id: link.id,
210
+ title: "Results " + link.id,
211
+ },
212
+ source: {
213
+ type: "ImageStatic",
214
+ imageExtent: origBbox,
215
+ url: mustache.render(link.href, {
216
+ ...(jsonformValue ?? {}),
217
+ }),
218
+ },
219
+ });
220
+ }
221
+ return layers;
222
+ }
223
+
224
+ /**
225
+ * @param {import("stac-ts").StacLink[] | undefined} links
226
+ * @param {Record<string,any> | undefined} jsonformValue
227
+ * @param {string} layerId
228
+ */
229
+ export async function processVector(links, jsonformValue, layerId) {
230
+ if (!links) return;
231
+ /** @type {Record<string,any>[]} */
232
+ const layers = [];
233
+ const vectorLinks = links.filter(
234
+ (link) => link.rel === "service" && link.type === "application/geo+json",
235
+ );
236
+ if (vectorLinks.length === 0) return layers;
237
+
238
+ let flatStyleJSON = null;
239
+
240
+ for (const link of vectorLinks) {
241
+ if ("eox:flatstyle" in (link ?? {})) {
242
+ flatStyleJSON = await axios
243
+ .get(/** @type {string} */ (link["eox:flatstyle"]))
244
+ .then((resp) => resp.data);
245
+ }
246
+
247
+ /** @type {Record<string,any>|undefined} */
248
+ let layerConfig;
249
+ /** @type {Record<string,any>|undefined} */
250
+ let style;
251
+ if (flatStyleJSON) {
252
+ const extracted = extractLayerConfig(flatStyleJSON);
253
+ layerConfig = extracted.layerConfig;
254
+ style = extracted.style;
255
+ }
256
+
257
+ layers.push({
258
+ type: "Vector",
259
+ source: {
260
+ type: "Vector",
261
+ url: mustache.render(link.href, {
262
+ ...(jsonformValue ?? {}),
263
+ }),
264
+ format: "GeoJSON",
265
+ },
266
+ properties: {
267
+ id: layerId + "_vector_process",
268
+ title: "Results " + layerId,
269
+ ...(layerConfig && { ...layerConfig, ...(style && { style: style }) }),
270
+ },
271
+ });
272
+ }
273
+ return layers;
274
+ }
275
+
276
+ /**
277
+ * @param {import("stac-ts").StacLink[] | undefined} links
278
+ * @param {Record<string,any> | undefined} jsonformValue
279
+ * @param {import("vue").Ref<boolean>} isPolling
280
+ * @param {string} layerId
281
+ */
282
+ export async function processGeoTiff(links, jsonformValue, layerId, isPolling) {
283
+ if (!links) return;
284
+ const geotiffLinks = links.filter(
285
+ (link) => link.rel === "service" && link.type === "image/tiff",
286
+ );
287
+ let urls = [];
288
+ let flatStyleJSON = null;
289
+ for (const link of geotiffLinks ?? []) {
290
+ if (link.endpoint === "eoxhub_workspaces") {
291
+ // TODO: prove of concept, needs to be reworked for sure
292
+ // Special handling for eoxhub workspace process endpoints
293
+ const postBody = await axios
294
+ .get(/** @type {string} */ (link["body"]), { responseType: "text" })
295
+ .then((resp) => resp.data);
296
+ const jsonData = JSON.parse(
297
+ mustache.render(postBody, { ...(jsonformValue ?? {}) }),
298
+ );
299
+ try {
300
+ const responseProcess = await axios.post(link.href, jsonData, {
301
+ headers: {
302
+ "Content-Type": "application/json",
303
+ },
304
+ });
305
+ console.log(responseProcess.headers.location);
306
+ await pollProcessStatus({
307
+ processUrl: responseProcess.headers.location,
308
+ isPolling,
309
+ })
310
+ .then((resultItem) => {
311
+ // @ts-expect-error we have currently no definition of what is allowed as response
312
+ const resultUrls = resultItem?.urls;
313
+ if (!resultUrls?.length) {
314
+ return;
315
+ }
316
+
317
+ urls.push(resultUrls[0]);
318
+ })
319
+ .catch((error) => {
320
+ if (error instanceof Error) {
321
+ console.error("Polling failed:", error.message);
322
+ } else {
323
+ console.error("Unknown error occurred during polling:", error);
324
+ }
325
+ });
326
+ } catch (error) {
327
+ if (error instanceof Error) {
328
+ console.error("Error sending POST request:", error.message);
329
+ } else {
330
+ console.error("Unknown error occurred:", error);
331
+ }
332
+ }
333
+ } else {
334
+ urls.push(mustache.render(link.href, { ...(jsonformValue ?? {}) }));
335
+ }
336
+ if ("eox:flatstyle" in (link ?? {})) {
337
+ flatStyleJSON = await axios
338
+ .get(/** @type {string} */ (link["eox:flatstyle"]))
339
+ .then((resp) => resp.data);
340
+ }
341
+ }
342
+ /** @type {Record<string,any>|undefined} */
343
+ let layerConfig;
344
+ /** @type {Record<string,any>|undefined} */
345
+ let style;
346
+ if (flatStyleJSON) {
347
+ const extracted = extractLayerConfig(flatStyleJSON);
348
+ layerConfig = extracted.layerConfig;
349
+ style = extracted.style;
350
+ }
351
+ return urls.length
352
+ ? {
353
+ type: "WebGLTile",
354
+ source: {
355
+ type: "GeoTIFF",
356
+ normalize: !style,
357
+ sources: urls.map((url) => ({ url })),
358
+ },
359
+ properties: {
360
+ id: layerId + "_geotiff_process",
361
+ title: "Results " + layerId,
362
+ ...(layerConfig && { layerConfig: layerConfig }),
363
+ },
364
+ ...(style && { style: style }),
365
+ }
366
+ : undefined;
367
+ }
368
+
369
+ /**
370
+ * @param {import("stac-ts").StacLink[] | undefined} links
371
+ * @param {Record<string,any> | undefined} jsonformValue
372
+ * @param {string} specUrl
373
+ * @returns {Promise<[import("vega").Spec|null,Record<string,any>|null]>}
374
+ **/
375
+ export async function getChartValues(links, jsonformValue, specUrl) {
376
+ if (!specUrl || !links) return [null, null];
377
+ /** @type {import("vega").Spec} */
378
+ const spec = await axios.get(specUrl).then((resp) => {
379
+ return resp.data;
380
+ });
381
+ // //@ts-expect-error NamedData
382
+ // const dataName = spec?.data?.name;
383
+ const dataLinks = links.filter(
384
+ (link) => link.rel === "service", // && dataName && link.id === dataName,
385
+ );
386
+
387
+ /** @type {Record<string,any>} */
388
+ const dataValues = {};
389
+ for (const link of dataLinks ?? []) {
390
+ if (link.type && ["application/json", "text/csv"].includes(link.type)) {
391
+ const dataUrl = mustache.render(link.href, {
392
+ ...(jsonformValue ?? {}),
393
+ ...(link["eox:flatstyle"] ?? {}),
394
+ });
395
+ // Wait for data to be retrieved
396
+ const data = await axios.get(dataUrl).then((resp) => {
397
+ return resp.data;
398
+ });
399
+ // @ts-expect-error we assume data to exist in spec
400
+ spec.data.values = data;
401
+ continue;
402
+ }
403
+
404
+ dataValues[/** @type {string} */ (link.id)] = await axios
405
+ .get(
406
+ mustache.render(link.href, {
407
+ ...(jsonformValue ?? {}),
408
+ ...(link["eox:flatstyle"] ?? {}),
409
+ }),
410
+ )
411
+ .then((resp) => resp.data);
412
+ }
413
+ return [spec, dataValues];
414
+ }
415
+
416
+ /**
417
+ * @param {Object} params
418
+ * @param {import("vue").Ref<boolean>} params.loading
419
+ * @param {import("vue").Ref<import("stac-ts").StacCollection | null>} params.selectedStac
420
+ * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} params.jsonformEl
421
+ * @param {import("vue").Ref<Record<string,any>|null>} params.jsonformSchema
422
+ * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"]>} params.chartSpec
423
+ * @param {import("vue").Ref<Record<string, any> | null>} params.chartData
424
+ * @param {import("vue").Ref<boolean>} params.isPolling
425
+ */
426
+ export async function handleProcesses({
427
+ loading,
428
+ selectedStac,
429
+ jsonformEl,
430
+ jsonformSchema,
431
+ chartSpec,
432
+ chartData,
433
+ isPolling,
434
+ }) {
435
+ log.debug("Processing...");
436
+ loading.value = true;
437
+ try {
438
+ const serviceLinks = selectedStac.value?.links?.filter(
439
+ (l) => l.rel === "service",
440
+ );
441
+ const bboxProperty = getBboxProperty(jsonformSchema.value);
442
+ const jsonformValue = /** @type {Record<string,any>} */ (
443
+ jsonformEl.value?.value
444
+ );
445
+
446
+ extractGeometries(jsonformValue, jsonformSchema.value);
447
+
448
+ const origBbox = jsonformValue[bboxProperty];
449
+
450
+ const specUrl = /** @type {string} */ (
451
+ selectedStac.value?.["eodash:vegadefinition"]
452
+ );
453
+
454
+ [chartSpec.value, chartData.value] = await getChartValues(
455
+ serviceLinks,
456
+ { ...(jsonformValue ?? {}) },
457
+ specUrl,
458
+ );
459
+ if (chartSpec.value && !("background" in chartSpec.value)) {
460
+ chartSpec.value["background"] = "transparent";
461
+ }
462
+ const geotiffLayer = await processGeoTiff(
463
+ serviceLinks,
464
+ jsonformValue,
465
+ selectedStac.value?.id ?? "",
466
+ isPolling,
467
+ );
468
+ const vectorLayers = await processVector(
469
+ serviceLinks,
470
+ jsonformValue,
471
+ selectedStac.value?.id ?? "",
472
+ );
473
+
474
+ const imageLayers = processImage(serviceLinks, jsonformValue, origBbox);
475
+
476
+ log.debug(
477
+ "rendered layers after processing:",
478
+ geotiffLayer,
479
+ vectorLayers,
480
+ imageLayers,
481
+ );
482
+
483
+ if (geotiffLayer || vectorLayers?.length || imageLayers?.length) {
484
+ const layers = [
485
+ ...(geotiffLayer ? [geotiffLayer] : []),
486
+ ...(vectorLayers ?? []),
487
+ ...(imageLayers ?? []),
488
+ ];
489
+ let currentLayers = [...getLayers()];
490
+ let analysisGroup = currentLayers.find((l) =>
491
+ l.properties.id.includes("AnalysisGroup"),
492
+ );
493
+ analysisGroup?.layers.push(...layers);
494
+
495
+ if (mapEl.value) {
496
+ mapEl.value.layers = [...currentLayers];
497
+ }
498
+ }
499
+ loading.value = false;
500
+ } catch (error) {
501
+ console.error("[eodash] Error while running process:", error);
502
+ loading.value = false;
503
+ throw error;
504
+ }
505
+ }
506
+
507
+ /**
508
+ * Reset the process state
509
+ * @param {Object} params
510
+ * @param {import("vue").Ref<boolean>} params.loading
511
+ * @param {import("vue").Ref<boolean>} params.isProcessed
512
+ * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"]>} params.chartSpec
513
+ * @param {import("vue").Ref<boolean>} params.isPolling
514
+ * @param {import("vue").Ref<Record<string,any>|null>} params.jsonformSchema
515
+ */
516
+ export function resetProcess({
517
+ loading,
518
+ isProcessed,
519
+ chartSpec,
520
+ jsonformSchema,
521
+ isPolling,
522
+ }) {
523
+ loading.value = false;
524
+ isProcessed.value = false;
525
+ isPolling.value = false;
526
+ chartSpec.value = null;
527
+ jsonformSchema.value = null;
528
+ }
529
+
530
+ /**
531
+ * Description placeholder
532
+ *
533
+ * @export
534
+ * @async
535
+ * @param {Object} params
536
+ * @param {import("vue").Ref<import("stac-ts").StacCollection>} params.selectedStac
537
+ * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} params.jsonformEl
538
+ * @param {import("vue").Ref<Record<string,any> | null>} params.jsonformSchema
539
+ * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"]>} params.chartSpec
540
+ * @param {import("vue").Ref<boolean>} params.isProcessed
541
+ * @param {import("vue").Ref<boolean>} params.loading
542
+ * @param {import("vue").Ref<boolean>} params.isPolling
543
+ */
544
+ export async function initProcess({
545
+ selectedStac,
546
+ jsonformEl,
547
+ jsonformSchema,
548
+ chartSpec,
549
+ isProcessed,
550
+ loading,
551
+ isPolling,
552
+ }) {
553
+ if (!selectedStac.value) {
554
+ return;
555
+ }
556
+ resetProcess({ loading, isProcessed, chartSpec, jsonformSchema, isPolling });
557
+ if (selectedStac.value["eodash:jsonform"]) {
558
+ jsonformEl.value?.editor.destroy();
559
+ // wait for the layers to be rendered
560
+ jsonformSchema.value = await axios
561
+ //@ts-expect-error eodash extention
562
+ .get(selectedStac.value["eodash:jsonform"])
563
+ .then((resp) => resp.data);
564
+ // remove borders from jsonform
565
+ await nextTick(() => {
566
+ injectJsonformCSS(jsonformEl.value);
567
+ });
568
+ } else {
569
+ if (!jsonformSchema.value) {
570
+ return;
571
+ }
572
+ jsonformSchema.value = null;
573
+ }
574
+ }
@@ -1,18 +1,22 @@
1
1
  // functions of this folder can only be consumed inside setup stores,
2
- // setup functions or vue composition api components
2
+ // setup functions or vue composition api components https://vuejs.org/guide/reusability/composables
3
3
 
4
4
  import {
5
+ activeTemplate,
5
6
  currentCompareUrl,
6
7
  currentUrl,
7
8
  datetime,
8
9
  indicator,
9
10
  mapPosition,
10
- } from "@/store/States";
11
+ } from "@/store/states";
11
12
  import eodash from "@/eodash";
12
13
  import { useTheme } from "vuetify/lib/framework.mjs";
13
- import { onMounted, watch } from "vue";
14
+ import { inject, onMounted, onUnmounted, watch } from "vue";
14
15
  import { useSTAcStore } from "@/store/stac";
15
16
  import log from "loglevel";
17
+ import { eodashKey, eoxLayersKey } from "@/utils/keys";
18
+ import { useEventBus } from "@vueuse/core";
19
+ import { posIsSetFromUrl } from "@/utils/states";
16
20
 
17
21
  /**
18
22
  * Creates an absolute URL from a relative link and assignes it to `currentUrl`
@@ -21,11 +25,11 @@ import log from "loglevel";
21
25
  * @param {string} [base=eodash.stacEndpoint] - Base URL, default value is the
22
26
  * root stac catalog. Default is `eodash.stacEndpoint`
23
27
  * @returns {import("vue").Ref<string>} - Returns `currentUrl`
24
- * @see {@link '@/store/States.js'}
28
+ * @see {@link '@/store/states.js'}
25
29
  */
26
30
  export const useAbsoluteUrl = (rel = "", base = eodash.stacEndpoint) => {
27
31
  if (!rel || rel.includes("http")) {
28
- currentUrl.value = base;
32
+ currentUrl.value = rel;
29
33
  return currentUrl;
30
34
  }
31
35
 
@@ -50,7 +54,7 @@ export const useAbsoluteUrl = (rel = "", base = eodash.stacEndpoint) => {
50
54
  * @param {string} [base=eodash.stacEndpoint] - Base URL, default value is the
51
55
  * root stac catalog. Default is `eodash.stacEndpoint`
52
56
  * @returns {import("vue").Ref<string>} - Returns `currentUrl`
53
- * @see {@link '@/store/States.js'}
57
+ * @see {@link '@/store/states.js'}
54
58
  */
55
59
  export const useCompareAbsoluteUrl = (rel = "", base = eodash.stacEndpoint) => {
56
60
  if (!rel || rel.includes("http")) {
@@ -117,6 +121,10 @@ export const useURLSearchParametersSync = () => {
117
121
  z;
118
122
  for (const [key, value] of searchParams) {
119
123
  switch (key) {
124
+ case "template": {
125
+ activeTemplate.value = value;
126
+ break;
127
+ }
120
128
  case "indicator": {
121
129
  log.debug("Found indicator key in url");
122
130
  const { loadSelectedSTAC, stac } = useSTAcStore();
@@ -158,12 +166,20 @@ export const useURLSearchParametersSync = () => {
158
166
  if (x && y && z) {
159
167
  log.debug("Coordinates found, applying map poisition", x, y, z);
160
168
  mapPosition.value = [x, y, z];
169
+ if (!posIsSetFromUrl.value) {
170
+ posIsSetFromUrl.value = true;
171
+ }
161
172
  }
162
173
  }
163
174
 
164
175
  watch(
165
- [indicator, mapPosition, datetime],
166
- ([updatedIndicator, updatedMapPosition, updatedDatetime]) => {
176
+ [indicator, mapPosition, datetime, activeTemplate],
177
+ ([
178
+ updatedIndicator,
179
+ updatedMapPosition,
180
+ updatedDatetime,
181
+ updatedTemplate,
182
+ ]) => {
167
183
  if ("URLSearchParams" in window) {
168
184
  const searchParams = new URLSearchParams(window.location.search);
169
185
  if (updatedIndicator !== "") {
@@ -179,6 +195,9 @@ export const useURLSearchParametersSync = () => {
179
195
  if (updatedDatetime) {
180
196
  searchParams.set("datetime", updatedDatetime.split("T")?.[0] ?? "");
181
197
  }
198
+ if (updatedTemplate) {
199
+ searchParams.set("template", updatedTemplate);
200
+ }
182
201
  const newRelativePathQuery =
183
202
  window.location.pathname + "?" + searchParams.toString();
184
203
  history.pushState(null, "", newRelativePathQuery);
@@ -188,14 +207,38 @@ export const useURLSearchParametersSync = () => {
188
207
  });
189
208
  };
190
209
 
191
- /** @param {import("vue").Ref<HTMLElement|null>} root - components root element ref*/
210
+ /**
211
+ * Converts eox-layout-item to transparent
212
+ *
213
+ * @param {import("vue").Ref<HTMLElement|null>} root - components root element ref*/
192
214
  export const makePanelTransparent = (root) => {
193
215
  onMounted(() => {
194
216
  const eoxItem = root.value?.parentElement;
195
217
  if (eoxItem?.tagName === "EOX-LAYOUT-ITEM") {
196
218
  eoxItem.classList.remove("bg-surface");
197
- eoxItem.style.background = "transparent";
198
- eoxItem.style.border = "transparent";
199
219
  }
200
220
  });
201
221
  };
222
+
223
+ export const useGetTemplates = () => {
224
+ const eodash = /** @type {import("@/types").Eodash} */ (inject(eodashKey));
225
+ return "template" in eodash ? [] : Object.keys(eodash.templates);
226
+ };
227
+
228
+ /**
229
+ * Listens to the `layers:updated` and `time:updated` events and calls
230
+ *
231
+ * @param {import("@vueuse/core").EventBusListener<
232
+ * "layers:updated"|"time:updated",
233
+ * {layers:Record<string,any>[]| undefined}
234
+ * >} listener
235
+ */
236
+ export const useOnLayersUpdate = (listener) => {
237
+ const layersEvents = useEventBus(eoxLayersKey);
238
+
239
+ const unsubscribe = layersEvents.on(listener);
240
+
241
+ onUnmounted(() => {
242
+ unsubscribe();
243
+ });
244
+ };