@eodash/eodash 5.0.0-rc.3 → 5.1.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.
- package/README.md +1 -0
- package/core/client/App.vue +8 -2
- package/core/client/asWebComponent.js +5 -5
- package/core/client/components/DashboardLayout.vue +42 -25
- package/core/client/components/EodashOverlay.vue +1 -1
- package/core/client/components/ErrorAlert.vue +2 -2
- package/core/client/components/Footer.vue +4 -4
- package/core/client/components/Header.vue +3 -3
- package/core/client/components/MobileLayout.vue +9 -10
- package/core/client/composables/DefineEodash.js +38 -43
- package/core/client/composables/DefineTemplate.js +4 -2
- package/core/client/composables/DefineWidgets.js +14 -8
- package/core/client/composables/index.js +273 -23
- package/core/client/eodashSTAC/EodashCollection.js +80 -47
- package/core/client/eodashSTAC/helpers.js +136 -27
- package/core/client/eodashSTAC/parquet.js +145 -0
- package/core/client/eodashSTAC/triggers.js +6 -3
- package/core/client/plugins/index.js +4 -3
- package/core/client/plugins/vuetify.js +3 -0
- package/core/client/store/actions.js +21 -4
- package/core/client/store/stac.js +93 -56
- package/core/client/store/states.js +15 -5
- package/core/client/types.ts +59 -43
- package/core/client/utils/index.js +79 -0
- package/core/client/utils/keys.js +2 -2
- package/core/client/utils/states.js +30 -5
- package/core/client/views/Dashboard.vue +36 -32
- package/core/client/vite-env.d.ts +7 -0
- package/dist/client/{DashboardLayout-t_PavJPO.js → DashboardLayout-ByVs1DrY.js} +23 -12
- package/dist/client/{DynamicWebComponent-y07rVJch.js → DynamicWebComponent-C3W7HSQm.js} +1 -1
- package/dist/client/{EodashDatePicker-CcOfyzGD.js → EodashDatePicker-BIAf1sMT.js} +59 -32
- package/dist/client/{EodashItemFilter-B9HCvIMi.js → EodashItemFilter-DPznh8UB.js} +20 -10
- package/dist/client/{EodashLayerControl-KStn7Nb_.js → EodashLayerControl-Bhxjw4V2.js} +29 -16
- package/dist/client/EodashLayoutSwitcher-C5qTEffW.js +61 -0
- package/dist/client/EodashMapBtns-WoGq8MuV.js +173 -0
- package/dist/client/{EodashStacInfo-C_hDy6Pd.js → EodashStacInfo-CSvvF2jI.js} +3 -18
- package/dist/client/{EodashTools-BXflvRf8.js → EodashTools-Cv1SXQ5y.js} +13 -13
- package/dist/client/{ExportState-C0QRemK1.js → ExportState-D-iuwaad.js} +58 -52
- package/dist/client/{Footer-7VGyGUAs.js → Footer-CyF0zRAk.js} +15 -13
- package/dist/client/{Header-BQJnXHYq.js → Header-CgD8jDKU.js} +33 -28
- package/dist/client/{MobileLayout-b8nQ-Vyl.js → MobileLayout-EKQ_kpSh.js} +69 -60
- package/dist/client/{PopUp-DgNrh9Df.js → PopUp-BsYLvWch.js} +19 -10
- package/dist/client/ProcessList-C2xsLU2_.js +191 -0
- package/dist/client/{VImg-D4eT3IQ1.js → VImg-OHe8YTs2.js} +24 -24
- package/dist/client/{VMain-C3hN2-H3.js → VMain-PryTLU4a.js} +7 -7
- package/dist/client/{VOverlay-tAeNygaA.js → VOverlay-yUn7p-Uf.js} +64 -27
- package/dist/client/{VTooltip-B0Q3iHMZ.js → VTooltip-DZ0fjpB3.js} +13 -10
- package/dist/client/{WidgetsContainer-CtDHfCYf.js → WidgetsContainer-B9LBadcC.js} +1 -1
- package/dist/client/asWebComponent-By_7_JjS.js +19193 -0
- package/dist/client/async-DkSu_u2K.js +740 -0
- package/dist/client/eo-dash.js +1 -1
- package/dist/client/{forwardRefs-CIFAqXaZ.js → forwardRefs-BXxrv98s.js} +31 -4
- package/dist/client/handling-CgmFXkW6.js +1212 -0
- package/dist/client/helpers-Dy0Q13tP.js +4534 -0
- package/dist/client/{index-DvcUndod.js → index-BuhOHXKv.js} +2 -4
- package/dist/client/{index-BQ16n4Sk.js → index-Ch_HchK3.js} +39 -32
- package/dist/client/{index-Cv7HBz49.js → index-Dqj4tbx2.js} +2 -2
- package/dist/client/index-skjhlH8u.js +376 -0
- package/dist/client/{ssrBoot-BP7SYRyC.js → ssrBoot-Zgc_Ttvi.js} +2 -2
- package/dist/client/templates.js +850 -0
- package/dist/client/transition-C98Yn4Vo.js +40 -0
- package/dist/node/cli.js +16 -6
- package/dist/node/types.d.ts +1 -1
- package/dist/types/core/client/App.vue.d.ts +2 -2
- package/dist/types/core/client/asWebComponent.d.ts +1 -1
- package/dist/types/core/client/components/DynamicWebComponent.vue.d.ts +1 -3
- package/dist/types/core/client/components/Footer.vue.d.ts +1 -105
- package/dist/types/core/client/components/IframeWrapper.vue.d.ts +1 -1
- package/dist/types/core/client/components/MobileLayout.vue.d.ts +1 -324
- package/dist/types/core/client/composables/DefineEodash.d.ts +2 -2
- package/dist/types/core/client/composables/DefineTemplate.d.ts +1 -1
- package/dist/types/core/client/composables/DefineWidgets.d.ts +4 -4
- package/dist/types/core/client/composables/index.d.ts +24 -2
- package/dist/types/core/client/eodashSTAC/EodashCollection.d.ts +9 -6
- package/dist/types/core/client/eodashSTAC/helpers.d.ts +20 -5
- package/dist/types/core/client/eodashSTAC/parquet.d.ts +2 -0
- package/dist/types/core/client/plugins/vuetify.d.ts +7 -4
- package/dist/types/core/client/store/actions.d.ts +3 -2
- package/dist/types/core/client/store/stac.d.ts +16 -13
- package/dist/types/core/client/store/states.d.ts +14 -4
- package/dist/types/core/client/types.d.ts +45 -30
- package/dist/types/core/client/utils/index.d.ts +2 -0
- package/dist/types/core/client/utils/keys.d.ts +4 -4
- package/dist/types/core/client/utils/states.d.ts +59 -47
- package/dist/types/core/client/views/Dashboard.vue.d.ts +2 -2
- package/dist/types/templates/baseConfig.d.ts +4 -0
- package/dist/types/templates/compare.d.ts +210 -0
- package/dist/types/templates/expert.d.ts +151 -0
- package/dist/types/templates/index.d.ts +6 -0
- package/dist/types/templates/light.d.ts +145 -0
- package/dist/types/widgets/EodashDatePicker.vue.d.ts +1 -458
- package/dist/types/widgets/EodashItemFilter.vue.d.ts +3 -3
- package/dist/types/widgets/EodashLayerControl.vue.d.ts +14 -7
- package/dist/types/widgets/EodashLayoutSwitcher.vue.d.ts +1 -3
- package/dist/types/widgets/EodashMap/index.vue.d.ts +1 -4
- package/dist/types/widgets/EodashMapBtns.vue.d.ts +8 -8
- package/dist/types/widgets/EodashProcess/ProcessList.vue.d.ts +8 -1
- package/dist/types/widgets/EodashProcess/index.vue.d.ts +8 -4
- package/dist/types/widgets/EodashProcess/methods/async.d.ts +18 -18
- package/dist/types/widgets/EodashProcess/methods/composables.d.ts +3 -2
- package/dist/types/widgets/EodashProcess/methods/custom-endpoints/chart/index.d.ts +1 -0
- package/dist/types/widgets/EodashProcess/methods/custom-endpoints/chart/sentinelhub-endpoint.d.ts +6 -0
- package/dist/types/widgets/EodashProcess/methods/custom-endpoints/chart/veda-endpoint.d.ts +4 -0
- package/dist/types/widgets/EodashProcess/methods/custom-endpoints/layers/eoxhub-workspaces-endpoint.d.ts +5 -0
- package/dist/types/widgets/EodashProcess/methods/custom-endpoints/layers/index.d.ts +1 -0
- package/dist/types/widgets/EodashProcess/methods/handling.d.ts +12 -5
- package/dist/types/widgets/EodashProcess/methods/outputs.d.ts +72 -41
- package/dist/types/widgets/EodashProcess/methods/utils.d.ts +41 -21
- package/dist/types/widgets/EodashProcess/states.d.ts +11 -0
- package/dist/types/widgets/EodashProcess/types.d.ts +41 -0
- package/dist/types/widgets/EodashStacInfo.vue.d.ts +14 -14
- package/dist/types/widgets/EodashTools.vue.d.ts +3 -3
- package/dist/types/widgets/ExportState.vue.d.ts +1 -1
- package/dist/types/widgets/PopUp.vue.d.ts +11 -16
- package/dist/types/widgets/WidgetsContainer.vue.d.ts +3 -6
- package/package.json +53 -45
- package/templates/baseConfig.js +68 -0
- package/templates/compare.js +162 -0
- package/templates/expert.js +123 -0
- package/templates/index.js +8 -0
- package/templates/light.js +130 -0
- package/widgets/EodashDatePicker.vue +80 -31
- package/widgets/EodashItemFilter.vue +26 -11
- package/widgets/EodashLayerControl.vue +20 -11
- package/widgets/EodashLayoutSwitcher.vue +6 -3
- package/widgets/EodashMap/index.vue +3 -8
- package/widgets/EodashMap/methods/create-layers-config.js +4 -3
- package/widgets/EodashMap/methods/index.js +33 -23
- package/widgets/EodashMapBtns.vue +83 -41
- package/widgets/EodashProcess/ProcessList.vue +34 -10
- package/widgets/EodashProcess/index.vue +55 -20
- package/widgets/EodashProcess/methods/async.js +77 -59
- package/widgets/EodashProcess/methods/composables.js +21 -14
- package/widgets/EodashProcess/methods/custom-endpoints/chart/index.js +35 -0
- package/widgets/EodashProcess/methods/custom-endpoints/chart/sentinelhub-endpoint.js +275 -0
- package/widgets/EodashProcess/methods/custom-endpoints/chart/veda-endpoint.js +116 -0
- package/widgets/EodashProcess/methods/custom-endpoints/layers/eoxhub-workspaces-endpoint.js +94 -0
- package/widgets/EodashProcess/methods/custom-endpoints/layers/index.js +33 -0
- package/widgets/EodashProcess/methods/handling.js +127 -80
- package/widgets/EodashProcess/methods/outputs.js +376 -125
- package/widgets/EodashProcess/methods/utils.js +398 -10
- package/widgets/EodashProcess/states.js +13 -0
- package/widgets/EodashProcess/types.ts +46 -0
- package/widgets/EodashStacInfo.vue +2 -17
- package/widgets/EodashTools.vue +13 -13
- package/widgets/WidgetsContainer.vue +1 -1
- package/core/client/eodash.js +0 -454
- package/dist/client/EodashLayoutSwitcher-DqeFO3RN.js +0 -52
- package/dist/client/EodashMapBtns-5BF27qJB.js +0 -131
- package/dist/client/ProcessList-C62SOVO6.js +0 -484
- package/dist/client/asWebComponent-BJ2NWunV.js +0 -12479
- package/dist/client/eo-dash.css +0 -5
- package/dist/client/index-Da5xXX6Q.js +0 -780
- package/dist/client/transition-Cdb4K27U.js +0 -37
- package/dist/types/core/client/eodash.d.ts +0 -8
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { mapEl } from "@/store/states";
|
|
2
1
|
import { initProcess } from "./handling";
|
|
3
2
|
import { useEventBus } from "@vueuse/core";
|
|
4
3
|
import { nextTick, onMounted, watch } from "vue";
|
|
@@ -11,7 +10,7 @@ import { useOnLayersUpdate } from "@/composables";
|
|
|
11
10
|
* @export
|
|
12
11
|
* @async
|
|
13
12
|
* @param {Object} params
|
|
14
|
-
* @param {import("vue").Ref<import("stac-ts").StacCollection>} params.selectedStac
|
|
13
|
+
* @param {import("vue").Ref<import("stac-ts").StacCollection | null>} params.selectedStac
|
|
15
14
|
* @param {import("vue").Ref<import("@eox/jsonform").EOxJSONForm | null>} params.jsonformEl
|
|
16
15
|
* @param {import("vue").Ref<Record<string,any> | null>} params.jsonformSchema
|
|
17
16
|
* @param {import("vue").Ref<import("@eox/chart").EOxChart["spec"] | null>} params.chartSpec
|
|
@@ -19,6 +18,7 @@ import { useOnLayersUpdate } from "@/composables";
|
|
|
19
18
|
* @param {import("vue").Ref<boolean>} params.isProcessed
|
|
20
19
|
* @param {import("vue").Ref<boolean>} params.loading
|
|
21
20
|
* @param {import("vue").Ref<boolean>} params.isPolling
|
|
21
|
+
* @param {import("@eox/map").EOxMap | null} params.mapElement
|
|
22
22
|
*/
|
|
23
23
|
export const useInitProcess = ({
|
|
24
24
|
selectedStac,
|
|
@@ -29,13 +29,15 @@ export const useInitProcess = ({
|
|
|
29
29
|
processResults,
|
|
30
30
|
loading,
|
|
31
31
|
isPolling,
|
|
32
|
+
mapElement,
|
|
32
33
|
}) => {
|
|
33
34
|
const layersEvents = useEventBus(eoxLayersKey);
|
|
34
35
|
|
|
35
36
|
onMounted(async () => {
|
|
36
37
|
// wait for the layers to be rendered
|
|
37
|
-
if (
|
|
38
|
+
if ((mapElement?.layers.length ?? 0) > 1) {
|
|
38
39
|
await initProcess({
|
|
40
|
+
enableCompare: mapElement?.id === "compare",
|
|
39
41
|
selectedStac,
|
|
40
42
|
jsonformEl,
|
|
41
43
|
jsonformSchema,
|
|
@@ -48,6 +50,7 @@ export const useInitProcess = ({
|
|
|
48
50
|
} else {
|
|
49
51
|
layersEvents.once(async () => {
|
|
50
52
|
await initProcess({
|
|
53
|
+
enableCompare: mapElement?.id === "compare",
|
|
51
54
|
selectedStac,
|
|
52
55
|
jsonformEl,
|
|
53
56
|
jsonformSchema,
|
|
@@ -61,19 +64,23 @@ export const useInitProcess = ({
|
|
|
61
64
|
}
|
|
62
65
|
});
|
|
63
66
|
|
|
67
|
+
const evtKey =
|
|
68
|
+
mapElement?.id === "compare" ? "compareLayers:updated" : "layers:updated";
|
|
64
69
|
useOnLayersUpdate(async (evt, _payload) => {
|
|
65
|
-
if (evt
|
|
66
|
-
|
|
67
|
-
selectedStac,
|
|
68
|
-
jsonformEl,
|
|
69
|
-
jsonformSchema,
|
|
70
|
-
chartSpec,
|
|
71
|
-
isProcessed,
|
|
72
|
-
processResults,
|
|
73
|
-
loading,
|
|
74
|
-
isPolling,
|
|
75
|
-
});
|
|
70
|
+
if (evt !== evtKey) {
|
|
71
|
+
return;
|
|
76
72
|
}
|
|
73
|
+
await initProcess({
|
|
74
|
+
enableCompare: mapElement?.id === "compare",
|
|
75
|
+
selectedStac,
|
|
76
|
+
jsonformEl,
|
|
77
|
+
jsonformSchema,
|
|
78
|
+
chartSpec,
|
|
79
|
+
isProcessed,
|
|
80
|
+
processResults,
|
|
81
|
+
loading,
|
|
82
|
+
isPolling,
|
|
83
|
+
});
|
|
77
84
|
});
|
|
78
85
|
};
|
|
79
86
|
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import log from "loglevel";
|
|
2
|
+
import { handleSentinelHubProcess } from "./sentinelhub-endpoint";
|
|
3
|
+
import { handleVedaEndpoint } from "./veda-endpoint";
|
|
4
|
+
|
|
5
|
+
export const handleChartCustomEndpoints = createCustomChartEndpointsHandler([
|
|
6
|
+
handleSentinelHubProcess,
|
|
7
|
+
handleVedaEndpoint,
|
|
8
|
+
]);
|
|
9
|
+
/**
|
|
10
|
+
* @param {((input:import("^/EodashProcess/types").CustomEnpointInput)=> Promise<any[] | undefined | null>)[]} callbacks
|
|
11
|
+
*/
|
|
12
|
+
function createCustomChartEndpointsHandler(callbacks) {
|
|
13
|
+
/**
|
|
14
|
+
* @param {import("^/EodashProcess/types").CustomEnpointInput} inputs
|
|
15
|
+
* */
|
|
16
|
+
return async (inputs) => {
|
|
17
|
+
for (const callback of callbacks) {
|
|
18
|
+
const data = await callback(inputs);
|
|
19
|
+
log.debug(
|
|
20
|
+
"Custom endpoint data:",
|
|
21
|
+
data,
|
|
22
|
+
"for callback:",
|
|
23
|
+
callback.name,
|
|
24
|
+
"inputs:",
|
|
25
|
+
inputs,
|
|
26
|
+
);
|
|
27
|
+
const isNotValid = !data || !data.length || data.some((item) => !item);
|
|
28
|
+
if (isNotValid) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
return data;
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
import axios from "@/plugins/axios";
|
|
2
|
+
import { currentUrl, currentCompareUrl } from "@/store/states";
|
|
3
|
+
import { generateTimePairs, getBboxProperty } from "../../utils";
|
|
4
|
+
import { extractCollectionUrls } from "@/eodashSTAC/helpers";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
*
|
|
8
|
+
* @param {import("^/EodashProcess/types").CustomEnpointInput} inputs
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
export async function handleSentinelHubProcess({
|
|
12
|
+
links,
|
|
13
|
+
jsonformValue,
|
|
14
|
+
jsonformSchema,
|
|
15
|
+
selectedStac,
|
|
16
|
+
enableCompare = false,
|
|
17
|
+
}) {
|
|
18
|
+
const sentinelHubLink = links.find(
|
|
19
|
+
(link) => link.rel === "service" && link.endpoint === "sentinelhub",
|
|
20
|
+
);
|
|
21
|
+
if (!sentinelHubLink) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const evalScriptLink = await getEvalScriptLink(
|
|
25
|
+
selectedStac,
|
|
26
|
+
enableCompare ? currentCompareUrl.value : currentUrl.value,
|
|
27
|
+
);
|
|
28
|
+
if (!evalScriptLink) {
|
|
29
|
+
console.error(
|
|
30
|
+
"[eodash] evalscript link for sentinel hub not found in indicator",
|
|
31
|
+
evalScriptLink,
|
|
32
|
+
);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (!sentinelHubLink) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const endpoint = sentinelHubLink.href;
|
|
39
|
+
const bboxProperty = getBboxProperty(jsonformSchema);
|
|
40
|
+
const bbox = jsonformValue[bboxProperty];
|
|
41
|
+
|
|
42
|
+
const clientId = process.env.EODASH_SENTINELHUB_CLIENT_ID;
|
|
43
|
+
const clientSecret = process.env.EODASH_SENTINELHUB_CLIENT_SECRET;
|
|
44
|
+
|
|
45
|
+
const bearer = await sentinelHubAuth(clientId, clientSecret);
|
|
46
|
+
if (!bearer) {
|
|
47
|
+
console.error(
|
|
48
|
+
"[eodash] Error while fetching bearer token from sentinel hub",
|
|
49
|
+
);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// generate 30 dates from the start and end date of the selected stac
|
|
53
|
+
// generate time pairs from the selected stac temporal extent
|
|
54
|
+
const timePairs = generateTimePairs(
|
|
55
|
+
selectedStac.extent.temporal.interval[0],
|
|
56
|
+
[jsonformValue["start_date"], jsonformValue["end_date"]],
|
|
57
|
+
jsonformValue["distribution"],
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
// fetch data from sentinel hub
|
|
61
|
+
return await Promise.all(
|
|
62
|
+
timePairs.map(([to, from]) => {
|
|
63
|
+
return fetchSentinelHubData({
|
|
64
|
+
url: endpoint,
|
|
65
|
+
bearer,
|
|
66
|
+
bbox,
|
|
67
|
+
from,
|
|
68
|
+
to,
|
|
69
|
+
exampleLink: evalScriptLink,
|
|
70
|
+
}).catch((err) =>
|
|
71
|
+
console.error(
|
|
72
|
+
"[eodash] Error while fetching data from sentinel hub endpoint:",
|
|
73
|
+
err,
|
|
74
|
+
),
|
|
75
|
+
);
|
|
76
|
+
}),
|
|
77
|
+
).then((data) => data.flat().map((data) => data.outputs.data));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @param {string} [clientId]
|
|
82
|
+
* @param {string} [clientSecret]
|
|
83
|
+
* @returns {Promise<string | void>}
|
|
84
|
+
*/
|
|
85
|
+
async function sentinelHubAuth(clientId, clientSecret) {
|
|
86
|
+
if (!clientId || !clientSecret) {
|
|
87
|
+
console.error(
|
|
88
|
+
"[eodash] Error (sentinelhub): client id or secret not found",
|
|
89
|
+
);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const sessionToken = sessionStorage.getItem("sentinelhub_token");
|
|
94
|
+
const sessionTokenTime = /** @type {string} */ (
|
|
95
|
+
sessionStorage.getItem("sentinelhub_token_time")
|
|
96
|
+
);
|
|
97
|
+
const isValid = Date.now() - Number(sessionTokenTime) < 3600 * 1000;
|
|
98
|
+
|
|
99
|
+
// if the token is still valid, return it
|
|
100
|
+
if (sessionToken && isValid) {
|
|
101
|
+
sessionStorage.setItem("sentinelhub_token_time", Date.now().toString());
|
|
102
|
+
return sessionToken;
|
|
103
|
+
}
|
|
104
|
+
const token = await retrieveSentinelHubToken(clientId, clientSecret);
|
|
105
|
+
if (!token) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
sessionStorage.setItem("sentinelhub_token_time", Date.now().toString());
|
|
109
|
+
sessionStorage.setItem("sentinelhub_token", token);
|
|
110
|
+
return token;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* @param {string} clientId
|
|
114
|
+
* @param {string} clientSecret
|
|
115
|
+
* @returns {Promise<string | void>}
|
|
116
|
+
*/
|
|
117
|
+
async function retrieveSentinelHubToken(clientId, clientSecret) {
|
|
118
|
+
const url = "https://services.sentinel-hub.com/oauth/token";
|
|
119
|
+
const headers = {
|
|
120
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
121
|
+
};
|
|
122
|
+
const body = new URLSearchParams({
|
|
123
|
+
client_id: clientId,
|
|
124
|
+
client_secret: clientSecret,
|
|
125
|
+
response_type: "token",
|
|
126
|
+
grant_type: "client_credentials",
|
|
127
|
+
});
|
|
128
|
+
return await axios
|
|
129
|
+
.post(url, body, { headers })
|
|
130
|
+
.then((resp) => resp.data.access_token);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
*
|
|
134
|
+
* @param {object} param0
|
|
135
|
+
* @param {string} param0.url - url to the sentinel hub endpoint
|
|
136
|
+
* @param {string} param0.bearer - bearer token for authentication
|
|
137
|
+
* @param {number[]} param0.bbox - bounding box of the area of interest
|
|
138
|
+
* @param {string} param0.from - start date of the time range
|
|
139
|
+
* @param {string} param0.to - end date of the time range
|
|
140
|
+
* @param {number} [param0.timeout = 20000] - timeout for the request
|
|
141
|
+
* @param {import("stac-ts").StacLink} param0.exampleLink - example link containing evalscript to use for the request
|
|
142
|
+
* @returns
|
|
143
|
+
*/
|
|
144
|
+
async function fetchSentinelHubData({
|
|
145
|
+
url,
|
|
146
|
+
bearer,
|
|
147
|
+
bbox,
|
|
148
|
+
from,
|
|
149
|
+
to,
|
|
150
|
+
timeout = 20000,
|
|
151
|
+
exampleLink,
|
|
152
|
+
}) {
|
|
153
|
+
if (!exampleLink) {
|
|
154
|
+
console.error(
|
|
155
|
+
"[eodash] Error (sentinelhub): example link not found in indicator",
|
|
156
|
+
);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
if (!bbox) {
|
|
160
|
+
console.error("[eodash] Error (sentinelhub): bbox not found");
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (!from || !to || new Date(from) > new Date(to)) {
|
|
164
|
+
console.error(
|
|
165
|
+
"[eodash] Error (sentinelhub): time range is faulty or not found",
|
|
166
|
+
from,
|
|
167
|
+
to,
|
|
168
|
+
);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const evalscript = await axios
|
|
172
|
+
.get(exampleLink.href, { responseType: "text" })
|
|
173
|
+
.then((resp) => resp.data);
|
|
174
|
+
|
|
175
|
+
if (!evalscript || evalscript.error) {
|
|
176
|
+
console.error(
|
|
177
|
+
"[eodash] Error (sentinelhub): evalscript not found",
|
|
178
|
+
evalscript,
|
|
179
|
+
);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const body = {
|
|
183
|
+
input: {
|
|
184
|
+
bounds: {
|
|
185
|
+
bbox,
|
|
186
|
+
},
|
|
187
|
+
|
|
188
|
+
data: [
|
|
189
|
+
{
|
|
190
|
+
dataFilter: {},
|
|
191
|
+
type: exampleLink.dataId,
|
|
192
|
+
},
|
|
193
|
+
],
|
|
194
|
+
},
|
|
195
|
+
aggregation: {
|
|
196
|
+
evalscript,
|
|
197
|
+
timeRange: {
|
|
198
|
+
from,
|
|
199
|
+
to,
|
|
200
|
+
},
|
|
201
|
+
aggregationInterval: {
|
|
202
|
+
of: "P1D",
|
|
203
|
+
},
|
|
204
|
+
width: 100,
|
|
205
|
+
height: 100,
|
|
206
|
+
},
|
|
207
|
+
calculations: {
|
|
208
|
+
default: {},
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
const config = {
|
|
212
|
+
headers: {
|
|
213
|
+
Authorization: `Bearer ${bearer}`,
|
|
214
|
+
"Content-Type": "application/json",
|
|
215
|
+
},
|
|
216
|
+
params: {
|
|
217
|
+
credentials: "same-origin",
|
|
218
|
+
},
|
|
219
|
+
timeout,
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
return await axios
|
|
223
|
+
.post(url, body, config)
|
|
224
|
+
.then((resp) => {
|
|
225
|
+
const fetched = resp.data.data;
|
|
226
|
+
//@ts-expect-error TODO
|
|
227
|
+
fetched.forEach((dataItem) => {
|
|
228
|
+
dataItem.outputs.data.date = from;
|
|
229
|
+
});
|
|
230
|
+
return fetched;
|
|
231
|
+
})
|
|
232
|
+
.catch((err) => {
|
|
233
|
+
if (err.response?.status === 401) {
|
|
234
|
+
console.error(
|
|
235
|
+
"[eodash] Error (sentinelhub): bearer token expired, please try again",
|
|
236
|
+
);
|
|
237
|
+
sessionStorage.removeItem("sentinelhub_token");
|
|
238
|
+
sessionStorage.removeItem("sentinelhub_token_time");
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
console.error(
|
|
243
|
+
"[eodash] Error (sentinelhub): error while fetching data from sentinel hub",
|
|
244
|
+
err.response?.data,
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
return [];
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* @param {import("stac-ts").StacCollection} selectedStac
|
|
252
|
+
* @param {string} absoluteUrl
|
|
253
|
+
*/
|
|
254
|
+
async function getEvalScriptLink(selectedStac, absoluteUrl) {
|
|
255
|
+
const evalScriptLink = selectedStac.links.find(
|
|
256
|
+
(link) => link.rel === "example" && link.title === "evalscript",
|
|
257
|
+
);
|
|
258
|
+
if (evalScriptLink) {
|
|
259
|
+
return evalScriptLink;
|
|
260
|
+
}
|
|
261
|
+
// retrieve the first example link from the indicator children
|
|
262
|
+
for (const link of extractCollectionUrls(selectedStac, absoluteUrl)) {
|
|
263
|
+
const scriptLink = axios
|
|
264
|
+
.get(link)
|
|
265
|
+
.then((resp) =>
|
|
266
|
+
/** @type {import("stac-ts").StacCollection} */ (resp.data).links.find(
|
|
267
|
+
(link) => link.rel === "example" && link.title === "evalscript",
|
|
268
|
+
),
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
if (scriptLink) {
|
|
272
|
+
return scriptLink;
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import axios from "@/plugins/axios";
|
|
2
|
+
import { getBboxProperty } from "../../utils";
|
|
3
|
+
import { toAbsolute } from "stac-js/src/http.js";
|
|
4
|
+
import { currentCompareUrl, currentUrl } from "@/store/states";
|
|
5
|
+
import { getDatetimeProperty } from "@/eodashSTAC/helpers";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {import("^/EodashProcess/types").CustomEnpointInput} inputs
|
|
9
|
+
*/
|
|
10
|
+
export async function handleVedaEndpoint({
|
|
11
|
+
links,
|
|
12
|
+
jsonformSchema,
|
|
13
|
+
jsonformValue,
|
|
14
|
+
selectedStac,
|
|
15
|
+
enableCompare = false,
|
|
16
|
+
}) {
|
|
17
|
+
const vedaLink = links.find(
|
|
18
|
+
(link) => link.rel === "service" && link.endpoint === "veda",
|
|
19
|
+
);
|
|
20
|
+
if (!vedaLink) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const vedaEndpoint = vedaLink?.href;
|
|
24
|
+
const bboxProperty = getBboxProperty(jsonformSchema);
|
|
25
|
+
// this should be type geojson
|
|
26
|
+
const bboxGeoJSON = JSON.parse(jsonformValue[bboxProperty]);
|
|
27
|
+
|
|
28
|
+
const configs = await fetchVedaCOGsConfig(
|
|
29
|
+
selectedStac,
|
|
30
|
+
enableCompare ? currentCompareUrl.value : currentUrl.value,
|
|
31
|
+
);
|
|
32
|
+
// TODO: convert jsonform bbox type to geojson in the schema to avoid the conversion here
|
|
33
|
+
return await Promise.all(
|
|
34
|
+
configs.map(({ endpoint, datetime }) => {
|
|
35
|
+
return axios
|
|
36
|
+
.post(vedaEndpoint + `?url=${endpoint}`, {
|
|
37
|
+
...{
|
|
38
|
+
type: "Feature",
|
|
39
|
+
properties: {},
|
|
40
|
+
geometry: bboxGeoJSON,
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
.then((resp) => {
|
|
44
|
+
const fetchedSats = resp.data.properties.statistics;
|
|
45
|
+
fetchedSats.date = datetime;
|
|
46
|
+
return fetchedSats;
|
|
47
|
+
})
|
|
48
|
+
.catch((resp) =>
|
|
49
|
+
console.error(
|
|
50
|
+
"[eodash] Error while fetching data from veda endpoint:",
|
|
51
|
+
resp,
|
|
52
|
+
),
|
|
53
|
+
);
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Fetches the COGs endpoints from the STAC collections
|
|
60
|
+
* @param {import("stac-ts").StacCollection} selectedStac
|
|
61
|
+
* @param {string} absoluteUrl
|
|
62
|
+
*/
|
|
63
|
+
async function fetchVedaCOGsConfig(selectedStac, absoluteUrl) {
|
|
64
|
+
// retrieve the collections from the indicator
|
|
65
|
+
const collectionLinks = selectedStac.links.filter(
|
|
66
|
+
(link) => link.rel == "child",
|
|
67
|
+
);
|
|
68
|
+
/** @type {import("stac-ts").StacCollection[]} */
|
|
69
|
+
const collections = [];
|
|
70
|
+
if (!collectionLinks.length) {
|
|
71
|
+
collections.push(selectedStac);
|
|
72
|
+
} else {
|
|
73
|
+
collections.push(
|
|
74
|
+
...(await Promise.all(
|
|
75
|
+
collectionLinks.map((link) =>
|
|
76
|
+
axios
|
|
77
|
+
.get(toAbsolute(link.href, absoluteUrl))
|
|
78
|
+
.then((resp) => resp.data),
|
|
79
|
+
),
|
|
80
|
+
)),
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
/** @type {{endpoint:string; datetime:string}[]} */
|
|
84
|
+
const configs = [];
|
|
85
|
+
for (const collection of collections) {
|
|
86
|
+
const datetimeProperty = /** @type string **/ (
|
|
87
|
+
getDatetimeProperty(collection.links)
|
|
88
|
+
);
|
|
89
|
+
let itemLinks = collection.links.filter((link) => link.rel == "item");
|
|
90
|
+
configs.push(
|
|
91
|
+
...itemLinks.map((link) => ({
|
|
92
|
+
endpoint: /** @type {string} */ (link["cog_href"]),
|
|
93
|
+
datetime: /** @type string **/ (link[datetimeProperty]),
|
|
94
|
+
})),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Sort by date ascending
|
|
99
|
+
configs.sort(
|
|
100
|
+
(a, b) => new Date(a.datetime).getTime() - new Date(b.datetime).getTime(),
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
const maxConfigs = 50;
|
|
104
|
+
if (configs.length <= maxConfigs) {
|
|
105
|
+
return configs;
|
|
106
|
+
}
|
|
107
|
+
// we need to sample if the number of configs are more than 50
|
|
108
|
+
const totalSize = configs.length;
|
|
109
|
+
const sampledConfigs = [];
|
|
110
|
+
for (let i = 0; i < maxConfigs; i++) {
|
|
111
|
+
// Calculate the index to pick, ensuring distribution and inclusion of first/last
|
|
112
|
+
const index = Math.floor((i * (totalSize - 1)) / (maxConfigs - 1));
|
|
113
|
+
sampledConfigs.push(configs[index]);
|
|
114
|
+
}
|
|
115
|
+
return sampledConfigs;
|
|
116
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import axios from "@/plugins/axios";
|
|
2
|
+
import { compareIndicator, indicator } from "@/store/states";
|
|
3
|
+
import mustache from "mustache";
|
|
4
|
+
import {
|
|
5
|
+
pollProcessStatus,
|
|
6
|
+
updateJobsStatus,
|
|
7
|
+
} from "^/EodashProcess/methods/async";
|
|
8
|
+
import {
|
|
9
|
+
creatAsyncProcessLayerDefinitions,
|
|
10
|
+
extractAsyncResults,
|
|
11
|
+
} from "../../utils";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
*
|
|
15
|
+
* @param {import("^/EodashProcess/types").CustomEnpointInput} param0
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export async function handleEOxHubEndpoint({
|
|
19
|
+
links,
|
|
20
|
+
jsonformValue,
|
|
21
|
+
isPolling,
|
|
22
|
+
selectedStac,
|
|
23
|
+
jobs,
|
|
24
|
+
enableCompare = false,
|
|
25
|
+
}) {
|
|
26
|
+
if (!isPolling) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const eoxhubLinks = links.filter(
|
|
30
|
+
(link) => link.rel === "service" && link.endpoint === "eoxhub_workspaces",
|
|
31
|
+
);
|
|
32
|
+
const layers = [];
|
|
33
|
+
for (const link of eoxhubLinks) {
|
|
34
|
+
// TODO: prove of concept, needs to be reworked for sure
|
|
35
|
+
// Special handling for eoxhub workspace process endpoints
|
|
36
|
+
const postBody = await axios
|
|
37
|
+
.get(/** @type {string} */ (link["body"]), { responseType: "text" })
|
|
38
|
+
.then((resp) => resp.data);
|
|
39
|
+
const jsonData = JSON.parse(
|
|
40
|
+
mustache.render(postBody, { ...(jsonformValue ?? {}) }),
|
|
41
|
+
);
|
|
42
|
+
const currentIndicator = enableCompare ? compareIndicator : indicator;
|
|
43
|
+
try {
|
|
44
|
+
const responseProcess = await axios.post(link.href, jsonData, {
|
|
45
|
+
headers: {
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// We save the process status url into localstorage assigning it to the indicator id
|
|
51
|
+
const currentJobs = JSON.parse(
|
|
52
|
+
localStorage.getItem(currentIndicator.value) || "[]",
|
|
53
|
+
);
|
|
54
|
+
currentJobs.push(responseProcess.headers.location);
|
|
55
|
+
localStorage.setItem(currentIndicator.value, JSON.stringify(currentJobs));
|
|
56
|
+
|
|
57
|
+
const processResults = await pollProcessStatus({
|
|
58
|
+
jobs,
|
|
59
|
+
processUrl: responseProcess.headers.location,
|
|
60
|
+
isPolling,
|
|
61
|
+
enableCompare,
|
|
62
|
+
})
|
|
63
|
+
.then((resultItem) => {
|
|
64
|
+
return extractAsyncResults(resultItem);
|
|
65
|
+
})
|
|
66
|
+
.catch((error) => {
|
|
67
|
+
if (error instanceof Error) {
|
|
68
|
+
console.error("Polling failed:", error.message);
|
|
69
|
+
} else {
|
|
70
|
+
console.error("Unknown error occurred during polling:", error);
|
|
71
|
+
}
|
|
72
|
+
return [];
|
|
73
|
+
});
|
|
74
|
+
await updateJobsStatus(jobs, currentIndicator.value);
|
|
75
|
+
|
|
76
|
+
layers.push(
|
|
77
|
+
...(await creatAsyncProcessLayerDefinitions(
|
|
78
|
+
processResults,
|
|
79
|
+
link,
|
|
80
|
+
selectedStac,
|
|
81
|
+
)),
|
|
82
|
+
);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
await updateJobsStatus(jobs, currentIndicator.value);
|
|
85
|
+
if (error instanceof Error) {
|
|
86
|
+
console.error("Error sending POST request:", error.message);
|
|
87
|
+
} else {
|
|
88
|
+
console.error("Unknown error occurred:", error);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return layers;
|
|
94
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { handleEOxHubEndpoint } from "./eoxhub-workspaces-endpoint";
|
|
2
|
+
|
|
3
|
+
export const handleLayersCustomEndpoints = createCustomLayersEndpointsHandler([
|
|
4
|
+
handleEOxHubEndpoint,
|
|
5
|
+
]);
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {((input:import("^/EodashProcess/types").CustomEnpointInput)=> Promise<Record<string,any>[] | undefined | null>)[]} callbacks
|
|
9
|
+
* @returns {(input: import("^/EodashProcess/types").CustomEnpointInput) => Promise<import("@eox/map/.").EoxLayer[]>}
|
|
10
|
+
*/
|
|
11
|
+
function createCustomLayersEndpointsHandler(callbacks) {
|
|
12
|
+
return async (inputs) => {
|
|
13
|
+
// this allows multiple endpoints links to exist
|
|
14
|
+
// and return multiple layers
|
|
15
|
+
return await Promise.all(
|
|
16
|
+
callbacks.map((callback) => callback(inputs)),
|
|
17
|
+
).then((asyncProcessesLayers) => {
|
|
18
|
+
const layers = [];
|
|
19
|
+
for (const processLayers of asyncProcessesLayers) {
|
|
20
|
+
layers.push(...(processLayers?.filter(isValidEoxLayer) ?? []));
|
|
21
|
+
}
|
|
22
|
+
return layers;
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {any} layer
|
|
29
|
+
* @returns {layer is import("@eox/map/.").EoxLayer}
|
|
30
|
+
*/
|
|
31
|
+
function isValidEoxLayer(layer) {
|
|
32
|
+
return !!layer && !!layer.type && (!!layer.source || !!layer.layers);
|
|
33
|
+
}
|