@eodash/eodash 5.0.0-rc.2.4 → 5.0.0-rc.3

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 (80) hide show
  1. package/core/client/composables/DefineWidgets.js +8 -1
  2. package/core/client/eodash.js +9 -9
  3. package/core/client/eodashSTAC/createLayers.js +4 -17
  4. package/core/client/eodashSTAC/helpers.js +23 -0
  5. package/core/client/store/stac.js +3 -1
  6. package/core/client/types.ts +127 -21
  7. package/core/client/utils/states.js +9 -0
  8. package/core/client/vite-env.d.ts +0 -13
  9. package/dist/client/{DashboardLayout-D1UcB3RV.js → DashboardLayout-t_PavJPO.js} +2 -2
  10. package/dist/client/{DynamicWebComponent-DtZ_mHL9.js → DynamicWebComponent-y07rVJch.js} +1 -1
  11. package/dist/client/{EodashDatePicker-CYU0MZX5.js → EodashDatePicker-CcOfyzGD.js} +3 -83
  12. package/dist/client/{EodashItemFilter-SE9oW3oZ.js → EodashItemFilter-B9HCvIMi.js} +1 -1
  13. package/dist/client/{EodashLayerControl-BuGe29Nt.js → EodashLayerControl-KStn7Nb_.js} +8 -2
  14. package/dist/client/{EodashLayoutSwitcher-6wLl-Gtd.js → EodashLayoutSwitcher-DqeFO3RN.js} +2 -2
  15. package/dist/client/{EodashMapBtns-BWWu6eHG.js → EodashMapBtns-5BF27qJB.js} +36 -12
  16. package/dist/client/{EodashStacInfo-DjRSGLHM.js → EodashStacInfo-C_hDy6Pd.js} +7 -1
  17. package/dist/client/{EodashTools-CJ4hBH_X.js → EodashTools-BXflvRf8.js} +5 -4
  18. package/dist/client/{ExportState-BqnlEpzR.js → ExportState-C0QRemK1.js} +27 -12
  19. package/dist/client/{Footer-C_3WrfI4.js → Footer-7VGyGUAs.js} +1 -1
  20. package/dist/client/{Header-D_hcGpNG.js → Header-BQJnXHYq.js} +3 -3
  21. package/dist/client/{MobileLayout-CDbupC9v.js → MobileLayout-b8nQ-Vyl.js} +5 -5
  22. package/dist/client/{PopUp-Ba6mY2jQ.js → PopUp-DgNrh9Df.js} +3 -3
  23. package/dist/client/ProcessList-C62SOVO6.js +484 -0
  24. package/dist/client/{VImg-Yc9F9pYq.js → VImg-D4eT3IQ1.js} +2 -2
  25. package/dist/client/{VMain-BiS7HPEk.js → VMain-C3hN2-H3.js} +1 -1
  26. package/dist/client/{VOverlay-B9mxXaCv.js → VOverlay-tAeNygaA.js} +15 -6
  27. package/dist/client/{VTooltip-XJLaLrZQ.js → VTooltip-B0Q3iHMZ.js} +3 -3
  28. package/dist/client/{WidgetsContainer-DRVb_73N.js → WidgetsContainer-CtDHfCYf.js} +1 -1
  29. package/dist/client/{asWebComponent-DZpMGxEY.js → asWebComponent-BJ2NWunV.js} +100 -95
  30. package/dist/client/eo-dash.css +2 -2
  31. package/dist/client/eo-dash.js +1 -1
  32. package/dist/client/{forwardRefs-BtkfywIE.js → forwardRefs-CIFAqXaZ.js} +9 -9
  33. package/dist/client/{EodashMap-DhVCoYMi.js → index-BQ16n4Sk.js} +103 -78
  34. package/dist/client/index-Cv7HBz49.js +85 -0
  35. package/dist/client/{EodashProcess-GSj_LMsK.js → index-Da5xXX6Q.js} +349 -443
  36. package/dist/client/{index-f55xuyof.js → index-DvcUndod.js} +1 -1
  37. package/dist/client/{transition-CtL4BoVi.js → transition-Cdb4K27U.js} +1 -1
  38. package/dist/types/core/client/components/MobileLayout.vue.d.ts +9 -9
  39. package/dist/types/core/client/eodashSTAC/EodashCollection.d.ts +11 -6
  40. package/dist/types/core/client/eodashSTAC/createLayers.d.ts +6 -5
  41. package/dist/types/core/client/eodashSTAC/helpers.d.ts +383 -2
  42. package/dist/types/core/client/types.d.ts +85 -19
  43. package/dist/types/core/client/utils/states.d.ts +7 -0
  44. package/dist/types/widgets/EodashDatePicker.vue.d.ts +4 -4
  45. package/dist/types/widgets/EodashItemFilter.vue.d.ts +18 -18
  46. package/dist/types/widgets/EodashLayerControl.vue.d.ts +2 -2
  47. package/dist/types/widgets/EodashLayoutSwitcher.vue.d.ts +2 -2
  48. package/dist/types/widgets/EodashMap/methods/create-layers-config.d.ts +9 -0
  49. package/dist/types/widgets/EodashMap/methods/index.d.ts +5 -0
  50. package/dist/types/widgets/EodashMapBtns.vue.d.ts +8 -2
  51. package/dist/types/widgets/EodashProcess/ProcessList.vue.d.ts +2 -0
  52. package/dist/types/widgets/EodashProcess/methods/async.d.ts +45 -0
  53. package/dist/types/widgets/EodashProcess/methods/composables.d.ts +19 -0
  54. package/dist/types/widgets/EodashProcess/methods/handling.d.ts +78 -0
  55. package/dist/types/widgets/EodashProcess/methods/outputs.d.ts +54 -0
  56. package/dist/types/widgets/EodashProcess/methods/utils.d.ts +42 -0
  57. package/dist/types/widgets/EodashStacInfo.vue.d.ts +12 -12
  58. package/dist/types/widgets/EodashTools.vue.d.ts +44 -6
  59. package/dist/types/widgets/PopUp.vue.d.ts +4 -4
  60. package/package.json +30 -29
  61. package/widgets/EodashLayerControl.vue +8 -1
  62. package/widgets/{EodashMap.vue → EodashMap/index.vue} +53 -29
  63. package/widgets/EodashMap/methods/create-layers-config.js +151 -0
  64. package/{core/client/composables/EodashMap.js → widgets/EodashMap/methods/index.js} +4 -153
  65. package/widgets/EodashMapBtns.vue +33 -7
  66. package/widgets/EodashProcess/ProcessList.vue +82 -0
  67. package/widgets/EodashProcess/index.vue +186 -0
  68. package/widgets/EodashProcess/methods/async.js +209 -0
  69. package/widgets/EodashProcess/methods/composables.js +129 -0
  70. package/widgets/EodashProcess/methods/handling.js +254 -0
  71. package/widgets/EodashProcess/methods/outputs.js +216 -0
  72. package/widgets/EodashProcess/methods/utils.js +138 -0
  73. package/widgets/EodashStacInfo.vue +6 -0
  74. package/widgets/EodashTools.vue +1 -0
  75. package/core/client/composables/EodashProcess.js +0 -624
  76. package/dist/types/core/client/composables/EodashMap.d.ts +0 -6
  77. package/dist/types/core/client/composables/EodashProcess.d.ts +0 -162
  78. package/widgets/EodashProcess.vue +0 -208
  79. /package/dist/types/widgets/{EodashMap.vue.d.ts → EodashMap/index.vue.d.ts} +0 -0
  80. /package/dist/types/widgets/{EodashProcess.vue.d.ts → EodashProcess/index.vue.d.ts} +0 -0
