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