@eodash/eodash 5.0.0-rc.2.5 → 5.0.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 (77) 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 -18
  4. package/core/client/eodashSTAC/helpers.js +23 -0
  5. package/core/client/store/stac.js +3 -1
  6. package/core/client/types.ts +125 -19
  7. package/core/client/utils/states.js +9 -0
  8. package/dist/client/{DashboardLayout-BX3Sm_Vx.js → DashboardLayout-CkWvOMOW.js} +2 -2
  9. package/dist/client/{DynamicWebComponent-BqoHM1np.js → DynamicWebComponent-DYBbpvUK.js} +1 -1
  10. package/dist/client/{EodashDatePicker-BoWV2vc8.js → EodashDatePicker-CALmW3SI.js} +3 -83
  11. package/dist/client/{EodashItemFilter-127fZLyK.js → EodashItemFilter-DlQiE713.js} +1 -1
  12. package/dist/client/{EodashLayerControl-B-pZaizw.js → EodashLayerControl-DEzEbft7.js} +8 -2
  13. package/dist/client/{EodashLayoutSwitcher-DwexHfOD.js → EodashLayoutSwitcher-CDeCV8F-.js} +2 -2
  14. package/dist/client/{EodashMapBtns-Jfn3bpWD.js → EodashMapBtns-CktQCfa-.js} +36 -12
  15. package/dist/client/{EodashStacInfo-STq_bW7S.js → EodashStacInfo-DPPxDkF6.js} +7 -1
  16. package/dist/client/{EodashTools-uxSuJhVJ.js → EodashTools-CUaL9s4H.js} +5 -4
  17. package/dist/client/{ExportState-Ckcb6u01.js → ExportState-DjyIZVhl.js} +27 -12
  18. package/dist/client/{Footer-C8JP-coH.js → Footer-DyL0JoWt.js} +1 -1
  19. package/dist/client/{Header-Dxx7q9FW.js → Header-B5Dgty9l.js} +3 -3
  20. package/dist/client/{MobileLayout-BE19Peep.js → MobileLayout-CRsg_5Q4.js} +5 -5
  21. package/dist/client/{PopUp-D3IyjsN4.js → PopUp-BfB8s_ki.js} +3 -3
  22. package/dist/client/ProcessList-DTefwQZx.js +484 -0
  23. package/dist/client/{VImg-BmCNSu3X.js → VImg-FD1WVphJ.js} +2 -2
  24. package/dist/client/{VMain-eZDKIfmJ.js → VMain-DJKG4SvM.js} +1 -1
  25. package/dist/client/{VOverlay-BS-E4Z6g.js → VOverlay-BzOdRu9h.js} +15 -6
  26. package/dist/client/{VTooltip-BMsliOuh.js → VTooltip-CfeefrXI.js} +3 -3
  27. package/dist/client/{WidgetsContainer-Cl6M5R5c.js → WidgetsContainer-C2TaTdb6.js} +1 -1
  28. package/dist/client/{asWebComponent-Df8nUiLs.js → asWebComponent-CLhcT715.js} +100 -96
  29. package/dist/client/eo-dash.css +2 -2
  30. package/dist/client/eo-dash.js +1 -1
  31. package/dist/client/{forwardRefs-lhDuXD-N.js → forwardRefs-Bon_Kku1.js} +9 -9
  32. package/dist/client/index-4CT7Tz83.js +85 -0
  33. package/dist/client/{index-Bt5GEGxl.js → index-Bm9cbtx5.js} +1 -1
  34. package/dist/client/{EodashMap-BSR7_wRA.js → index-CIHH_3dW.js} +101 -80
  35. package/dist/client/{EodashProcess-CpbZPYBp.js → index-DiGDvTQU.js} +346 -468
  36. package/dist/client/{transition-DHEuQX4I.js → transition-C5I57hn6.js} +1 -1
  37. package/dist/types/core/client/components/MobileLayout.vue.d.ts +9 -9
  38. package/dist/types/core/client/eodashSTAC/helpers.d.ts +3 -2
  39. package/dist/types/core/client/types.d.ts +83 -17
  40. package/dist/types/core/client/utils/states.d.ts +7 -0
  41. package/dist/types/widgets/EodashDatePicker.vue.d.ts +4 -4
  42. package/dist/types/widgets/EodashItemFilter.vue.d.ts +18 -18
  43. package/dist/types/widgets/EodashLayerControl.vue.d.ts +2 -2
  44. package/dist/types/widgets/EodashLayoutSwitcher.vue.d.ts +2 -2
  45. package/dist/types/widgets/EodashMap/methods/create-layers-config.d.ts +9 -0
  46. package/dist/types/widgets/EodashMap/methods/index.d.ts +5 -0
  47. package/dist/types/widgets/EodashMapBtns.vue.d.ts +8 -2
  48. package/dist/types/widgets/EodashProcess/ProcessList.vue.d.ts +2 -0
  49. package/dist/types/widgets/EodashProcess/methods/async.d.ts +45 -0
  50. package/dist/types/widgets/EodashProcess/methods/composables.d.ts +19 -0
  51. package/dist/types/widgets/EodashProcess/methods/handling.d.ts +78 -0
  52. package/dist/types/widgets/EodashProcess/methods/outputs.d.ts +54 -0
  53. package/dist/types/widgets/EodashProcess/methods/utils.d.ts +42 -0
  54. package/dist/types/widgets/EodashStacInfo.vue.d.ts +12 -12
  55. package/dist/types/widgets/EodashTools.vue.d.ts +44 -6
  56. package/dist/types/widgets/PopUp.vue.d.ts +4 -4
  57. package/package.json +27 -27
  58. package/widgets/EodashLayerControl.vue +8 -1
  59. package/widgets/{EodashMap.vue → EodashMap/index.vue} +51 -31
  60. package/widgets/EodashMap/methods/create-layers-config.js +151 -0
  61. package/{core/client/composables/EodashMap.js → widgets/EodashMap/methods/index.js} +4 -153
  62. package/widgets/EodashMapBtns.vue +33 -7
  63. package/widgets/EodashProcess/ProcessList.vue +82 -0
  64. package/widgets/EodashProcess/index.vue +186 -0
  65. package/widgets/EodashProcess/methods/async.js +209 -0
  66. package/widgets/EodashProcess/methods/composables.js +129 -0
  67. package/widgets/EodashProcess/methods/handling.js +254 -0
  68. package/widgets/EodashProcess/methods/outputs.js +216 -0
  69. package/widgets/EodashProcess/methods/utils.js +138 -0
  70. package/widgets/EodashStacInfo.vue +6 -0
  71. package/widgets/EodashTools.vue +1 -0
  72. package/core/client/composables/EodashProcess.js +0 -654
  73. package/dist/types/core/client/composables/EodashMap.d.ts +0 -6
  74. package/dist/types/core/client/composables/EodashProcess.d.ts +0 -162
  75. package/widgets/EodashProcess.vue +0 -206
  76. /package/dist/types/widgets/{EodashMap.vue.d.ts → EodashMap/index.vue.d.ts} +0 -0
  77. /package/dist/types/widgets/{EodashProcess.vue.d.ts → EodashProcess/index.vue.d.ts} +0 -0