@@ -1,235 +1,13 @@
1
- import { createVNode, nextTick, watch, onMounted, ref, useTemplateRef, computed, createElementBlock, openBlock, createCommentVNode, normalizeStyle, toRaw, withCtx, createElementVNode, createBlock, createTextVNode } from 'vue';
1
+ import { onMounted, watch, nextTick, ref, useTemplateRef, computed, createElementBlock, openBlock, createVNode, createCommentVNode, createElementVNode, normalizeStyle, unref, toRaw, createBlock, withCtx, createTextVNode } from 'vue';
2
2
  import '@eox/chart';
3
3
  import '@eox/drawtools';
4
4
  import '@eox/jsonform';
5
- import { g as genericComponent, p as propsFactory, c as useRtl, H as useDimension, a as useRender, h as makeTagProps, J as makeDimensionProps, i as makeComponentProps, ah as axios, ai as getLayers, a4 as mapEl, aj as extractLayerConfig, a8 as eoxLayersKey, $ as useSTAcStore, ab as useOnLayersUpdate, V as VBtn } from './asWebComponent-DZpMGxEY.js';
5
+ import { ai as axios, aj as indicator, ak as extractLayerConfig, Y as datetime, al as getLayers, a3 as mapEl, a9 as eoxLayersKey, ac as useOnLayersUpdate, Z as useSTAcStore, V as VBtn } from './asWebComponent-BJ2NWunV.js';
6
6
  import { storeToRefs } from 'pinia';
7
- import { useEventBus } from '@vueuse/core';
8
- import { isMulti } from '@eox/jsonform/src/custom-inputs/spatial/utils';
9
- import mustache from 'mustache';
7
+ import { p as pollProcessStatus, c as createLayerDefinition, g as getBboxProperty, e as extractGeometries, _ as _sfc_main$1, u as updateJobsStatus, d as download, j as jobs } from './ProcessList-C62SOVO6.js';
10
8
  import log from 'loglevel';
