@opengeoweb/soundings 12.7.0 → 12.9.1
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/index.esm.js
CHANGED
|
@@ -1670,20 +1670,22 @@ const getCollectionLocations = (collectionId, baseUrl) => fetch(`${baseUrl}/coll
|
|
|
1670
1670
|
const getCollectionInstances = (collectionId, baseUrl) => fetch(`${baseUrl}/collections/${collectionId}/instances`, {
|
|
1671
1671
|
headers: getHeaders()
|
|
1672
1672
|
}).then(handleResponse);
|
|
1673
|
-
const getEdrCollectionForLocation = (collectionId, baseUrl, instanceId, locationId, parameters, datetime) => {
|
|
1673
|
+
const getEdrCollectionForLocation = (collectionId, baseUrl, instanceId, locationId, parameters, datetime, verticalRange) => {
|
|
1674
1674
|
const url = new URL(`${baseUrl}/collections/${collectionId}${instanceId ? `/instances/${instanceId}` : ''}/locations/${locationId}`);
|
|
1675
1675
|
url.searchParams.append('parameter-name', parameters.join(','));
|
|
1676
1676
|
url.searchParams.append('datetime', datetime);
|
|
1677
|
+
url.searchParams.append('z', verticalRange);
|
|
1677
1678
|
url.searchParams.append('f', 'CoverageJSON');
|
|
1678
1679
|
return fetch(url.toString(), {
|
|
1679
1680
|
headers: getHeaders()
|
|
1680
1681
|
}).then(handleResponse);
|
|
1681
1682
|
};
|
|
1682
|
-
const getEdrCollectionForPosition = (collectionId, baseUrl, instanceId, coordinates, parameters, datetime) => {
|
|
1683
|
+
const getEdrCollectionForPosition = (collectionId, baseUrl, instanceId, coordinates, parameters, datetime, verticalRange) => {
|
|
1683
1684
|
const url = new URL(`${baseUrl}/collections/${collectionId}${instanceId ? `/instances/${instanceId}` : ''}/position`);
|
|
1684
1685
|
url.searchParams.append('coords', `POINT(${coordinates[0]} ${coordinates[1]})`);
|
|
1685
1686
|
url.searchParams.append('parameter-name', parameters.join(','));
|
|
1686
1687
|
url.searchParams.append('datetime', datetime);
|
|
1688
|
+
url.searchParams.append('z', verticalRange);
|
|
1687
1689
|
url.searchParams.append('f', 'CoverageJSON');
|
|
1688
1690
|
return fetch(url.toString(), {
|
|
1689
1691
|
headers: getHeaders()
|
|
@@ -1893,27 +1895,29 @@ const getTimestepsFromInstance = instance => {
|
|
|
1893
1895
|
if (!timeExtentValues) {
|
|
1894
1896
|
return [];
|
|
1895
1897
|
}
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
return parseDurationWithRepeats(timeExtent);
|
|
1898
|
+
const allParsedTimesteps = timeExtentValues.reduce((parsedSteps, currentValue) => {
|
|
1899
|
+
try {
|
|
1900
|
+
// Try to parse EDR time extent value in different possible formats
|
|
1901
|
+
// R<repeats>/<start>/P<period>
|
|
1902
|
+
if (currentValue.match(/^R\d+\/.*\/P.*$/)) {
|
|
1903
|
+
return [...parsedSteps, ...parseDurationWithRepeats(currentValue)];
|
|
1903
1904
|
}
|
|
1904
|
-
//
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1905
|
+
// <start>/<end>[/P<period>]
|
|
1906
|
+
if (currentValue.match(/.*\/.*P?.*/)) {
|
|
1907
|
+
const parseObject = new ParseISOTimeRangeDuration(currentValue);
|
|
1908
|
+
const timeValues = range(parseObject.getTimeSteps()).map(timestep => parseObject.getDateAtTimeStep(timestep).toISOString());
|
|
1909
|
+
return [...parsedSteps, ...timeValues];
|
|
1910
|
+
}
|
|
1911
|
+
// individual datetime string
|
|
1912
|
+
const isoFormattedValue = new Date(currentValue).toISOString();
|
|
1913
|
+
return [...parsedSteps, isoFormattedValue];
|
|
1914
|
+
} catch (error) {
|
|
1915
|
+
console.warn(error);
|
|
1916
|
+
// skip unsupported format
|
|
1917
|
+
return [...parsedSteps];
|
|
1908
1918
|
}
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
const isoFormattedValues = timeExtentValues.map(value => new Date(value).toISOString());
|
|
1912
|
-
return isoFormattedValues;
|
|
1913
|
-
} catch (error) {
|
|
1914
|
-
console.warn(error);
|
|
1915
|
-
}
|
|
1916
|
-
return [];
|
|
1919
|
+
}, []);
|
|
1920
|
+
return allParsedTimesteps;
|
|
1917
1921
|
};
|
|
1918
1922
|
|
|
1919
1923
|
/* *
|
|
@@ -1943,19 +1947,19 @@ const sortSoundingFeatures = data => {
|
|
|
1943
1947
|
return featureB.properties.pressure - featureA.properties.pressure;
|
|
1944
1948
|
});
|
|
1945
1949
|
};
|
|
1946
|
-
const constructQueryParams = (collectionId, baseUrl, instanceId, location, datetime, parameterMappings) => {
|
|
1950
|
+
const constructQueryParams = (collectionId, baseUrl, instanceId, location, datetime, parameterMappings, verticalRange) => {
|
|
1947
1951
|
const parameters = getParameterMappings(parameterMappings);
|
|
1948
1952
|
if (typeof location === 'string') {
|
|
1949
1953
|
// LOCATION call
|
|
1950
1954
|
return {
|
|
1951
|
-
queryKey: ['edr-soundings-for-location', collectionId, instanceId || '', location, parameters.join(), datetime],
|
|
1955
|
+
queryKey: ['edr-soundings-for-location', collectionId, instanceId || '', location, parameters.join(), datetime, verticalRange],
|
|
1952
1956
|
queryFn: async () => {
|
|
1953
1957
|
// No collection, location or time selected, don't do EDR call but return empty array
|
|
1954
1958
|
if (collectionId === undefined || location === '' || datetime === '') {
|
|
1955
1959
|
return [];
|
|
1956
1960
|
}
|
|
1957
1961
|
try {
|
|
1958
|
-
const rawData = await getEdrCollectionForLocation(collectionId, baseUrl, instanceId, location, parameters, datetime);
|
|
1962
|
+
const rawData = await getEdrCollectionForLocation(collectionId, baseUrl, instanceId, location, parameters, datetime, verticalRange);
|
|
1959
1963
|
const parsedData = parseCoverageCollection(rawData, parameterMappings);
|
|
1960
1964
|
return sortSoundingFeatures(parsedData);
|
|
1961
1965
|
} catch (err) {
|
|
@@ -1966,14 +1970,14 @@ const constructQueryParams = (collectionId, baseUrl, instanceId, location, datet
|
|
|
1966
1970
|
}
|
|
1967
1971
|
// POSITION call
|
|
1968
1972
|
return {
|
|
1969
|
-
queryKey: ['edr-soundings-for-position', collectionId, location.join(), parameters.join(), datetime],
|
|
1973
|
+
queryKey: ['edr-soundings-for-position', collectionId, location.join(), parameters.join(), datetime, verticalRange],
|
|
1970
1974
|
queryFn: async () => {
|
|
1971
1975
|
// No collection, position or time selected, don't do EDR call but return empty array
|
|
1972
1976
|
if (collectionId === undefined || location === undefined || datetime === '') {
|
|
1973
1977
|
return [];
|
|
1974
1978
|
}
|
|
1975
1979
|
try {
|
|
1976
|
-
const rawData = await getEdrCollectionForPosition(collectionId, baseUrl, instanceId, location, parameters, datetime);
|
|
1980
|
+
const rawData = await getEdrCollectionForPosition(collectionId, baseUrl, instanceId, location, parameters, datetime, verticalRange);
|
|
1977
1981
|
const parsedData = parseCoverageCollection(rawData, parameterMappings);
|
|
1978
1982
|
return sortSoundingFeatures(parsedData);
|
|
1979
1983
|
} catch (err) {
|
|
@@ -2008,13 +2012,14 @@ const useMultipleSources = (sources, locations, datetime) => {
|
|
|
2008
2012
|
collectionId,
|
|
2009
2013
|
url,
|
|
2010
2014
|
instanceId,
|
|
2011
|
-
parameterMappings
|
|
2015
|
+
parameterMappings,
|
|
2016
|
+
verticalRange
|
|
2012
2017
|
}, index) => {
|
|
2013
2018
|
// If acceptance time logic is needed, it could come here.
|
|
2014
2019
|
const dateToUse = datetime &&
|
|
2015
2020
|
// Only use selected time if exact match if found
|
|
2016
2021
|
timesteps[index].includes(new Date(datetime).toISOString()) ? datetime : '';
|
|
2017
|
-
const queryParams = constructQueryParams(collectionId, url, instanceId, locations[collectionId] || '', dateToUse || '', parameterMappings || defaultParameterMappings);
|
|
2022
|
+
const queryParams = constructQueryParams(collectionId, url, instanceId, locations[collectionId] || '', dateToUse || '', parameterMappings || defaultParameterMappings, verticalRange || '');
|
|
2018
2023
|
return queryParams;
|
|
2019
2024
|
});
|
|
2020
2025
|
}, [datetime, locations, sources, timesteps]);
|
|
@@ -2367,6 +2372,7 @@ const getSelectedSources = createSelector(getSoundingsStore, store => {
|
|
|
2367
2372
|
collectionId: key,
|
|
2368
2373
|
url: value.url,
|
|
2369
2374
|
instanceId: value.instanceId,
|
|
2375
|
+
verticalRange: value.verticalRange,
|
|
2370
2376
|
parameterMappings: value.parameterMappings
|
|
2371
2377
|
});
|
|
2372
2378
|
}
|
|
@@ -2643,6 +2649,26 @@ const SoundingsConnect = ({
|
|
|
2643
2649
|
});
|
|
2644
2650
|
};
|
|
2645
2651
|
|
|
2652
|
+
const extractVerticalRange = (collection, selectedInstanceId) => {
|
|
2653
|
+
const instance = collection.instances.find(instance => instance.id === selectedInstanceId);
|
|
2654
|
+
const interval = instance?.extent?.vertical?.interval;
|
|
2655
|
+
if (interval) {
|
|
2656
|
+
// Fallback for FMI server while it sends a string array instead of string[][] as specified in documentation
|
|
2657
|
+
if (typeof interval[0] === 'string') {
|
|
2658
|
+
const verticalDims = interval.toSorted((a, b) => a.localeCompare(b, undefined, {
|
|
2659
|
+
numeric: true
|
|
2660
|
+
})) ?? [];
|
|
2661
|
+
return verticalDims.join('/');
|
|
2662
|
+
}
|
|
2663
|
+
const firstEl = interval[0][0];
|
|
2664
|
+
const lastEl = interval[interval.length - 1][1];
|
|
2665
|
+
const verticalDims = [firstEl, lastEl].toSorted((a, b) => a.localeCompare(b, undefined, {
|
|
2666
|
+
numeric: true
|
|
2667
|
+
})) ?? [];
|
|
2668
|
+
return verticalDims.join('/');
|
|
2669
|
+
}
|
|
2670
|
+
return '';
|
|
2671
|
+
};
|
|
2646
2672
|
const SoundingsSourceMenu = ({
|
|
2647
2673
|
soundingsCollections,
|
|
2648
2674
|
isOpen = false,
|
|
@@ -2705,11 +2731,15 @@ const SoundingsSourceMenu = ({
|
|
|
2705
2731
|
},
|
|
2706
2732
|
children: jsx(Checkbox, {
|
|
2707
2733
|
checked: !!isChecked,
|
|
2708
|
-
onChange: event =>
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2734
|
+
onChange: event => {
|
|
2735
|
+
const verticalRange = selectedInstanceId !== undefined ? extractVerticalRange(collection, selectedInstanceId) : '';
|
|
2736
|
+
updateCollection(collection.id, {
|
|
2737
|
+
url,
|
|
2738
|
+
isChecked: event.target.checked,
|
|
2739
|
+
instanceId: selectedInstanceId,
|
|
2740
|
+
verticalRange
|
|
2741
|
+
});
|
|
2742
|
+
},
|
|
2713
2743
|
disableRipple: true
|
|
2714
2744
|
})
|
|
2715
2745
|
}), jsxs(StyledSelect, {
|
|
@@ -2719,10 +2749,15 @@ const SoundingsSourceMenu = ({
|
|
|
2719
2749
|
},
|
|
2720
2750
|
skipLocalStyling: false,
|
|
2721
2751
|
value: selectedInstanceId || t('noInstancesAvailable'),
|
|
2722
|
-
onChange: event =>
|
|
2723
|
-
|
|
2724
|
-
instanceId
|
|
2725
|
-
|
|
2752
|
+
onChange: event => {
|
|
2753
|
+
const instanceId = event.target.value;
|
|
2754
|
+
const verticalRange = extractVerticalRange(collection, instanceId);
|
|
2755
|
+
updateCollection(collection.id, {
|
|
2756
|
+
url,
|
|
2757
|
+
instanceId,
|
|
2758
|
+
verticalRange
|
|
2759
|
+
});
|
|
2760
|
+
},
|
|
2726
2761
|
renderValue: value => jsx(Box, {
|
|
2727
2762
|
sx: {
|
|
2728
2763
|
textOverflow: 'ellipsis',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeoweb/soundings",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.9.1",
|
|
4
4
|
"description": "GeoWeb soundings library for the opengeoweb project",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -8,25 +8,26 @@
|
|
|
8
8
|
"url": "git@gitlab.com:opengeoweb/opengeoweb.git"
|
|
9
9
|
},
|
|
10
10
|
"dependencies": {
|
|
11
|
-
"@opengeoweb/api": "12.
|
|
11
|
+
"@opengeoweb/api": "12.9.1",
|
|
12
12
|
"@tanstack/react-query": "^5.69.2",
|
|
13
13
|
"react": "^18.3.1",
|
|
14
14
|
"d3": "^7.9.0",
|
|
15
15
|
"react-i18next": "^15.1.1",
|
|
16
16
|
"i18next": "^25.0.1",
|
|
17
|
-
"@opengeoweb/shared": "12.
|
|
17
|
+
"@opengeoweb/shared": "12.9.1",
|
|
18
18
|
"@mui/material": "^7.0.1",
|
|
19
|
-
"@opengeoweb/store": "12.
|
|
19
|
+
"@opengeoweb/store": "12.9.1",
|
|
20
20
|
"react-redux": "^9.2.0",
|
|
21
|
-
"@opengeoweb/theme": "12.
|
|
21
|
+
"@opengeoweb/theme": "12.9.1",
|
|
22
22
|
"@reduxjs/toolkit": "^2.6.1",
|
|
23
|
-
"@opengeoweb/timeslider": "12.
|
|
23
|
+
"@opengeoweb/timeslider": "12.9.1",
|
|
24
24
|
"react-window": "^1.8.10",
|
|
25
|
-
"@opengeoweb/webmap": "12.
|
|
26
|
-
"lodash": "^4.17.21"
|
|
25
|
+
"@opengeoweb/webmap": "12.9.1",
|
|
26
|
+
"lodash": "^4.17.21",
|
|
27
|
+
"@types/geojson": "^7946.0.14"
|
|
27
28
|
},
|
|
28
29
|
"module": "./index.esm.js",
|
|
29
30
|
"type": "module",
|
|
30
31
|
"main": "./index.esm.js",
|
|
31
|
-
"types": "./index.
|
|
32
|
+
"types": "./index.d.ts"
|
|
32
33
|
}
|
|
@@ -2,5 +2,5 @@ import { CoverageCollection } from '@opengeoweb/shared';
|
|
|
2
2
|
import { LocationsResponseFromBE, SoundingsInstances } from './types';
|
|
3
3
|
export declare const getCollectionLocations: (collectionId: string, baseUrl: string) => Promise<LocationsResponseFromBE>;
|
|
4
4
|
export declare const getCollectionInstances: (collectionId: string, baseUrl: string) => Promise<SoundingsInstances>;
|
|
5
|
-
export declare const getEdrCollectionForLocation: (collectionId: string, baseUrl: string, instanceId: string | undefined, locationId: string, parameters: string[], datetime: string) => Promise<CoverageCollection>;
|
|
6
|
-
export declare const getEdrCollectionForPosition: (collectionId: string, baseUrl: string, instanceId: string | undefined, coordinates: [number, number], parameters: string[], datetime: string) => Promise<CoverageCollection>;
|
|
5
|
+
export declare const getEdrCollectionForLocation: (collectionId: string, baseUrl: string, instanceId: string | undefined, locationId: string, parameters: string[], datetime: string, verticalRange: string) => Promise<CoverageCollection>;
|
|
6
|
+
export declare const getEdrCollectionForPosition: (collectionId: string, baseUrl: string, instanceId: string | undefined, coordinates: [number, number], parameters: string[], datetime: string, verticalRange: string) => Promise<CoverageCollection>;
|
|
@@ -3,6 +3,7 @@ import { SoundingFeature } from './types';
|
|
|
3
3
|
import { SourceType } from '../../store/types';
|
|
4
4
|
import { SoundingsCollectionsWithInstances } from '../../components/Soundings/types';
|
|
5
5
|
import { ServiceWithLocations } from '../../components/MenuBar/LocationsMenu';
|
|
6
|
+
export declare const sortSoundingFeatures: (data: SoundingFeature[]) => SoundingFeature[];
|
|
6
7
|
type Coordinates = [number, number];
|
|
7
8
|
export declare const defaultParameterMappings: {
|
|
8
9
|
temperature: string;
|
package/src/lib/store/types.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export interface SourceType {
|
|
|
2
2
|
collectionId: string;
|
|
3
3
|
url: string;
|
|
4
4
|
instanceId?: string;
|
|
5
|
+
verticalRange?: string;
|
|
5
6
|
parameterMappings?: Record<string, string>;
|
|
6
7
|
}
|
|
7
8
|
export interface UpdateSourcePayload {
|
|
@@ -12,6 +13,7 @@ export interface SourceSelection {
|
|
|
12
13
|
url: string;
|
|
13
14
|
instanceId?: string;
|
|
14
15
|
isChecked?: boolean;
|
|
16
|
+
verticalRange?: string;
|
|
15
17
|
parameterMappings?: Record<string, string>;
|
|
16
18
|
}
|
|
17
19
|
export interface UpdateLocationPayload {
|
|
File without changes
|