@eodash/eodash 5.6.0 → 5.7.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 (91) hide show
  1. package/core/client/components/DashboardLayout.vue +1 -1
  2. package/core/client/composables/index.js +6 -2
  3. package/core/client/eodashSTAC/EodashCollection.js +5 -21
  4. package/core/client/eodashSTAC/createLayers.js +23 -9
  5. package/core/client/eodashSTAC/helpers.js +37 -4
  6. package/core/client/types.ts +8 -1
  7. package/core/client/utils/index.js +4 -0
  8. package/dist/client/{DashboardLayout-DkKDhfgH.js → DashboardLayout-kRsmsNW5.js} +5 -5
  9. package/dist/client/{DynamicWebComponent-BrpkA-e3.js → DynamicWebComponent-CnKhYo0K.js} +1 -1
  10. package/dist/client/{EodashChart-p7_1FRlF.js → EodashChart-CLDqE93C.js} +4 -4
  11. package/dist/client/{EodashDatePicker-HK0Jl7wQ.js → EodashDatePicker-CMPDT-ce.js} +3 -3
  12. package/dist/client/{EodashItemFilter-BYQDA78B.js → EodashItemFilter-BpdA8QQa.js} +1 -1
  13. package/dist/client/{EodashLayerControl-NcrNncGn.js → EodashLayerControl-BHpDA4_0.js} +25 -7
  14. package/dist/client/{EodashLayoutSwitcher-CC2Znd0I.js → EodashLayoutSwitcher-B1fRUt7G.js} +3 -3
  15. package/dist/client/EodashMapBtns-Cpned0tc.js +478 -0
  16. package/dist/client/{EodashStacInfo-BA-0UjvT.js → EodashStacInfo-BQspAHKH.js} +31 -31
  17. package/dist/client/{EodashTools-CWmoH0g_.js → EodashTools-1zHz26gv.js} +4 -4
  18. package/dist/client/{ExportState-CfAfX4RN.js → ExportState-DbOm8hBI.js} +4 -4
  19. package/dist/client/{Footer-DLGxQTZt.js → Footer-BKg-VVkj.js} +1 -1
  20. package/dist/client/{Header-eyEyyzD6.js → Header-DCrwCvmY.js} +2 -2
  21. package/dist/client/MobileLayout-vWSHpluo.js +118 -0
  22. package/dist/client/{PopUp-WNs6Io2N.js → PopUp-9uimfK49.js} +2 -2
  23. package/dist/client/{ProcessList-RzVqbd5E.js → ProcessList-CTTIZa06.js} +4 -4
  24. package/dist/client/{VImg-GKUTFoV-.js → VImg-CrmB76ZY.js} +2 -2
  25. package/dist/client/{VMain-D7_72mHr.js → VMain-OKZNpcEG.js} +1 -1
  26. package/dist/client/{VTooltip-BbmvtvYw.js → VTooltip-CJw2FyWk.js} +2 -2
  27. package/dist/client/{WidgetsContainer-Dw5d7SOW.js → WidgetsContainer-BaWOnE5R.js} +1 -1
  28. package/dist/client/{asWebComponent-DDt7V3Bl.js → asWebComponent-BHWpMuE3.js} +47 -35
  29. package/dist/client/{async-CT3KEV52.js → async-DSKj6g1f.js} +29 -28
  30. package/dist/client/create-layers-config-CBoYedqB.js +182 -0
  31. package/dist/client/eo-dash.js +1 -1
  32. package/dist/client/{forwardRefs-CVzxyoSq.js → forwardRefs-DH51zPUr.js} +2 -2
  33. package/dist/client/{handling-C285F_Mq.js → handling-BrcDDlgS.js} +452 -114
  34. package/dist/client/{helpers-CZFH0EVN.js → helpers-DjZVl_WF.js} +2277 -1504
  35. package/dist/client/{index-B-m7V3Kb.js → index-1JKE68n3.js} +49 -194
  36. package/dist/client/{index-CF3ZMzTz.js → index-5Jhsa8Xe.js} +3 -3
  37. package/dist/client/index-CSG_JoOA.js +436 -0
  38. package/dist/client/{index-DgOXD7wd.js → index-CUjl-ZsI.js} +2 -2
  39. package/dist/client/{index-B_6H-N14.js → index-Cu3-13Xg.js} +84 -90
  40. package/dist/client/material-symbols-outlined.woff2 +0 -0
  41. package/dist/client/material-symbols-rounded.woff2 +0 -0
  42. package/dist/client/material-symbols-sharp.woff2 +0 -0
  43. package/dist/client/material-symbols-subset.woff2 +0 -0
  44. package/dist/client/templates.js +1 -1
  45. package/dist/client/{transition-C2gnrWg0.js → transition-OHcz5Qq1.js} +1 -1
  46. package/dist/node/cli.js +1 -1
  47. package/dist/types/core/client/composables/index.d.ts +1 -3
  48. package/dist/types/core/client/eodashSTAC/EodashCollection.d.ts +6 -7
  49. package/dist/types/core/client/eodashSTAC/createLayers.d.ts +3 -3
  50. package/dist/types/core/client/eodashSTAC/helpers.d.ts +1 -0
  51. package/dist/types/core/client/types.d.ts +8 -1
  52. package/dist/types/templates/baseConfig.d.ts +12 -0
  53. package/dist/types/widgets/EodashLayerControl.vue.d.ts +1 -1
  54. package/dist/types/widgets/EodashMap/EodashMapBtns.vue.d.ts +9 -0
  55. package/dist/types/widgets/EodashMap/index.vue.d.ts +7 -0
  56. package/dist/types/widgets/EodashMap/methods/create-layers-config.d.ts +1 -8
  57. package/dist/types/widgets/EodashProcess/methods/composables.d.ts +2 -3
  58. package/dist/types/widgets/EodashProcess/methods/handling.d.ts +15 -10
  59. package/dist/types/widgets/EodashProcess/methods/outputs.d.ts +3 -1
  60. package/dist/types/widgets/EodashProcess/methods/template-helpers.d.ts +99 -0
  61. package/dist/types/widgets/EodashProcess/methods/utils.d.ts +1 -6
  62. package/dist/types/widgets/EodashProcess/types.d.ts +1 -0
  63. package/dist/types/widgets/EodashStacInfo.vue.d.ts +10 -10
  64. package/dist/types/widgets/EodashTimeSlider/index.vue.d.ts +34 -0
  65. package/dist/types/widgets/EodashTimeSlider/methods/index.d.ts +39 -0
  66. package/dist/types/widgets/EodashTimeSlider/types.d.ts +62 -0
  67. package/package.json +32 -32
  68. package/widgets/EodashLayerControl.vue +22 -3
  69. package/widgets/EodashMap/EodashMapBtns.vue +46 -1
  70. package/widgets/EodashMap/index.vue +17 -5
  71. package/widgets/EodashMap/methods/create-layers-config.js +2 -0
  72. package/widgets/EodashMap/methods/index.js +23 -5
  73. package/widgets/EodashProcess/index.vue +17 -13
  74. package/widgets/EodashProcess/methods/async.js +19 -8
  75. package/widgets/EodashProcess/methods/composables.js +63 -74
  76. package/widgets/EodashProcess/methods/custom-endpoints/chart/sentinelhub-endpoint.js +9 -5
  77. package/widgets/EodashProcess/methods/custom-endpoints/chart/veda-endpoint.js +7 -4
  78. package/widgets/EodashProcess/methods/handling.js +125 -76
  79. package/widgets/EodashProcess/methods/outputs.js +74 -29
  80. package/widgets/EodashProcess/methods/template-helpers.js +246 -0
  81. package/widgets/EodashProcess/methods/utils.js +7 -17
  82. package/widgets/EodashProcess/types.ts +1 -0
  83. package/widgets/EodashStacInfo.vue +30 -30
  84. package/widgets/EodashTimeSlider/index.vue +152 -0
  85. package/widgets/EodashTimeSlider/methods/index.js +279 -0
  86. package/widgets/EodashTimeSlider/types.ts +64 -0
  87. package/dist/client/EodashMapBtns-BJSh7qT-.js +0 -435
  88. package/dist/client/EodashTimeSlider-GDv1hbw7.js +0 -53
  89. package/dist/client/MobileLayout-RzLOyXwL.js +0 -118
  90. package/dist/types/widgets/EodashTimeSlider.vue.d.ts +0 -15
  91. package/widgets/EodashTimeSlider.vue +0 -40