11
-
12
- const makeVContainerProps = propsFactory({
13
- fluid: {
14
- type: Boolean,
15
- default: false
16
- },
17
- ...makeComponentProps(),
18
- ...makeDimensionProps(),
19
- ...makeTagProps()
20
- }, 'VContainer');
21
- const VContainer = genericComponent()({
22
- name: 'VContainer',
23
- props: makeVContainerProps(),
24
- setup(props, _ref) {
25
- let {
26
- slots
27
- } = _ref;
28
- const {
29
- rtlClasses
30
- } = useRtl();
31
- const {
32
- dimensionStyles
33
- } = useDimension(props);
34
- useRender(() => createVNode(props.tag, {
35
- "class": ['v-container', {
36
- 'v-container--fluid': props.fluid
37
- }, rtlClasses.value, props.class],
38
- "style": [dimensionStyles.value, props.style]
39
- }, slots));
40
- return {};
41
- }
42
- });
43
-
44
- /**
45
- * Polls the process status and fetches a result item when the process is successful.
46
- *
47
- * @param {Object} params - Parameters for polling the process status.
48
- * @param {string} params.processUrl - The URL of the process JSON report.
49
- * @param {import("vue").Ref<boolean>} params.isPolling - checks wether the polling should continue
50
- * @param {number} [params.pollInterval=5000] - The interval (in milliseconds) between polling attempts.
51
- * @param {number} [params.maxRetries=60] - The maximum number of polling attempts.
52
- * @returns {Promise<JSON>} The fetched results JSON.
53
- * @throws {Error} If the process does not complete successfully within the maximum retries.
54
- */
55
- async function pollProcessStatus({
56
- processUrl,
57
- isPolling,
58
- pollInterval = 5000,
59
- maxRetries = 60,
60
- }) {
61
- let retries = 0;
62
- isPolling.value = true;
63
- while (retries < maxRetries && isPolling.value) {
64
- try {
65
- // Fetch the process JSON report
66
- const cacheBuster = new Date().getTime(); // Add a timestamp for cache busting
67
- const response = await axios.get(`${processUrl}?t=${cacheBuster}`);
68
- const processReport = response.data;
69
-
70
- // Check if the status is "successful"
71
- if (processReport.status === "successful") {
72
- console.log("Process completed successfully. Fetching result item...");
73
-
74
- // Extract the result item URL
75
- const resultsUrl = processReport.links[1].href;
76
- if (!resultsUrl) {
77
- throw new Error(`Result links not found in the process report.`);
78
- }
79
-
80
- // Fetch the result item
81
- const resultResponse = await axios.get(resultsUrl);
82
- console.log("Result file fetched successfully:", resultResponse.data);
83
- return resultResponse.data; // Return the json result list
84
- }
85
- if (processReport.status === "failed") {
86
- isPolling.value = false;
87
- throw new Error("Process failed.", processReport);
88
- }
89
-
90
- // Log the current status if not successful
91
- console.log(
92
- `Status: ${processReport.status}. Retrying in ${pollInterval / 1000} seconds...`,
93
- );
94
- } catch (error) {
95
- if (error instanceof Error) {
96
- console.error("Error while polling process status:", error.message);
97
- } else {
98
- console.error("Unknown error occurred:", error);
99
- }
100
- }
101
-
102
- // Wait for the next poll
103
- await new Promise((resolve) => setTimeout(resolve, pollInterval));
104
- retries++;
105
- }
106
- if (!isPolling.value) {
107
- console.warn("Polling was stopped before the process was completed.");
108
- return JSON.parse("{}");
109
- }
110
-
111
- throw new Error(
112
- "Max retries reached. Process did not complete successfully.",
113
- );
114
- }
115
-
116
- /**
117
- * Auto execute the process when the jsonform has the execute option
118
- *
119
- * @param {import("vue").Ref<boolean>} autoExec
120
- * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} jsonformEl
121
- * @param {import("vue").Ref<Record<string,any> | null>} jsonformSchema
122
- * @param {() => Promise<void>} startProcess
123
- **/
124
- function useAutoExec(
125
- autoExec,
126
- jsonformEl,
127
- jsonformSchema,
128
- startProcess,
129
- ) {
130
- /**
131
- * @param {CustomEvent} _e
132
- **/
133
- const onJsonFormChange = async (_e) => {
134
- await startProcess();
135
- };
136
-
137
- const addEventListener = async () => {
138
- await nextTick(() => {
139
- //@ts-expect-error TODO
140
- jsonformEl.value?.addEventListener("change", onJsonFormChange);
141
- });
142
- };
143
- const removeEventListener = () => {
144
- //@ts-expect-error TODO
145
- jsonformEl.value?.removeEventListener("change", onJsonFormChange);
146
- };
147
-
148
- watch(jsonformSchema, (updatedSchema) => {
149
- autoExec.value = updatedSchema?.options?.["execute"] || false;
150
- });
151
-
152
- onMounted(() => {
153
- watch(
154
- autoExec,
155
- async (exec) => {
156
- if (exec) {
157
- await addEventListener();
158
- } else {
159
- removeEventListener();
160
- }
161
- },
162
- { immediate: true },
163
- );
164
- });
165
- }
166
-
167
- /**
168
- * @param {Record<string,any> |null} [jsonformSchema]
169
- **/
170
- function getBboxProperty(jsonformSchema) {
171
- return /** @type {string} */ (
172
- Object.keys(jsonformSchema?.properties ?? {}).find(
173
- (key) => jsonformSchema?.properties[key].format === "bounding-box",
174
- )
175
- );
176
- }
177
-
178
- /**
179
- * Extracts the keys of type "geojson" from the jsonform schema
180
- * @param {Record<string,any> |null} [jsonformSchema]
181
- **/
182
- function getGeoJsonProperties(jsonformSchema) {
183
- return /** @type {string[]} */ (
184
- Object.keys(jsonformSchema?.properties ?? {}).filter(
185
- (key) => jsonformSchema?.properties[key].type === "geojson",
186
- )
187
- );
188
- }
189
-
190
- /**
191
- * Converts jsonform geojson values to stringified geometries
192
- * @param {Record<string,any> |null} [jsonformSchema]
193
- * @param {Record<string,any>} jsonformValue
194
- **/
195
- function extractGeometries(jsonformValue, jsonformSchema) {
196
- const geojsonKeys = getGeoJsonProperties(jsonformSchema);
197
-
198
- for (const key of geojsonKeys) {
199
- if (!jsonformValue[key]) {
200
- continue;
201
- }
202
-
203
- if (isMulti(jsonformSchema?.properties[key])) {
204
- // jsonformValue[key] is a feature collection
205
- jsonformValue[key] =
206
- /** @type {import("ol/format/GeoJSON").GeoJSONFeatureCollection} */ (
207
- jsonformValue[key]
208
- ).features.map((feature) => JSON.stringify(feature.geometry));
209
- } else {
210
- // jsonformValue[key] is a single feature
211
- jsonformValue[key] = JSON.stringify(jsonformValue[key].geometry);
212
- }
213
- }
214
- }
215
-
216
- /**
217
- * Injects CSS to remove the borders of the jsonform from inside the shadowRoot
218
- * @param {import("@eox/jsonform").EOxJSONForm | null} jsonFormEl
219
- **/
220
- function injectJsonformCSS(jsonFormEl) {
221
- //@ts-expect-error TODO
222
- if (!jsonFormEl?.shadowRoot) {
223
- console.error("jsonform has no shadowRoot");
224
- return;
225
- }
226
- const stylesheet = new CSSStyleSheet();
227
- stylesheet.replaceSync(`.je-indented-panel {
228
- border: none !important;
229
- }`);
230
- //@ts-expect-error TODO
231
- jsonFormEl.shadowRoot.adoptedStyleSheets = [stylesheet];
232
- }
9
+ import mustache from 'mustache';
10
+ import { useEventBus } from '@vueuse/core';
233
11
 