@@ -1,233 +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-Df8nUiLs.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-CLhcT715.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-DTefwQZx.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
- if (!jsonFormEl?.shadowRoot) {
222
- console.error("jsonform has no shadowRoot");
223
- return;
224
- }
225
- const stylesheet = new CSSStyleSheet();
226
- stylesheet.replaceSync(`.je-indented-panel {
227
- border: none !important;
228
- }`);
229
- jsonFormEl.shadowRoot.adoptedStyleSheets = [stylesheet];
230
- }
9
+ import mustache from 'mustache';
10
+ import { useEventBus } from '@vueuse/core';
231
11
 
232
12
  /**
233
13
  * @param {import("stac-ts").StacLink[] | undefined} links
@@ -311,19 +91,75 @@ async function processVector(links, jsonformValue, layerId) {
311
91
  return layers;
312
92
  }
313
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
+
314
143
  /**
315
144
  * @param {import("stac-ts").StacLink[] | undefined} links
316
145
  * @param {Record<string,any> | undefined} jsonformValue
317
146
  * @param {import("vue").Ref<boolean>} isPolling
318
147
  * @param {string} layerId
148
+ * @param {string} projection
319
149
  */
320
- async function processGeoTiff(links, jsonformValue, layerId, isPolling) {
150
+ async function processGeoTiff(
151
+ links,
152
+ jsonformValue,
153
+ layerId,
154
+ isPolling,
155
+ projection,
156
+ ) {
321
157
  if (!links) return;
322
158
  const geotiffLinks = links.filter(
323
159
  (link) => link.rel === "service" && link.type === "image/tiff",
324
160
  );
325
161
  let urls = [];
326
- let flatStyleJSON = null;
162
+ let processId = "";
327
163
  for (const link of geotiffLinks ?? []) {
328
164
  if (link.endpoint === "eoxhub_workspaces") {
329
165
  // TODO: prove of concept, needs to be reworked for sure
@@ -341,6 +177,12 @@ async function processGeoTiff(links, jsonformValue, layerId, isPolling) {
341
177
  },
342
178
  });
343
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));
344
186
  await pollProcessStatus({
345
187
  processUrl: responseProcess.headers.location,
346
188
  isPolling,
@@ -348,11 +190,12 @@ async function processGeoTiff(links, jsonformValue, layerId, isPolling) {
348
190
  .then((resultItem) => {
349
191
  // @ts-expect-error we have currently no definition of what is allowed as response
350
192
  const resultUrls = resultItem?.urls;
351
- if (!resultUrls?.length) {
193
+ if (resultUrls?.length < 1) {
352
194
  return;
353
195
  }
354
-
355
- urls.push(resultUrls[0]);
196
+ //@ts-expect-error todo
197
+ processId = resultItem?.id;
198
+ urls = resultUrls;
356
199
  })
357
200
  .catch((error) => {
358
201
  if (error instanceof Error) {
@@ -371,87 +214,65 @@ async function processGeoTiff(links, jsonformValue, layerId, isPolling) {
371
214
  } else {
372
215
  urls.push(mustache.render(link.href, { ...(jsonformValue ?? {}) }));
373
216
  }
374
- if ("eox:flatstyle" in (link ?? {})) {
375
- flatStyleJSON = await axios
376
- .get(/** @type {string} */ (link["eox:flatstyle"]))
377
- .then((resp) => resp.data);
378
- }
379
217
  }
380
- /** @type {Record<string,any>|undefined} */
381
- let layerConfig;
382
- /** @type {Record<string,any>|undefined} */
383
- let style;
384
- if (flatStyleJSON) {
385
- const extracted = extractLayerConfig(layerId ?? "", flatStyleJSON);
386
- layerConfig = extracted.layerConfig;
387
- style = extracted.style;
388
- }
389
- return urls.length
390
- ? {
391
- type: "WebGLTile",
392
- source: {
393
- type: "GeoTIFF",
394
- normalize: !style,
395
- sources: urls.map((url) => ({ url })),
396
- },
397
- properties: {
398
- id: layerId + "_geotiff_process",
399
- title: "Results " + layerId,
400
- ...(layerConfig && { layerConfig: layerConfig }),
401
- },
402
- ...(style && { style: style }),
403
- }
404
- : undefined;
218
+
219
+ return createLayerDefinition(links[0], layerId, urls, projection, processId);
405
220
  }
406
221
 
407
222
  /**
408
- * @param {import("stac-ts").StacLink[] | undefined} links
409
- * @param {Record<string,any> | undefined} jsonformValue
410
- * @param {string} specUrl
411
- * @returns {Promise<[import("@eox/chart").EOxChart["spec"] | null,Record<string,any>|null]>}
412
- **/
413
- async function getChartValues(links, jsonformValue, specUrl) {
414
- if (!specUrl || !links) return [null, null];
415
- /** @type {import("vega").Spec} */
416
- const spec = await axios.get(specUrl).then((resp) => {
417
- 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,
418
257
  });
419
- // //@ts-expect-error NamedData
420
- // const dataName = spec?.data?.name;
421
- const dataLinks = links.filter(
422
- (link) => link.rel === "service", // && dataName && link.id === dataName,
423
- );
424
-
425
- /** @type {Record<string,any>} */
426
- const dataValues = {};
427
- for (const link of dataLinks ?? []) {
428
- if (link.type && ["application/json", "text/csv"].includes(link.type)) {
429
- const dataUrl = mustache.render(link.href, {
430
- ...(jsonformValue ?? {}),
431
- ...(link["eox:flatstyle"] ?? {}),
432
- });
433
- // Wait for data to be retrieved
434
- const data = await axios.get(dataUrl).then((resp) => {
435
- return resp.data;
436
- });
437
- // @ts-expect-error we assume data to exist in spec
438
- spec.data.values = data;
439
- continue;
440
- }
441
-
442
- dataValues[/** @type {string} */ (link.id)] = await axios
443
- .get(
444
- mustache.render(link.href, {
445
- ...(jsonformValue ?? {}),
446
- ...(link["eox:flatstyle"] ?? {}),
447
- }),
448
- )
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"])
449
264
  .then((resp) => resp.data);
265
+ // remove borders from jsonform
266
+ } else {
267
+ if (!jsonformSchema.value) {
268
+ return;
269
+ }
270
+ jsonformSchema.value = null;
450
271
  }
451
- return [spec, dataValues];
452
272
  }
453
273
 
454
274
  /**
275
+ *
455
276
  * @param {Object} params
456
277
  * @param {import("vue").Ref<boolean>} params.loading
457
278
  * @param {import("vue").Ref<import("stac-ts").StacCollection | null>} params.selectedStac
@@ -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,66 +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
- jsonformEl.value?.editor.destroy();
489
+ }) => {
490
+ const layersEvents = useEventBus(eoxLayersKey);
491
+
492
+ onMounted(async () => {
642
493
  // wait for the layers to be rendered
643
- jsonformSchema.value = await axios
644
- //@ts-expect-error eodash extention
645
- .get(selectedStac.value["eodash:jsonform"])
646
- .then((resp) => resp.data);
647
- // jsonformSchema.value = {
648
- // "options": {
649
- // "execute": true
650
- // },
651
- // "type": "object",
652
- // "properties": {
653
- // "feature": {
654
- // "type": "string",
655
- // "title": "Select feature on map",
656
- // "options": {
657
- // drawtools:{
658
- // "for": "eox-map#main",
659
- // "layerId": "geodb-collection",
660
- // featureStyles:{
661
- // /** @type {import("ol/")} */
662
- // layer: {
663
-
664
- // },
665
- // // hover:{},
666
- // click:{
667
- // "stroke-width": 2,
668
- // "stroke-color": "red",
669
- // }
670
- // }
671
- // },
672
- // "featureProperty": "id"
673
- // },
674
- // "format": "feature"
675
- // }
676
- // }
677
- // }
678
- // 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 () => {
679
559
  await nextTick(() => {
680
- injectJsonformCSS(jsonformEl.value);
560
+ //@ts-expect-error TODO
561
+ jsonformEl.value?.addEventListener("change", onJsonFormChange);
681
562
  });
682
- } else {
683
- if (!jsonformSchema.value) {
684
- return;
685
- }
686
- jsonformSchema.value = null;
687
- }
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
+ });
688
586
  }
689
587
 
690
588
  const _hoisted_1 = {
@@ -693,16 +591,14 @@ const _hoisted_1 = {
693
591
  };
694
592
  const _hoisted_2 = [".schema"];
695
593
  const _hoisted_3 = [".spec", ".dataValues"];
594
+ const _hoisted_4 = { style: {"text-align":"right"} };
696
595
 
596
+ /** @type {import("vue").Ref<import("vega").Spec|null>} */
697
597
 
698
598
  const _sfc_main = {
699
- __name: 'EodashProcess',
599
+ __name: 'index',
700
600
  setup(__props) {
701
601
 
702
- const layersEvents = useEventBus(eoxLayersKey);
703
- const { selectedStac } = storeToRefs(useSTAcStore());
704
-
705
- /** @type {import("vue").Ref<import("vega").Spec|null>} */
706
602
  const chartSpec = ref(null);
707
603
 
708
604
  /** @type {import("vue").Ref<Record<string,any>|null>} */
@@ -712,9 +608,15 @@ const isProcessed = ref(false);
712
608
  /** @type {import("vue").Ref<Record<string,any>|null>} */
713
609
  const jsonformSchema = ref(null);
714
610
 
715
- /** @type {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} */
716
- const jsonformEl = ref(null);
717
-
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
+ );
718
620
  const containerEl = useTemplateRef("container");
719
621
 
720
622
  const loading = ref(false);
@@ -725,90 +627,68 @@ const isPolling = ref(false);
725
627
  /** @type {import("vue").Ref<any[]>} */
726
628
  const processResults = ref([]);
727
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
+
728
644
  const downloadResults = () => {
729
645
  processResults.value.forEach((result) => {
730
646
  if (!result) {
731
647
  return;
732
648
  }
733
- let url = "";
734
- let downloadFile = "";
649
+ let fileName = "";
735
650
  if (typeof result === "string") {
736
- url = result;
737
- //@ts-expect-error TODO
738
- downloadFile = url.includes("/") ? url.split("/").pop() : url;
739
- downloadFile = downloadFile.includes("?")
740
- ? downloadFile.split("?")[0]
741
- : downloadFile;
651
+ fileName = result.includes("/")
652
+ ? (result.split("/").pop() ?? "")
653
+ : result;
654
+ fileName = fileName.includes("?") ? fileName.split("?")[0] : fileName;
742
655
  } else {
743
- result = JSON.stringify(result);
744
- const blob = new Blob([result], { type: "text" });
745
- url = URL.createObjectURL(blob);
746
- downloadFile = selectedStac.value?.id + "_process_results.json";
656
+ fileName = selectedStac.value?.id + "_process_results.json";
747
657
  }
748
- const link = document.createElement("a");
749
- if (confirm(`Would you like to download ${downloadFile}?`)) {
750
- link.href = url;
751
- link.download = downloadFile;
752
- link.click();
753
- }
754
- URL.revokeObjectURL(url);
755
- link.remove();
658
+ download(fileName, result);
756
659
  });
757
660
  };
758
- onMounted(async () => {
759
- // wait for the layers to be rendered
760
- if (mapEl.value?.layers.length > 1) {
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
- } else {
773
- layersEvents.once(async () => {
774
- await initProcess({
775
- //@ts-expect-error TODO
776
- selectedStac,
777
- jsonformEl,
778
- jsonformSchema,
779
- chartSpec,
780
- isProcessed,
781
- loading,
782
- processResults,
783
- isPolling,
784
- });
785
- });
786
- }
787
- });
788
-
789
- useOnLayersUpdate(async (evt, _payload) => {
790
- if (evt === "layers:updated") {
791
- await initProcess({
792
- //@ts-expect-error TODO
793
- selectedStac,
794
- jsonformEl,
795
- jsonformSchema,
796
- chartSpec,
797
- isProcessed,
798
- processResults,
799
- loading,
800
- isPolling,
801
- });
802
- }
803
- });
804
661
 
805
662
  const startProcess = async () => {
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
+ }
806
684
  const errors = jsonformEl.value?.editor.validate();
807
685
  if (errors?.length) {
808
686
  console.warn("[eodash] Form validation failed", errors);
809
687
  return;
810
688
  }
689
+
811
690
  processResults.value = [];
691
+
812
692
  await handleProcesses({
813
693
  jsonformEl,
814
694
  jsonformSchema,
@@ -820,7 +700,9 @@ const startProcess = async () => {
820
700
  isPolling,
821
701
  processResults,
822
702
  });
703
+
823
704
  isProcessed.value = true;
705
+ if (isAsync.value) updateJobsStatus(jobs, indicator);
824
706
  };
825
707
  useAutoExec(autoExec, jsonformEl, jsonformSchema, startProcess);
826
708
 
@@ -840,9 +722,9 @@ const chartStyles = computed(() => {
840
722
 
841
723
  return (_ctx, _cache) => {
842
724
 
843
-
844
725
 
845
726
  return (openBlock(), createElementBlock("div", _hoisted_1, [
727
+ createVNode(_sfc_main$1),
846
728
  (jsonformSchema.value)
847
729
  ? (openBlock(), createElementBlock("eox-jsonform", {
848
730
  key: 0,
@@ -857,42 +739,38 @@ return (_ctx, _cache) => {
857
739
  class: "chart",
858
740
  ".spec": toRaw(chartSpec.value),
859
741
  ".dataValues": toRaw(chartData.value),
742
+ "onClick:item": _cache[0] || (_cache[0] = (...args) => (unref(onChartClick) && unref(onChartClick)(...args))),
860
743
  style: normalizeStyle(chartStyles.value)
861
744
  }, null, 44 /* STYLE, PROPS, NEED_HYDRATION */, _hoisted_3))
862
745
  : createCommentVNode("v-if", true),
863
- createVNode(VContainer, null, {
864
- default: withCtx(() => [
865
- createElementVNode("span", null, [
866
- (!autoExec.value)
867
- ? (openBlock(), createBlock(VBtn, {
868
- key: 0,
869
- loading: loading.value,
870
- style: {"float":"right","margin-right":"20px"},
871
- onClick: startProcess,
872
- color: "primary"
873
- }, {
874
- default: withCtx(() => _cache[0] || (_cache[0] = [
875
- createTextVNode(" Execute ")
876
- ])),
877
- _: 1 /* STABLE */
878
- }, 8 /* PROPS */, ["loading"]))
879
- : createCommentVNode("v-if", true),
880
- (processResults.value.length && isProcessed.value)
881
- ? (openBlock(), createBlock(VBtn, {
882
- key: 1,
883
- color: "primary",
884
- onClick: downloadResults
885
- }, {
886
- default: withCtx(() => _cache[1] || (_cache[1] = [
887
- createTextVNode(" Download ")
888
- ])),
889
- _: 1 /* STABLE */
890
- }))
891
- : createCommentVNode("v-if", true)
892
- ])
893
- ]),
894
- _: 1 /* STABLE */
895
- })
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
+ ])
896
774
  ], 512 /* NEED_PATCH */))
897
775
  }
898
776
  }