@@ -1,9 +1,7 @@
1
1
  import { initProcess, updateJsonformIdentifier } from "./handling";
2
- import { useEventBus } from "@vueuse/core";
3
- import { nextTick, onMounted, watch } from "vue";
4
- import { eoxLayersKey } from "@/utils/keys";
2
+ import { nextTick, onMounted, onUnmounted, watch } from "vue";
5
3
  import { useOnLayersUpdate } from "@/composables";
6
-
4
+ import { getCompareLayers, getLayers } from "@/store/actions";
7
5
  /**
8
6
  * Composable resposible of timing the Initialization of the process
9
7
  *
@@ -11,17 +9,15 @@ import { useOnLayersUpdate } from "@/composables";
11
9
  * @async
12
10
  * @param {Object} params
13
11
  * @param {import("vue").Ref<import("stac-ts").StacCollection | null>} params.selectedStac
14
- * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} params.jsonformEl
15
12
  * @param {import("vue").Ref<Record<string,any> | null>} params.jsonformSchema
16
13
  * @param {import("vue").Ref<any[]>} params.processResults
17
14
  * @param {import("vue").Ref<boolean>} params.isProcessed
18
15
  * @param {import("vue").Ref<boolean>} params.loading
19
16
  * @param {import("vue").Ref<boolean>} params.isPolling
20
- * @param {import("@eox/map").EOxMap | null} params.mapElement
17
+ * @param {import("vue").Ref<import("@eox/map").EOxMap | null>} params.mapElement
21
18
  */