234
12
  /**
235
13
  * @param {import("stac-ts").StacLink[] | undefined} links
@@ -313,19 +91,75 @@ async function processVector(links, jsonformValue, layerId) {
313
91
  return layers;
314
92
  }
315
93
 
94
+ /**
95
+ * @param {import("stac-ts").StacLink[] | undefined} links
96
+ * @param {Record<string,any> | undefined} jsonformValue
97
+ * @param {string} specUrl
98
+ * @returns {Promise<[import("@eox/chart").EOxChart["spec"] | null,Record<string,any>|null]>}
99
+ **/
100
+ async function getChartValues(links, jsonformValue, specUrl) {
101
+ if (!specUrl || !links) return [null, null];
102
+ /** @type {import("vega").Spec} */
103
+ const spec = await axios.get(specUrl).then((resp) => {
104
+ return resp.data;
105
+ });
106
+ // //@ts-expect-error NamedData
107
+ // const dataName = spec?.data?.name;
108
+ const dataLinks = links.filter(
109
+ (link) => link.rel === "service", // && dataName && link.id === dataName,
110
+ );
111
+
112
+ /** @type {Record<string,any>} */
113
+ const dataValues = {};
114
+ for (const link of dataLinks ?? []) {
115
+ if (link.type && ["application/json", "text/csv"].includes(link.type)) {
116
+ const dataUrl = mustache.render(link.href, {
117
+ ...(jsonformValue ?? {}),
118
+ ...(link["eox:flatstyle"] ?? {}),
119
+ });
120
+
121
+ // Wait for data to be retrieved
122
+ const data = await axios.get(dataUrl).then((resp) => {
123
+ return resp.data;
124
+ });
125
+ // @ts-expect-error we assume data to exist in spec
126
+ spec.data.values = data;
127
+ continue;
128
+ }
129
+
130
+ dataValues[/** @type {string} */ (link.id)] = await axios
131
+ .get(
132
+ mustache.render(link.href, {
133
+ ...(jsonformValue ?? {}),
134
+ ...(link["eox:flatstyle"] ?? {}),
135
+ }),
136
+ )
137
+ .then((resp) => resp.data);
138
+ }
139
+
140
+ return [spec, dataValues];
141
+ }
142
+
316
143
  /**
317
144
  * @param {import("stac-ts").StacLink[] | undefined} links
318
145
  * @param {Record<string,any> | undefined} jsonformValue
319
146
  * @param {import("vue").Ref<boolean>} isPolling
320
147
  * @param {string} layerId
148
+ * @param {string} projection
321
149
  */
322
- async function processGeoTiff(links, jsonformValue, layerId, isPolling) {
150
+ async function processGeoTiff(
151
+ links,
152
+ jsonformValue,
153
+ layerId,
154
+ isPolling,
155
+ projection,
156
+ ) {
323
157
  if (!links) return;
324
158
  const geotiffLinks = links.filter(
325
159
  (link) => link.rel === "service" && link.type === "image/tiff",
326
160
  );
327
161
  let urls = [];
328
- let flatStyleJSON = null;
162
+ let processId = "";
329
163
  for (const link of geotiffLinks ?? []) {
330
164
  if (link.endpoint === "eoxhub_workspaces") {
331
165
  // TODO: prove of concept, needs to be reworked for sure
@@ -343,6 +177,12 @@ async function processGeoTiff(links, jsonformValue, layerId, isPolling) {
343
177
  },
344
178
  });
345
179
  console.log(responseProcess.headers.location);
180
+ // We save the process status url into localstorage assigning it to the indicator id
181
+ const currentJobs = JSON.parse(
182
+ localStorage.getItem(indicator.value) || "[]",
183
+ );
184
+ currentJobs.push(responseProcess.headers.location);
185
+ localStorage.setItem(indicator.value, JSON.stringify(currentJobs));
346
186
  await pollProcessStatus({
347
187
  processUrl: responseProcess.headers.location,
348
188
  isPolling,
@@ -350,11 +190,12 @@ async function processGeoTiff(links, jsonformValue, layerId, isPolling) {
350
190
  .then((resultItem) => {
351
191
  // @ts-expect-error we have currently no definition of what is allowed as response
352
192
  const resultUrls = resultItem?.urls;
353
- if (!resultUrls?.length) {
193
+ if (resultUrls?.length < 1) {
354
194
  return;
355
195
  }
356
-
357
- urls.push(resultUrls[0]);
196
+ //@ts-expect-error todo
197
+ processId = resultItem?.id;
198
+ urls = resultUrls;
358
199
  })
359
200
  .catch((error) => {
360
201
  if (error instanceof Error) {
@@ -373,87 +214,65 @@ async function processGeoTiff(links, jsonformValue, layerId, isPolling) {
373
214
  } else {
374
215
  urls.push(mustache.render(link.href, { ...(jsonformValue ?? {}) }));
375
216
  }
376
- if ("eox:flatstyle" in (link ?? {})) {
377
- flatStyleJSON = await axios
378
- .get(/** @type {string} */ (link["eox:flatstyle"]))
379
- .then((resp) => resp.data);
380
- }
381
- }
382
- /** @type {Record<string,any>|undefined} */
383
- let layerConfig;
384
- /** @type {Record<string,any>|undefined} */
385
- let style;
386
- if (flatStyleJSON) {
387
- const extracted = extractLayerConfig(layerId ?? "", flatStyleJSON);
388
- layerConfig = extracted.layerConfig;
389
- style = extracted.style;
390
217
  }
391
- return urls.length
392
- ? {
393
- type: "WebGLTile",
394
- source: {
395
- type: "GeoTIFF",
396
- normalize: !style,
397
- sources: urls.map((url) => ({ url })),
398
- },
399
- properties: {
400
- id: layerId + "_geotiff_process",
401
- title: "Results " + layerId,
402
- ...(layerConfig && { layerConfig: layerConfig }),
403
- },
404
- ...(style && { style: style }),
405
- }
406
- : undefined;
218
+
219
+ return createLayerDefinition(links[0], layerId, urls, projection, processId);
407
220
  }
408
221
 
409
222
  /**
410
- * @param {import("stac-ts").StacLink[] | undefined} links
411
- * @param {Record<string,any> | undefined} jsonformValue
412
- * @param {string} specUrl
413
- * @returns {Promise<[import("@eox/chart").EOxChart["spec"] | null,Record<string,any>|null]>}
414
- **/
415
- async function getChartValues(links, jsonformValue, specUrl) {
416
- if (!specUrl || !links) return [null, null];
417
- /** @type {import("vega").Spec} */
418
- const spec = await axios.get(specUrl).then((resp) => {
419
- return resp.data;
223
+ * Fetch and set the jsonform schema to initialize the process
224
+ *
225
+ * @export
226
+ * @async
227
+ * @param {Object} params
228
+ * @param {import("vue").Ref<import("stac-ts").StacCollection>} params.selectedStac
229
+ * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} params.jsonformEl
230
+ * @param {import("vue").Ref<Record<string,any> | null>} params.jsonformSchema
231
+ * @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"] | null>} params.chartSpec
232
+ * @param {import("vue").Ref<any[]>} params.processResults
233
+ * @param {import("vue").Ref<boolean>} params.isProcessed
234
+ * @param {import("vue").Ref<boolean>} params.loading
235
+ * @param {import("vue").Ref<boolean>} params.isPolling
236
+ */
237
+ async function initProcess({
238
+ selectedStac,
239
+ jsonformEl,
240
+ jsonformSchema,
241
+ chartSpec,
242
+ isProcessed,
243
+ processResults,
244
+ loading,
245
+ isPolling,
246
+ }) {
247
+ if (!selectedStac.value) {
248
+ return;
249
+ }
250
+ resetProcess({
251
+ loading,
252
+ isProcessed,
253
+ chartSpec,
254
+ jsonformSchema,
255
+ isPolling,
256
+ processResults,
420
257
  });
421
- // //@ts-expect-error NamedData
422
- // const dataName = spec?.data?.name;
423
- const dataLinks = links.filter(
424
- (link) => link.rel === "service", // && dataName && link.id === dataName,
425
- );
426
-
427
- /** @type {Record<string,any>} */
428
- const dataValues = {};
429
- for (const link of dataLinks ?? []) {
430
- if (link.type && ["application/json", "text/csv"].includes(link.type)) {
431
- const dataUrl = mustache.render(link.href, {
432
- ...(jsonformValue ?? {}),
433
- ...(link["eox:flatstyle"] ?? {}),
434
- });
435
- // Wait for data to be retrieved
436
- const data = await axios.get(dataUrl).then((resp) => {
437
- return resp.data;
438
- });
439
- // @ts-expect-error we assume data to exist in spec
440
- spec.data.values = data;
441
- continue;
442
- }
443
-
444
- dataValues[/** @type {string} */ (link.id)] = await axios
445
- .get(
446
- mustache.render(link.href, {
447
- ...(jsonformValue ?? {}),
448
- ...(link["eox:flatstyle"] ?? {}),
449
- }),
450
- )
258
+ if (selectedStac.value["eodash:jsonform"]) {
259
+ jsonformEl.value?.editor.destroy();
260
+ // wait for the layers to be rendered
261
+ jsonformSchema.value = await axios
262
+ //@ts-expect-error eodash extention
263
+ .get(selectedStac.value["eodash:jsonform"])
451
264
  .then((resp) => resp.data);
265
+ // remove borders from jsonform
266
+ } else {
267
+ if (!jsonformSchema.value) {
268
+ return;
269
+ }
270
+ jsonformSchema.value = null;
452
271
  }
453
- return [spec, dataValues];
454
272
  }
455
273
 
456
274
  /**
275
+ *
457
276
  * @param {Object} params
458
277
  * @param {import("vue").Ref<boolean>} params.loading
459
278
  * @param {import("vue").Ref<import("stac-ts").StacCollection | null>} params.selectedStac
@@ -474,6 +293,9 @@ async function handleProcesses({
474
293
  isPolling,
475
294
  processResults,
476
295
  }) {
296
+ if (!jsonformEl.value || !jsonformSchema.value || !selectedStac.value) {
297
+ return;
298
+ }
477
299
  log.debug("Processing...");
478
300
  loading.value = true;
479
301
  try {
@@ -482,7 +304,6 @@ async function handleProcesses({
482
304
  );
483
305
  const bboxProperty = getBboxProperty(jsonformSchema.value);
484
306
  const jsonformValue = /** @type {Record<string,any>} */ (
485
- //@ts-expect-error todo
486
307
  jsonformEl.value?.value
487
308
  );
488
309
 
@@ -502,6 +323,7 @@ async function handleProcesses({
502
323
  if (Object.keys(chartData.value ?? {}).length) {
503
324
  processResults.value.push(chartData.value);
504
325
  }
326
+
505
327
  //@ts-expect-error we assume that the spec data is of type InlineData
506
328
  if (chartSpec.value?.data?.values?.length) {
507
329
  //@ts-expect-error we assume that the spec data is of type InlineData
@@ -517,6 +339,8 @@ async function handleProcesses({
517
339
  jsonformValue,
518
340
  selectedStac.value?.id ?? "",
519
341
  isPolling,
342
+ //@ts-expect-error TODO
343
+ selectedStac.value?.["eodash:mapProjection"]?.["name"] ?? null,
520
344
  );
521
345
 
522
346
  if (geotiffLayer && geotiffLayer.source?.sources.length) {
@@ -602,7 +426,44 @@ function resetProcess({
602
426
  }
603
427
 
604
428
  /**
605
- * Description placeholder
429
+ * Handles the click event on a chart to extract temporal information and update the global datetime value.
430
+ *
431
+ * @param {object} evt - The click event object.
432
+ * @param {object} evt.target - The target of the event, expected to have a Vega-Lite specification (`spec`).
433
+ * @param {object} evt.target.spec - The Vega-Lite specification of the chart.
434
+ * @param {Record<string,{type?:string;field?:string;}>} [evt.target.spec.encoding] - The encoding specification of the chart.
435
+ * @param {object} evt.detail - The detail of the event, containing information about the clicked item.
436
+ * @param {import("vega").Item} evt.detail.item - The Vega item that was clicked.
437
+ */
438
+ const onChartClick = (evt) => {
439
+ const chartSpec = evt.target?.spec;
440
+ if (!chartSpec) {
441
+ return;
442
+ }
443
+ const encodingKey = Object.keys(chartSpec.encoding ?? {}).find(
444
+ (key) => chartSpec.encoding?.[key].type === "temporal",
445
+ );
446
+ if (!encodingKey) {
447
+ return;
448
+ }
449
+ const temporalKey = chartSpec.encoding?.[encodingKey].field;
450
+ if (!temporalKey) {
451
+ return;
452
+ }
453
+ try {
454
+ const vegaItem = evt.detail.item;
455
+ const temporalValue = new Date(vegaItem.datum.datum[temporalKey]);
456
+ datetime.value = temporalValue.toISOString();
457
+ } catch (error) {
458
+ console.warn(
459
+ "[eodash] Error while setting datetime from eox-chart:",
460
+ error,
461
+ );
462
+ }
463
+ };
464
+
465
+ /**
466
+ * Composable resposible of timing the Initialization of the process
606
467
  *
607
468
  * @export
608
469
  * @async
@@ -616,7 +477,7 @@ function resetProcess({
616
477
  * @param {import("vue").Ref<boolean>} params.loading
617
478
  * @param {import("vue").Ref<boolean>} params.isPolling
618
479
  */
619
- async function initProcess({
480
+ const useInitProcess = ({
620
481
  selectedStac,
621
482
  jsonformEl,
622
483
  jsonformSchema,
@@ -625,36 +486,103 @@ async function initProcess({
625
486
  processResults,
626
487
  loading,
627
488
  isPolling,
628
- }) {
629
- if (!selectedStac.value) {
630
- return;
631
- }
632
- resetProcess({
633
- loading,
634
- isProcessed,
635
- chartSpec,
636
- jsonformSchema,
637
- isPolling,
638
- processResults,
639
- });
640
- if (selectedStac.value["eodash:jsonform"]) {
641
- //@ts-expect-error todo
642
- jsonformEl.value?.editor.destroy();
489
+ }) => {
490
+ const layersEvents = useEventBus(eoxLayersKey);
491
+
492
+ onMounted(async () => {
643
493
  // wait for the layers to be rendered
644
- jsonformSchema.value = await axios
645
- //@ts-expect-error eodash extention
646
- .get(selectedStac.value["eodash:jsonform"])
647
- .then((resp) => resp.data);
648
- // remove borders from jsonform
494
+ if (mapEl.value?.layers.length > 1) {
495
+ await initProcess({
496
+ selectedStac,
497
+ jsonformEl,
498
+ jsonformSchema,
499
+ chartSpec,
500
+ isProcessed,
501
+ processResults,
502
+ loading,
503
+ isPolling,
504
+ });
505
+ } else {
506
+ layersEvents.once(async () => {
507
+ await initProcess({
508
+ selectedStac,
509
+ jsonformEl,
510
+ jsonformSchema,
511
+ chartSpec,
512
+ isProcessed,
513
+ loading,
514
+ processResults,
515
+ isPolling,
516
+ });
517
+ });
518
+ }
519
+ });
520
+
521
+ useOnLayersUpdate(async (evt, _payload) => {
522
+ if (evt === "layers:updated") {
523
+ await initProcess({
524
+ selectedStac,
525
+ jsonformEl,
526
+ jsonformSchema,
527
+ chartSpec,
528
+ isProcessed,
529
+ processResults,
530
+ loading,
531
+ isPolling,
532
+ });
533
+ }
534
+ });
535
+ };
536
+
537
+ /**
538
+ * Auto execute the process when the jsonform has the execute option
539
+ *
540
+ * @param {import("vue").Ref<boolean>} autoExec
541
+ * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} jsonformEl
542
+ * @param {import("vue").Ref<Record<string,any> | null>} jsonformSchema
543
+ * @param {() => Promise<void>} startProcess
544
+ **/
545
+ function useAutoExec(
546
+ autoExec,
547
+ jsonformEl,
548
+ jsonformSchema,
549
+ startProcess,
550
+ ) {
551
+ /**
552
+ * @param {CustomEvent} _e
553
+ **/
554
+ const onJsonFormChange = async (_e) => {
555
+ await startProcess();
556
+ };
557
+
558
+ const addEventListener = async () => {
649
559
  await nextTick(() => {
650
- injectJsonformCSS(jsonformEl.value);
560
+ //@ts-expect-error TODO
561
+ jsonformEl.value?.addEventListener("change", onJsonFormChange);
651
562
  });
652
- } else {
653
- if (!jsonformSchema.value) {
654
- return;
655
- }
656
- jsonformSchema.value = null;
657
- }
563
+ };
564
+ const removeEventListener = () => {
565
+ //@ts-expect-error TODO
566
+ jsonformEl.value?.removeEventListener("change", onJsonFormChange);
567
+ };
568
+
569
+ watch(jsonformSchema, (updatedSchema) => {
570
+ autoExec.value = updatedSchema?.options?.["execute"] || false;
571
+ });
572
+
573
+ onMounted(() => {
574
+ watch(
575
+ autoExec,
576
+ async (exec) => {
577
+ if (exec) {
578
+ await addEventListener();
579
+ } else {
580
+ removeEventListener();
581
+ }
582
+ },
583
+ { immediate: true },
584
+ );
585
+ });
658
586
  }
659
587
 
660
588
  const _hoisted_1 = {
@@ -663,16 +591,14 @@ const _hoisted_1 = {
663
591
  };
664
592
  const _hoisted_2 = [".schema"];
665
593
  const _hoisted_3 = [".spec", ".dataValues"];
594
+ const _hoisted_4 = { style: {"text-align":"right"} };
666
595
 
596
+ /** @type {import("vue").Ref<import("vega").Spec|null>} */
667
597
 
668
598
  const _sfc_main = {
669
- __name: 'EodashProcess',
599
+ __name: 'index',
670
600
  setup(__props) {
671
601
 
672
- const layersEvents = useEventBus(eoxLayersKey);
673
- const { selectedStac } = storeToRefs(useSTAcStore());
674
-
675
- /** @type {import("vue").Ref<import("vega").Spec|null>} */
676
602
  const chartSpec = ref(null);
677
603
 
678
604
  /** @type {import("vue").Ref<Record<string,any>|null>} */
@@ -682,9 +608,15 @@ const isProcessed = ref(false);
682
608
  /** @type {import("vue").Ref<Record<string,any>|null>} */
683
609
  const jsonformSchema = ref(null);
684
610
 
685
- /** @type {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} */
686
- const jsonformEl = ref(null);
687
-
611
+ const jsonformEl =
612
+ /** @type {Readonly<import("vue").ShallowRef<import("@eox/jsonform").EOxJSONForm | null>>} */ (
613
+ useTemplateRef("jsonformEl")
614
+ );
615
+ const isAsync = computed(
616
+ () =>
617
+ selectedStac.value?.links.filter((l) => l.endpoint === "eoxhub_workspaces")
618
+ .length,
619
+ );
688
620
  const containerEl = useTemplateRef("container");
689
621
 
690
622
  const loading = ref(false);
@@ -695,91 +627,68 @@ const isPolling = ref(false);
695
627
  /** @type {import("vue").Ref<any[]>} */
696
628
  const processResults = ref([]);
697
629
 
630
+ const { selectedStac } = storeToRefs(useSTAcStore());
631
+
632
+ useInitProcess({
633
+ //@ts-expect-error TODO
634
+ selectedStac,
635
+ jsonformEl,
636
+ jsonformSchema,
637
+ chartSpec,
638
+ isProcessed,
639
+ processResults,
640
+ loading,
641
+ isPolling,
642
+ });
643
+
698
644
  const downloadResults = () => {
699
645
  processResults.value.forEach((result) => {
700
646
  if (!result) {
701
647
  return;
702
648
  }
703
- let url = "";
704
- let downloadFile = "";
649
+ let fileName = "";
705
650
  if (typeof result === "string") {
706
- url = result;
707
- //@ts-expect-error TODO
708
- downloadFile = url.includes("/") ? url.split("/").pop() : url;
709
- downloadFile = downloadFile.includes("?")
710
- ? downloadFile.split("?")[0]
711
- : downloadFile;
651
+ fileName = result.includes("/")
652
+ ? (result.split("/").pop() ?? "")
653
+ : result;
654
+ fileName = fileName.includes("?") ? fileName.split("?")[0] : fileName;
712
655
  } else {
713
- result = JSON.stringify(result);
714
- const blob = new Blob([result], { type: "text" });
715
- url = URL.createObjectURL(blob);
716
- downloadFile = selectedStac.value?.id + "_process_results.json";
717
- }
718
- const link = document.createElement("a");
719
- if (confirm(`Would you like to download ${downloadFile}?`)) {
720
- link.href = url;
721
- link.download = downloadFile;
722
- link.click();
656
+ fileName = selectedStac.value?.id + "_process_results.json";
723
657
  }
724
- URL.revokeObjectURL(url);
725
- link.remove();
658
+ download(fileName, result);
726
659
  });
727
660
  };
728
- onMounted(async () => {
729
- // wait for the layers to be rendered
730
- if (mapEl.value?.layers.length > 1) {
731
- await initProcess({
732
- //@ts-expect-error TODO
733
- selectedStac,
734
- jsonformEl,
735
- jsonformSchema,
736
- chartSpec,
737
- isProcessed,
738
- processResults,
739
- loading,
740
- isPolling,
741
- });
742
- } else {
743
- layersEvents.once(async () => {
744
- await initProcess({
745
- //@ts-expect-error TODO
746
- selectedStac,
747
- jsonformEl,
748
- jsonformSchema,
749
- chartSpec,
750
- isProcessed,
751
- loading,
752
- processResults,
753
- isPolling,
754
- });
755
- });
756
- }
757
- });
758
-
759
- useOnLayersUpdate(async (evt, _payload) => {
760
- if (evt === "layers:updated") {
761
- await initProcess({
762
- //@ts-expect-error TODO
763
- selectedStac,
764
- jsonformEl,
765
- jsonformSchema,
766
- chartSpec,
767
- isProcessed,
768
- processResults,
769
- loading,
770
- isPolling,
771
- });
772
- }
773
- });
774
661
 
775
662
  const startProcess = async () => {
776
- //@ts-expect-error todo
663
+ /** @param {*} jsonformSchema */
664
+ const getDrawToolsProperty = (jsonformSchema) => {
665
+ for (const property in jsonformSchema.properties) {
666
+ if (jsonformSchema.properties[property]?.options?.drawtools) {
667
+ return property;
668
+ }
669
+ }
670
+ };
671
+ const drawToolsProperty = getDrawToolsProperty(jsonformSchema.value);
672
+ const propertyIsEmpty =
673
+ drawToolsProperty &&
674
+ //@ts-expect-error jsonfrom.value is not typed
675
+ Array.isArray(jsonformEl.value?.value[drawToolsProperty]) &&
676
+ //@ts-expect-error jsonfrom.value is not typed
677
+ !jsonformEl.value?.value[drawToolsProperty].length;
678
+
679
+ if (propertyIsEmpty) {
680
+ isProcessed.value = false;
681
+ chartSpec.value = null;
682
+ return;
683
+ }
777
684
  const errors = jsonformEl.value?.editor.validate();
778
685
  if (errors?.length) {
779
686
  console.warn("[eodash] Form validation failed", errors);
780
687
  return;
781
688
  }
689
+
782
690
  processResults.value = [];
691
+
783
692
  await handleProcesses({
784
693
  jsonformEl,
785
694
  jsonformSchema,
@@ -791,7 +700,9 @@ const startProcess = async () => {
791
700
  isPolling,
792
701
  processResults,
793
702
  });
703
+
794
704
  isProcessed.value = true;
705
+ if (isAsync.value) updateJobsStatus(jobs, indicator);
795
706
  };
796
707
  useAutoExec(autoExec, jsonformEl, jsonformSchema, startProcess);
797
708
 
@@ -802,7 +713,6 @@ const chartStyles = computed(() => {
802
713
  styles["height"] =
803
714
  Math.max(
804
715
  (containerEl.value?.offsetHeight ?? 0) -
805
- //@ts-expect-error TODO
806
716
  (jsonformEl.value?.offsetHeight ?? 0),
807
717
  200,
808
718
  ) + "px";
@@ -812,9 +722,9 @@ const chartStyles = computed(() => {
812
722
 
813
723
  return (_ctx, _cache) => {
814
724
 
815
-
816
725
 
817
726
  return (openBlock(), createElementBlock("div", _hoisted_1, [
727
+ createVNode(_sfc_main$1),
818
728
  (jsonformSchema.value)
819
729
  ? (openBlock(), createElementBlock("eox-jsonform", {
820
730
  key: 0,
@@ -829,42 +739,38 @@ return (_ctx, _cache) => {
829
739
  class: "chart",
830
740
  ".spec": toRaw(chartSpec.value),
831
741
  ".dataValues": toRaw(chartData.value),
742
+ "onClick:item": _cache[0] || (_cache[0] = (...args) => (unref(onChartClick) && unref(onChartClick)(...args))),
832
743
  style: normalizeStyle(chartStyles.value)
833
744
  }, null, 44 /* STYLE, PROPS, NEED_HYDRATION */, _hoisted_3))
834
745
  : createCommentVNode("v-if", true),
835
- createVNode(VContainer, null, {
836
- default: withCtx(() => [
837
- createElementVNode("span", null, [
838
- (!autoExec.value)
839
- ? (openBlock(), createBlock(VBtn, {
840
- key: 0,
841
- loading: loading.value,
842
- style: {"float":"right","margin-right":"20px"},
843
- onClick: startProcess,
844
- color: "primary"
845
- }, {
846
- default: withCtx(() => _cache[0] || (_cache[0] = [
847
- createTextVNode(" Execute ")
848
- ])),
849
- _: 1 /* STABLE */
850
- }, 8 /* PROPS */, ["loading"]))
851
- : createCommentVNode("v-if", true),
852
- (processResults.value.length && isProcessed.value)
853
- ? (openBlock(), createBlock(VBtn, {
854
- key: 1,
855
- color: "primary",
856
- onClick: downloadResults
857
- }, {
858
- default: withCtx(() => _cache[1] || (_cache[1] = [
859
- createTextVNode(" Download ")
860
- ])),
861
- _: 1 /* STABLE */
862
- }))
863
- : createCommentVNode("v-if", true)
864
- ])
865
- ]),
866
- _: 1 /* STABLE */
867
- })
746
+ createElementVNode("div", _hoisted_4, [
747
+ (!autoExec.value)
748
+ ? (openBlock(), createBlock(VBtn, {
749
+ key: 0,
750
+ loading: loading.value,
751
+ style: {"margin-right":"20px"},
752
+ onClick: startProcess,
753
+ color: "primary"
754
+ }, {
755
+ default: withCtx(() => _cache[1] || (_cache[1] = [
756
+ createTextVNode(" Execute ")
757
+ ])),
758
+ _: 1 /* STABLE */
759
+ }, 8 /* PROPS */, ["loading"]))
760
+ : createCommentVNode("v-if", true),
761
+ (processResults.value.length && isProcessed.value && !isAsync.value)
762
+ ? (openBlock(), createBlock(VBtn, {
763
+ key: 1,
764
+ color: "primary",
765
+ onClick: downloadResults
766
+ }, {
767
+ default: withCtx(() => _cache[2] || (_cache[2] = [
768
+ createTextVNode(" Download ")
769
+ ])),
770
+ _: 1 /* STABLE */
771
+ }))
772
+ : createCommentVNode("v-if", true)
773
+ ])
868
774
  ], 512 /* NEED_PATCH */))
869
775
  }
870
776
  }