22
19
  export const useInitProcess = ({
23
20
  selectedStac,
24
- jsonformEl,
25
21
  jsonformSchema,
26
22
  isProcessed,
27
23
  processResults,
@@ -29,64 +25,56 @@ export const useInitProcess = ({
29
25
  isPolling,
30
26
  mapElement,
31
27
  }) => {
32
- const layersEvents = useEventBus(eoxLayersKey);
33
-
34
28
  onMounted(async () => {
35
- // wait for the layers to be rendered
36
- if ((mapElement?.layers.length ?? 0) > 1) {
37
- await initProcess({
38
- enableCompare: mapElement?.id === "compare",
39
- selectedStac,
40
- jsonformEl,
41
- jsonformSchema,
42
- isProcessed,
43
- processResults,
44
- loading,
45
- isPolling,
46
- });
47
- } else {
48
- layersEvents.once(async () => {
49
- await initProcess({
50
- enableCompare: mapElement?.id === "compare",
51
- selectedStac,
52
- jsonformEl,
53
- jsonformSchema,
54
- isProcessed,
55
- loading,
56
- processResults,
57
- isPolling,
58
- });
59
- });
60
- }
29
+ await initProcess({
30
+ enableCompare: mapElement.value?.id === "compare",
31
+ selectedStac,
32
+ jsonformSchema,
33
+ isProcessed,
34
+ processResults,
35
+ loading,
36
+ isPolling,
37
+ mapElement: mapElement.value,
38
+ });
61
39
  });
62
40
 
63
- const evtKey =
64
- mapElement?.id === "compare" ? "compareLayers:updated" : "layers:updated";
65
- useOnLayersUpdate(async (evt, _payload) => {
66
- if (
67
- evt == "layertime:updated" ||
68
- evt == "compareLayertime:updated" ||
69
- evt == "time:updated" ||
70
- evt == "compareTime:updated"
71
- ) {
72
- await updateJsonformIdentifier({
41
+ useOnLayersUpdate(async (evt) => {
42
+ const enableCompare = mapElement.value?.id === "compare";
43
+ const layerUpdatedKey = enableCompare
44
+ ? "compareLayers:updated"
45
+ : "layers:updated";
46
+ const timeUpdatedKeys = enableCompare
47
+ ? ["compareLayertime:updated", "compareTime:updated"]
48
+ : ["layertime:updated", "time:updated"];
49
+
50
+ if (timeUpdatedKeys.includes(evt)) {
51
+ // we need to update jsonform on time change in cases
52
+ // when the feature selection layer was time-based,
53
+ // so that it attaches to a correct new layer
54
+ const newJsonForm = await updateJsonformIdentifier({
73
55
  jsonformSchema: jsonformSchema.value,
74
- // @ts-expect-error TODO payload coming from time update events is not an object with layers property
75
- newLayers: _payload,
56
+ newLayers: enableCompare ? getCompareLayers() : getLayers(),
57
+ enableCompare,
58
+ mapElement: mapElement.value,
76
59
  });
60
+
61
+ if (newJsonForm) {
62
+ jsonformSchema.value = newJsonForm;
63
+ }
77
64
  }
78
- if (evt !== evtKey) {
65
+
66
+ if (evt !== layerUpdatedKey) {
79
67
  return;
80
68
  }
81
69
  await initProcess({
82
- enableCompare: mapElement?.id === "compare",
70
+ enableCompare,
83
71
  selectedStac,
84
- jsonformEl,
85
72
  jsonformSchema,
86
73
  isProcessed,
87
74
  processResults,
88
75
  loading,
89
76
  isPolling,
77
+ mapElement: mapElement.value,
90
78
  });
91
79
  });
92
80
  };
@@ -106,38 +94,39 @@ export function useAutoExec(
106
94
  startProcess,
107
95
  ) {
108
96
  /**
109
- * @param {CustomEvent} _e
97
+ * @param {any} _e
110
98
  **/
111
99
  const onJsonFormChange = async (_e) => {
112
100
  await startProcess();
113
101
  };
114
102
 
115
- const addEventListener = async () => {
116
- await nextTick(() => {
117
- //@ts-expect-error TODO
118
- jsonformEl.value?.addEventListener("change", onJsonFormChange);
119
- });
120
- };
121
- const removeEventListener = () => {
122
- //@ts-expect-error TODO
123
- jsonformEl.value?.removeEventListener("change", onJsonFormChange);
124
- };
125
-
126
103
  watch(jsonformSchema, (updatedSchema) => {
127
104
  autoExec.value = updatedSchema?.options?.["execute"] || false;
128
105
  });
129
106
 
130
- onMounted(() => {
131
- watch(
132
- autoExec,
133
- async (exec) => {
134
- if (exec) {
135
- await addEventListener();
136
- } else {
137
- removeEventListener();
138
- }
139
- },
140
- { immediate: true },
141
- );
107
+ // Re-attach listener whenever the element or autoExec changes
108
+ const stop = watch(
109
+ [autoExec, jsonformEl],
110
+ async ([exec, el], [_prevExec, prevEl]) => {
111
+ // Cleanup if previous element existed
112
+ if (prevEl) {
113
+ prevEl.removeEventListener("change", onJsonFormChange);
114
+ }
115
+ // Add if enabled and we have an element
116
+ if (exec && el) {
117
+ // remove listener before adding to avoid duplicates in case of element change
118
+ el.removeEventListener("change", onJsonFormChange);
119
+ await nextTick();
120
+ el.addEventListener("change", onJsonFormChange);
121
+ }
122
+ },
123
+ { immediate: true },
124
+ );
125
+
126
+ onUnmounted(() => {
127
+ if (jsonformEl.value) {
128
+ jsonformEl.value.removeEventListener("change", onJsonFormChange);
129
+ }
130
+ stop();
142
131
  });
143
132
  }
@@ -58,7 +58,7 @@ export async function handleSentinelHubProcess({
58
58
  );
59
59
 
60
60
  // fetch data from sentinel hub
61
- return await Promise.all(
61
+ const results = await Promise.all(
62
62
  timePairs.map(([to, from]) => {
63
63
  return fetchSentinelHubData({
64
64
  url: endpoint,
@@ -67,14 +67,18 @@ export async function handleSentinelHubProcess({
67
67
  from,
68
68
  to,
69
69
  exampleLink: evalScriptLink,
70
- }).catch((err) =>
70
+ }).catch((err) => {
71
71
  console.error(
72
72
  "[eodash] Error while fetching data from sentinel hub endpoint:",
73
73
  err,
74
- ),
75
- );
74
+ );
75
+ return [];
76
+ });
76
77
  }),
77
- ).then((data) => data.flat().map((data) => data.outputs.data));
78
+ )
79
+ .then((data) => data.filter((result) => result.length > 0))
80
+ .then((data) => data.flat().map((data) => data.outputs.data));
81
+ return results;
78
82
  }
79
83
 
80
84
  /**
@@ -37,7 +37,7 @@ export async function handleVedaEndpoint({
37
37
  vedaLink,
38
38
  );
39
39
  // TODO: convert jsonform bbox type to geojson in the schema to avoid the conversion here
40
- return await Promise.all(
40
+ const results = await Promise.all(
41
41
  configs.map(({ endpoint, datetime }) => {
42
42
  const url = new URL(vedaEndpoint);
43
43
  const key = vedaLink.endpoint === "veda_stac" ? "ids" : "url";
@@ -56,14 +56,17 @@ export async function handleVedaEndpoint({
56
56
  fetchedSats.date = datetime;
57
57
  return fetchedSats;
58
58
  })
59
- .catch((resp) =>
59
+ .catch((resp) => {
60
60
  console.error(
61
61
  "[eodash] Error while fetching data from veda endpoint:",
62
62
  resp,
63
- ),
64
- );
63
+ );
64
+ return null;
65
+ });
65
66
  }),
66
67
  );
68
+ // Filter out the nulls (failed requests) before returning
69
+ return results.filter((result) => result !== null);
67
70
  }
68
71
 
69
72
  /**
@@ -3,8 +3,7 @@ import {
3
3
  applyProcessLayersToMap,
4
4
  extractGeometries,
5
5
  getBboxProperty,
6
- getDrawToolsProperty,
7
- updateJsonformSchemaTarget,
6
+ getDrawToolsProperties,
8
7
  } from "./utils";
9
8
  import {
10
9
  compareIndicator,
@@ -17,13 +16,12 @@ import {
17
16
  compareChartData,
18
17
  compareChartSpec,
19
18
  } from "@/store/states";
20
- import axios from "@/plugins/axios";
21
19
  import { processCharts, processLayers, processSTAC } from "./outputs";
22
20
  import { handleLayersCustomEndpoints } from "./custom-endpoints/layers";
23
21
  import { handleChartCustomEndpoints } from "./custom-endpoints/chart";
24
22
  import { useSTAcStore } from "@/store/stac";
25
23
  import { useGetSubCodeId } from "@/composables";
26
- import { getLayers } from "@/store/actions";
24
+ import { getLayers, getCompareLayers } from "@/store/actions";
27
25
 
28
26
  /**
29
27
  * Fetch and set the jsonform schema to initialize the process
@@ -32,37 +30,58 @@ import { getLayers } from "@/store/actions";
32
30
  * @async
33
31
  * @param {Object} params
34
32
  * @param {import("vue").Ref<import("stac-ts").StacCollection | null>} params.selectedStac
35
- * @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} params.jsonformEl
36
33
  * @param {import("vue").Ref<Record<string,any> | null>} params.jsonformSchema
37
34
  * @param {import("vue").Ref<any[]>} params.processResults
38
35
  * @param {import("vue").Ref<boolean>} params.isProcessed
39
36
  * @param {import("vue").Ref<boolean>} params.loading
40
37
  * @param {import("vue").Ref<boolean>} params.isPolling
38
+ * @param {import("@eox/map").EOxMap | null} params.mapElement
41
39
  * @param {boolean} params.enableCompare
42
40
  */
43
41
  export async function initProcess({
44
42
  selectedStac,
45
- jsonformEl,
46
43
  jsonformSchema,
47
44
  isProcessed,
48
45
  processResults,
49
46
  loading,
50
47
  isPolling,
51
48
  enableCompare,
49
+ mapElement,
52
50
  }) {
53
51
  const isPoiAlive = enableCompare ? !!comparePoi.value : !!poi.value;
54
52
  let updatedJsonform = null;
55
53
  if (selectedStac.value?.["eodash:jsonform"]) {
56
- updatedJsonform = await axios
54
+ updatedJsonform = await fetch(
57
55
  //@ts-expect-error eodash extention
58
- .get(selectedStac.value["eodash:jsonform"])
59
- .then((resp) => resp.data);
56
+ selectedStac.value["eodash:jsonform"],
57
+ ).then((resp) => resp.json());
60
58
  }
61
59
 
62
60
  if (!updatedJsonform && isPoiAlive) {
63
61
  jsonformSchema.value = null;
64
62
  return;
65
63
  }
64
+
65
+ if (!updatedJsonform) {
66
+ resetProcess({
67
+ loading,
68
+ isProcessed,
69
+ jsonformSchema,
70
+ isPolling,
71
+ processResults,
72
+ enableCompare,
73
+ });
74
+ return;
75
+ }
76
+
77
+ const newJsonForm = await updateJsonformIdentifier({
78
+ jsonformSchema: updatedJsonform,
79
+ newLayers: enableCompare ? getCompareLayers() : getLayers(),
80
+ enableCompare,
81
+ mapElement,
82
+ });
83
+ if (!newJsonForm) return;
84
+
66
85
  resetProcess({
67
86
  loading,
68
87
  isProcessed,
@@ -71,89 +90,109 @@ export async function initProcess({
71
90
  processResults,
72
91
  enableCompare,
73
92
  });
93
+ jsonformSchema.value = newJsonForm;
94
+ }
74
95
 
75
- await jsonformEl.value?.editor.destroy();
76
- if (updatedJsonform) {
77
- // make sure correct target layer id is used in jsonform
78
- let newJsonForm = null;
79
- newJsonForm = await updateJsonformIdentifier({
80
- jsonformSchema: updatedJsonform,
81
- newLayers: getLayers(),
82
- });
83
- if (enableCompare) {
84
- newJsonForm = updateJsonformSchemaTarget(newJsonForm);
96
+ /**
97
+ * Recursively search grouped layer tree for a layer whose id starts with the given prefix
98
+ *
99
+ * @param {Record<string, any>[]} layers
100
+ * @param {string} prefix
101
+ * @returns {string | null}
102
+ */
103
+ function findLayerIdByPrefix(layers, prefix) {
104
+ for (const layer of layers) {
105
+ if (layer.type === "Group" && Array.isArray(layer.layers)) {
106
+ const found = findLayerIdByPrefix(layer.layers, prefix);
107
+ if (found) return found;
108
+ } else if (layer.properties?.id?.startsWith(prefix)) {
109
+ return layer.properties.id;
85
110
  }
86
- // trigger jsonform update in next tick
87
- jsonformSchema.value = null;
88
- await new Promise((resolve) => setTimeout(resolve, 0));
89
- jsonformSchema.value = newJsonForm;
90
111
  }
112
+ return null;
91
113
  }
92
114
 
93
115
  /**
94
- * Update the jsonform schema to have the correct layer id from the map
116
+ * Wait until a layer's features are loaded for the drawtools to attach correctly
117
+ * Resolves immediately if already loaded.
118
+ *
119
+ * @param {import("@eox/map").AnyLayerWithSource | null | undefined} layer
120
+ * @returns {Promise<void>}
121
+ */
122
+ function waitForLayerRender(layer) {
123
+ return new Promise((resolve, reject) => {
124
+ if (!layer || layer.get("type") !== "Vector" || !("getSource" in layer))
125
+ return resolve();
126
+ const source = /** @type {import("ol/source/Vector").default} */ (
127
+ layer.getSource()
128
+ );
129
+ if (!source || source.getFeatures().length > 0) return resolve();
130
+ source.once("featuresloadend", () => resolve());
131
+ source.once("featuresloaderror", () =>
132
+ reject(new Error(`Layer ${layer.get("id")} failed to load features`)),
133
+ );
134
+ });
135
+ }
136
+
137
+ /**
138
+ * Update the jsonform schema to have the correct layer id from the map.
139
+ * Returns null if any required layerId cannot be resolved (layer not yet in map).
140
+ * Callers should treat null as "retry when layers:updated fires".
95
141
  *
96
142
  * @export
97
- * @async
98
143
  * @param {Object} params
99
- * @param {Record<string,any> | null} params.jsonformSchema params.jsonformSchema
100
- * @param {Record<string, any>[] | undefined} params.newLayers params.newLayers
101
- * @returns {Promise<Record<string,any> | null | undefined>} updated jsonform schema
144
+ * @param {Record<string,any> | null} params.jsonformSchema
145
+ * @param {Record<string, any>[] | undefined} params.newLayers
146
+ * @param {boolean} params.enableCompare
147
+ * @param {import("@eox/map").EOxMap | null | undefined} params.mapElement
148
+ * @returns {Promise<Record<string,any> | null>} updated schema, or null if a layerId could not be resolved
102
149
  */
103
- export async function updateJsonformIdentifier({ jsonformSchema, newLayers }) {
104
- const form = jsonformSchema;
105
- if (!form) {
106
- return;
107
- }
108
- const drawToolsProperty = getDrawToolsProperty(form);
109
- if (
110
- drawToolsProperty &&
111
- newLayers &&
112
- form?.properties[drawToolsProperty]?.options?.drawtools?.layerId
113
- ) {
114
- // get partial or full id and try to match with correct eoxmap layer
115
- // check if newLayers is an array or an object with layers property
116
- let layers = newLayers;
117
- // @ts-expect-error TODO payload coming from time update sometimes is not an object with layers property
118
- if (newLayers.layers && Array.isArray(newLayers.layers)) {
119
- // @ts-expect-error TODO payload coming from time update sometimes is not an object with layers property
120
- layers = newLayers.layers;
150
+ export async function updateJsonformIdentifier({
151
+ jsonformSchema,
152
+ newLayers,
153
+ enableCompare,
154
+ mapElement,
155
+ }) {
156
+ if (!jsonformSchema || !newLayers) return null;
157
+
158
+ const form = JSON.parse(JSON.stringify(jsonformSchema));
159
+ const drawToolsProperties = getDrawToolsProperties(form);
160
+ /** @type {Promise<void>[]} */
161
+ const renderPromises = [];
162
+
163
+ for (const drawToolsProperty of drawToolsProperties) {
164
+ if (!drawToolsProperty) continue;
165
+
166
+ const drawtoolsOptions =
167
+ form?.properties[drawToolsProperty]?.options?.drawtools;
168
+ if (!drawtoolsOptions) continue;
169
+
170
+ if (drawtoolsOptions.for && enableCompare) {
171
+ drawtoolsOptions.for = "eox-map#compare";
121
172
  }
122
173
 
123
- const layerId =
124
- form.properties[drawToolsProperty].options.drawtools.layerId.split(
125
- ";:;",
126
- )[0];
127
- let matchedLayerId = null;
128
- // layers are not flat can be grouped, we need to recursively search
129
- const traverseLayers = (
130
- /** @type {Record<string, any>[] | undefined} */ layersArray,
131
- ) => {
132
- if (!layersArray) {
133
- return;
134
- }
135
- for (const layer of layersArray) {
136
- if (layer.type === "Group" && Array.isArray(layer.layers)) {
137
- traverseLayers(layer.layers);
138
- } else {
139
- if (layer.properties?.id?.startsWith(layerId)) {
140
- matchedLayerId = layer.properties.id;
141
- break;
142
- }
174
+ if (drawtoolsOptions.layerId) {
175
+ let layer = mapElement?.getLayerById(drawtoolsOptions.layerId);
176
+ if (!layer) {
177
+ const prefix = drawtoolsOptions.layerId.split(";:;")[0];
178
+ const resolvedId = findLayerIdByPrefix(newLayers, prefix);
179
+ if (!resolvedId) {
180
+ console.warn(
181
+ `Could not find matching layer for processing form with id: ${prefix}`,
182
+ );
183
+ return null;
143
184
  }
185
+ drawtoolsOptions.layerId = resolvedId;
186
+ layer = mapElement?.getLayerById(resolvedId);
144
187
  }
145
- };
146
- traverseLayers(layers);
147
- if (matchedLayerId) {
148
- form.properties.feature.options.drawtools.layerId = matchedLayerId;
149
- return form;
150
- } else {
151
- console.warn(
152
- `Could not find matching layer for processing form with id: ${layerId}`,
153
- );
154
- return null;
188
+ renderPromises.push(waitForLayerRender(layer));
155
189
  }
156
190
  }
191
+
192
+ await Promise.all(renderPromises).catch((err) => {
193
+ console.warn("[eodash] layer load failed before jsonform attach:", err);
194
+ });
195
+
157
196
  return form;
158
197
  }
159
198
 
@@ -192,6 +231,15 @@ export async function handleProcesses({
192
231
  );
193
232
 
194
233
  const bboxProperty = getBboxProperty(jsonformSchema.value);
234
+ // Preserve raw form value before extractGeometries mutates it.
235
+ // Needed so POST multiQuery can iterate original GeoJSON Feature objects.
236
+ // Uses JSON round-trip instead of structuredClone to handle OL Feature
237
+ // objects from drawtools (which contain non-cloneable methods).
238
+ const rawJsonformValue = JSON.parse(
239
+ JSON.stringify(
240
+ /** @type {Record<string, any>} */ (jsonformEl.value?.value ?? {}),
241
+ ),
242
+ );
195
243
  const jsonformValue = /** @type {Record<string,any>} */ (
196
244
  jsonformEl.value?.value
197
245
  );
@@ -210,6 +258,7 @@ export async function handleProcesses({
210
258
  [tempChartSpec, usedChartData.value] = await processCharts({
211
259
  links: serviceLinks,
212
260
  jsonformValue: { ...(jsonformValue ?? {}) },
261
+ rawJsonformValue,
213
262
  jsonformSchema: jsonformSchema.value,
214
263
  enableCompare,
215
264
  selectedStac: selectedStac.value,