@opengeoweb/soundings 15.0.0 → 15.2.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/index.esm.js +753 -207
- package/package.json +9 -9
- package/src/index.d.ts +3 -0
- package/src/lib/api/edr-api/hooks.d.ts +2 -2
- package/src/lib/components/MenuBar/LocationsMenu.d.ts +1 -1
- package/src/lib/components/MenuBar/LocationsMenuConnect.d.ts +2 -1
- package/src/lib/components/MenuBar/MenuBar.d.ts +3 -1
- package/src/lib/components/MenuBar/SoundingsMarkersSwitch.d.ts +6 -0
- package/src/lib/components/MenuBar/SoundingsMarkersSwitch.spec.d.ts +1 -0
- package/src/lib/components/MenuBar/SoundingsSourceMenu.d.ts +1 -1
- package/src/lib/components/SoundingPanelPlaceholder/SoundingPanelPlaceholder.d.ts +5 -0
- package/src/lib/components/SoundingPanelPlaceholder/SoundingPanelPlaceholder.spec.d.ts +1 -0
- package/src/lib/components/SoundingPanelPlaceholder/index.d.ts +1 -0
- package/src/lib/components/Soundings/SoundingsConnect.d.ts +3 -3
- package/src/lib/components/SoundingsAccordion/SoundingsAccordion.d.ts +1 -0
- package/src/lib/components/SoundingsManager/SoundingManagerListItem.d.ts +3 -1
- package/src/lib/components/SoundingsManager/SoundingsManager.d.ts +2 -1
- package/src/lib/components/SoundingsTimeSlider/SoundingsTimeSliderConnect.d.ts +5 -1
- package/src/lib/store/reducer.d.ts +23 -11
- package/src/lib/store/selectors.d.ts +85 -20
- package/src/lib/store/store.d.ts +4 -1
- package/src/lib/store/types.d.ts +40 -15
- package/src/lib/store/utils.d.ts +10 -0
- package/src/lib/utils/soundingsLookUp.d.ts +2 -3
package/index.esm.js
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import { Menu, ListSubheader, Typography, MenuItem, Box, Card, Stack, IconButton, Tooltip, LinearProgress, List, ListItem, ListItemIcon, Checkbox, ListItemText, Grid, ListItemButton } from '@mui/material';
|
|
3
|
+
import { range, minBy, isEqual } from 'lodash';
|
|
3
4
|
import React, { useRef, useEffect, useMemo, useState, Fragment as Fragment$1 } from 'react';
|
|
4
|
-
import { useDispatch, useSelector } from 'react-redux';
|
|
5
|
-
import { safelyInitI18nForTestsAndStories, sharedTranslations, SHARED_NAMESPACE, CustomToggleButton, dateUtils, CustomSlider, AlertBanner, ToolContainerDraggable, StyledSelect, SearchField, CustomAccordion } from '@opengeoweb/shared';
|
|
5
|
+
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
|
|
6
|
+
import { safelyInitI18nForTestsAndStories, sharedTranslations, SHARED_NAMESPACE, CustomToggleButton, dateUtils, SwitchButton, CustomSlider, AlertBanner, ToolContainerDraggable, StyledSelect, SearchField, CustomAccordion } from '@opengeoweb/shared';
|
|
6
7
|
import { selectorMemoizationOptions, uiSelectors, uiTypes, uiActions, genericSelectors, mapSelectors, genericActions, syncGroupsActions, mapActions, useSetupDialog, storeReducerMap, storeMiddlewares } from '@opengeoweb/store';
|
|
7
8
|
import { ParseISOTimeRangeDuration, parseISO8601IntervalToDateInterval, webmapUtils } from '@opengeoweb/webmap';
|
|
8
9
|
import { MapFeatureClass } from '@opengeoweb/webmap-react';
|
|
@@ -16,9 +17,8 @@ import { timesliderTranslations, TIME_SLIDER_NAMESPACE, BackwardForwardStepButto
|
|
|
16
17
|
import { useResizable } from 'react-resizable-layout';
|
|
17
18
|
import { useQueries } from '@tanstack/react-query';
|
|
18
19
|
import { getHeaders, handleResponse } from '@opengeoweb/api';
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import { FixedSizeList } from 'react-window';
|
|
20
|
+
import { createSlice, createAction, createSelector, combineReducers, configureStore } from '@reduxjs/toolkit';
|
|
21
|
+
import { List as List$1 } from 'react-window';
|
|
22
22
|
|
|
23
23
|
var en = {
|
|
24
24
|
sources: "Sources",
|
|
@@ -30,7 +30,10 @@ var en = {
|
|
|
30
30
|
options: "Options",
|
|
31
31
|
"diagram-SKEWT": "Skew-T",
|
|
32
32
|
"diagram-BIJVOET": "Bijvoet",
|
|
33
|
-
"diagram-EMAGRAM": "Emagram"
|
|
33
|
+
"diagram-EMAGRAM": "Emagram",
|
|
34
|
+
"coming-soon": "Coming soon",
|
|
35
|
+
"soundings-toggle-location-markers-label": "Markers",
|
|
36
|
+
"soundings-toggle-location-markers-tooltip": "Show/hide location markers"
|
|
34
37
|
};
|
|
35
38
|
var no = {
|
|
36
39
|
sources: "Kilder",
|
|
@@ -42,7 +45,10 @@ var no = {
|
|
|
42
45
|
options: "Valg",
|
|
43
46
|
"diagram-SKEWT": "Skew-T",
|
|
44
47
|
"diagram-BIJVOET": "Bijvoet",
|
|
45
|
-
"diagram-EMAGRAM": "Emagram"
|
|
48
|
+
"diagram-EMAGRAM": "Emagram",
|
|
49
|
+
"coming-soon": "Kommer snart",
|
|
50
|
+
"soundings-toggle-location-markers-label": "ikke oversatt",
|
|
51
|
+
"soundings-toggle-location-markers-tooltip": "ikke oversatt"
|
|
46
52
|
};
|
|
47
53
|
var nl = {
|
|
48
54
|
sources: "Bronnen",
|
|
@@ -54,7 +60,10 @@ var nl = {
|
|
|
54
60
|
options: "Opties",
|
|
55
61
|
"diagram-SKEWT": "Skew-T",
|
|
56
62
|
"diagram-BIJVOET": "Bijvoet",
|
|
57
|
-
"diagram-EMAGRAM": "Emagram"
|
|
63
|
+
"diagram-EMAGRAM": "Emagram",
|
|
64
|
+
"coming-soon": "Binnenkort beschikbaar",
|
|
65
|
+
"soundings-toggle-location-markers-label": "Kaart locaties",
|
|
66
|
+
"soundings-toggle-location-markers-tooltip": "Toon/Verberg locatie punten"
|
|
58
67
|
};
|
|
59
68
|
var fi = {
|
|
60
69
|
sources: "Lähteet",
|
|
@@ -66,7 +75,10 @@ var fi = {
|
|
|
66
75
|
options: "Valinnat",
|
|
67
76
|
"diagram-SKEWT": "Skew-T",
|
|
68
77
|
"diagram-BIJVOET": "Bijvoet",
|
|
69
|
-
"diagram-EMAGRAM": "Emagram"
|
|
78
|
+
"diagram-EMAGRAM": "Emagram",
|
|
79
|
+
"coming-soon": "Tulossa pian",
|
|
80
|
+
"soundings-toggle-location-markers-label": "Merkit",
|
|
81
|
+
"soundings-toggle-location-markers-tooltip": "Näytä/piilota kohdemerkit"
|
|
70
82
|
};
|
|
71
83
|
var soundingsTranslations = {
|
|
72
84
|
en: en,
|
|
@@ -917,7 +929,7 @@ const drawIsothermsBijvoet = ({
|
|
|
917
929
|
const pathString = lineGenerator(points);
|
|
918
930
|
const strID = `${temp}-isotherm-BIJVOET`;
|
|
919
931
|
svg.append('path').attr('id', strID).attr('d', pathString).style('fill', 'none').style('stroke-width', temp % 10 === 0 ? 2 : 1).style('stroke', temp === 0 ? '#D27D2D' : 'orange').style('stroke-opacity', 0.5).attr('clip-path', `url(#clip-${d3GraphId}-BIJVOETd3)`);
|
|
920
|
-
if (temp % 10 === 0 && points[0]
|
|
932
|
+
if (temp % 10 === 0 && points[0]?.[1] === height) {
|
|
921
933
|
svg.append('text').text(temp).attr('text-anchor', 'middle').attr('x', `${points[0][0]}px`).attr('y', `${height + 12}px`).attr('fill', temp === 0 ? '#D27D2D' : 'orange').attr('font-size', '10px');
|
|
922
934
|
}
|
|
923
935
|
}
|
|
@@ -2039,7 +2051,8 @@ const SoundingsAccordion = React.forwardRef(({
|
|
|
2039
2051
|
children,
|
|
2040
2052
|
setSoundingsIsClosed,
|
|
2041
2053
|
setPreviousHeight,
|
|
2042
|
-
size
|
|
2054
|
+
size,
|
|
2055
|
+
isDisplayed
|
|
2043
2056
|
}, aspectRatioRef) => {
|
|
2044
2057
|
const containerRef = React.useRef(null);
|
|
2045
2058
|
const widthRef = React.useRef(null);
|
|
@@ -2156,6 +2169,7 @@ const SoundingsAccordion = React.forwardRef(({
|
|
|
2156
2169
|
};
|
|
2157
2170
|
}, [autoSizing, minWidth, setContainerWidth]);
|
|
2158
2171
|
const cardStyleWhenAuto = {
|
|
2172
|
+
display: isDisplayed ? 'block' : 'none',
|
|
2159
2173
|
width: 'auto',
|
|
2160
2174
|
flex: '1 1 100%',
|
|
2161
2175
|
minWidth: 0,
|
|
@@ -2163,12 +2177,14 @@ const SoundingsAccordion = React.forwardRef(({
|
|
|
2163
2177
|
boxSizing: 'border-box'
|
|
2164
2178
|
};
|
|
2165
2179
|
const cardStyleWhenLocked = {
|
|
2180
|
+
display: isDisplayed ? 'block' : 'none',
|
|
2166
2181
|
width: containerWidth,
|
|
2167
2182
|
flex: '0 1 auto',
|
|
2168
2183
|
minWidth,
|
|
2169
2184
|
maxWidth: maxWidth || '100%',
|
|
2170
2185
|
boxSizing: 'border-box'
|
|
2171
2186
|
};
|
|
2187
|
+
//
|
|
2172
2188
|
return jsx(Card, {
|
|
2173
2189
|
className: "sortable-item",
|
|
2174
2190
|
"data-autosizing": autoSizing ? 'true' : 'false',
|
|
@@ -2283,7 +2299,7 @@ const SortableAccordions = ({
|
|
|
2283
2299
|
}) => {
|
|
2284
2300
|
const [soundingsIsClosed, setSoundingsIsClosed] = React.useState(false);
|
|
2285
2301
|
const [previousHeight, setPreviousHeight] = React.useState(size);
|
|
2286
|
-
const createPanel = React.useCallback(id => {
|
|
2302
|
+
const createPanel = React.useCallback((id, isDisplayed) => {
|
|
2287
2303
|
const normalizedId = id.toLowerCase().replace(/\s+/g, '');
|
|
2288
2304
|
switch (normalizedId) {
|
|
2289
2305
|
case 'soundings':
|
|
@@ -2293,6 +2309,7 @@ const SortableAccordions = ({
|
|
|
2293
2309
|
diagramType: chosenDiagramType,
|
|
2294
2310
|
setDiagramType: setChosenDiagramType
|
|
2295
2311
|
}),
|
|
2312
|
+
isDisplayed: isDisplayed,
|
|
2296
2313
|
name: "Soundings",
|
|
2297
2314
|
ref: viewRef,
|
|
2298
2315
|
setPreviousHeight: setPreviousHeight,
|
|
@@ -2316,6 +2333,7 @@ const SortableAccordions = ({
|
|
|
2316
2333
|
});
|
|
2317
2334
|
case 'windbarbs':
|
|
2318
2335
|
return jsx(SoundingsAccordion, {
|
|
2336
|
+
isDisplayed: isDisplayed,
|
|
2319
2337
|
maxWidth: 200,
|
|
2320
2338
|
name: "Wind Barbs",
|
|
2321
2339
|
children: jsx(WindBarbs, {
|
|
@@ -2370,16 +2388,18 @@ const SortableAccordions = ({
|
|
|
2370
2388
|
width: '100%'
|
|
2371
2389
|
},
|
|
2372
2390
|
tag: "div",
|
|
2373
|
-
children: soundingPanelsInOrder.
|
|
2374
|
-
id
|
|
2391
|
+
children: soundingPanelsInOrder.flatMap(({
|
|
2392
|
+
id,
|
|
2393
|
+
isDisplayed
|
|
2375
2394
|
}) => {
|
|
2376
|
-
const panel = createPanel(id);
|
|
2395
|
+
const panel = createPanel(id, isDisplayed);
|
|
2377
2396
|
if (!panel) {
|
|
2378
2397
|
return [];
|
|
2379
2398
|
}
|
|
2380
2399
|
return panel ? jsx(React.Fragment, {
|
|
2381
2400
|
children: React.cloneElement(panel, {
|
|
2382
2401
|
accordionId: id,
|
|
2402
|
+
isDisplayed,
|
|
2383
2403
|
handleButtonComponent: jsx(IconButton, {
|
|
2384
2404
|
"aria-label": "drag-handle",
|
|
2385
2405
|
className: "drag-handle",
|
|
@@ -2850,10 +2870,28 @@ const useMultipleSources = (sources, locations, datetime) => {
|
|
|
2850
2870
|
parameterMappings,
|
|
2851
2871
|
verticalRange
|
|
2852
2872
|
}, index) => {
|
|
2853
|
-
//
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2873
|
+
// Find the best matching timestep for this source
|
|
2874
|
+
let dateToUse = '';
|
|
2875
|
+
if (datetime && timesteps[index] && timesteps[index].length > 0) {
|
|
2876
|
+
const requestedTime = new Date(datetime).getTime();
|
|
2877
|
+
const availableTimesteps = timesteps[index];
|
|
2878
|
+
// Check for exact match first
|
|
2879
|
+
if (availableTimesteps.includes(new Date(datetime).toISOString())) {
|
|
2880
|
+
dateToUse = datetime;
|
|
2881
|
+
} else {
|
|
2882
|
+
// Find nearest timestep (prefer earlier timesteps if equidistant)
|
|
2883
|
+
let nearestTimestep = availableTimesteps[0];
|
|
2884
|
+
let minDiff = Math.abs(new Date(availableTimesteps[0]).getTime() - requestedTime);
|
|
2885
|
+
for (const timestep of availableTimesteps) {
|
|
2886
|
+
const diff = Math.abs(new Date(timestep).getTime() - requestedTime);
|
|
2887
|
+
if (diff < minDiff) {
|
|
2888
|
+
minDiff = diff;
|
|
2889
|
+
nearestTimestep = timestep;
|
|
2890
|
+
}
|
|
2891
|
+
}
|
|
2892
|
+
dateToUse = nearestTimestep;
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2857
2895
|
const queryParams = constructQueryParams(collectionId, url, instanceId, locations[collectionId] || '', dateToUse || '', parameterMappings || defaultParameterMappings, verticalRange || '');
|
|
2858
2896
|
return queryParams;
|
|
2859
2897
|
});
|
|
@@ -3035,6 +3073,48 @@ const useGetCollectionLocations = (collections, enabled) => {
|
|
|
3035
3073
|
});
|
|
3036
3074
|
};
|
|
3037
3075
|
|
|
3076
|
+
/* *
|
|
3077
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
3078
|
+
* you may not use this file except in compliance with the License.
|
|
3079
|
+
* You may obtain a copy of the License at
|
|
3080
|
+
*
|
|
3081
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
3082
|
+
*
|
|
3083
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
3084
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
3085
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
3086
|
+
* See the License for the specific language governing permissions and
|
|
3087
|
+
* limitations under the License.
|
|
3088
|
+
*
|
|
3089
|
+
* Copyright 2025 - Koninklijk Nederlands Meteorologisch Instituut (KNMI)
|
|
3090
|
+
* Copyright 2025 - Finnish Meteorological Institute (FMI)
|
|
3091
|
+
* Copyright 2025 - The Norwegian Meteorological Institute (MET Norway)
|
|
3092
|
+
* */
|
|
3093
|
+
const emptyPanelIds = [];
|
|
3094
|
+
const toStringArray = value => {
|
|
3095
|
+
if (!Array.isArray(value)) {
|
|
3096
|
+
return emptyPanelIds;
|
|
3097
|
+
}
|
|
3098
|
+
return value.filter(item => typeof item === 'string');
|
|
3099
|
+
};
|
|
3100
|
+
const getRegisteredPanelIds = state => {
|
|
3101
|
+
if (!state) {
|
|
3102
|
+
return emptyPanelIds;
|
|
3103
|
+
}
|
|
3104
|
+
const registeredPanelIds = toStringArray(state.registeredPanelIds);
|
|
3105
|
+
if (registeredPanelIds.length > 0) {
|
|
3106
|
+
return registeredPanelIds;
|
|
3107
|
+
}
|
|
3108
|
+
return Object.keys(state.byId);
|
|
3109
|
+
};
|
|
3110
|
+
const isRegisteredPanelId = (state, panelId) => {
|
|
3111
|
+
if (!panelId) {
|
|
3112
|
+
return false;
|
|
3113
|
+
}
|
|
3114
|
+
return getRegisteredPanelIds(state).includes(panelId);
|
|
3115
|
+
};
|
|
3116
|
+
const getPanelIdFromAction = action => action.payload?.panelId;
|
|
3117
|
+
|
|
3038
3118
|
/* *
|
|
3039
3119
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
3040
3120
|
* you may not use this file except in compliance with the License.
|
|
@@ -3056,15 +3136,48 @@ const initialSoundingsState = {
|
|
|
3056
3136
|
selectedSources: {},
|
|
3057
3137
|
selectedLocations: {},
|
|
3058
3138
|
selectedTime: new Date().toISOString(),
|
|
3139
|
+
diagramType: 'SKEWT',
|
|
3059
3140
|
soundingPanels: {
|
|
3060
|
-
order: [],
|
|
3061
|
-
entities: {
|
|
3062
|
-
|
|
3141
|
+
order: ['soundings', 'windbarbs'],
|
|
3142
|
+
entities: {
|
|
3143
|
+
soundings: {
|
|
3144
|
+
id: 'soundings',
|
|
3145
|
+
name: 'Soundings',
|
|
3146
|
+
isDisplayed: true
|
|
3147
|
+
},
|
|
3148
|
+
windbarbs: {
|
|
3149
|
+
id: 'windbarbs',
|
|
3150
|
+
name: 'Wind Barbs',
|
|
3151
|
+
isDisplayed: true
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
},
|
|
3155
|
+
shouldHideLocationMarkers: false
|
|
3156
|
+
};
|
|
3157
|
+
const initialState = {
|
|
3158
|
+
byId: {},
|
|
3159
|
+
registeredPanelIds: [],
|
|
3160
|
+
soundingsCollections: []
|
|
3063
3161
|
};
|
|
3064
3162
|
const slice = createSlice({
|
|
3065
3163
|
initialState: initialSoundingsState,
|
|
3066
3164
|
name: 'soundings',
|
|
3067
3165
|
reducers: {
|
|
3166
|
+
registerSoundingsPanel: (draft, _payloadAction) => {
|
|
3167
|
+
},
|
|
3168
|
+
registerSoundingsPreset: (draft, payloadAction) => {
|
|
3169
|
+
const {
|
|
3170
|
+
preset
|
|
3171
|
+
} = payloadAction.payload;
|
|
3172
|
+
if (preset) {
|
|
3173
|
+
draft.selectedSources = preset.selectedSources ?? {};
|
|
3174
|
+
draft.selectedLocations = preset.selectedLocations ?? {};
|
|
3175
|
+
draft.selectedTime = preset.selectedTime ?? new Date().toISOString();
|
|
3176
|
+
draft.diagramType = preset.diagramType ?? 'SKEWT';
|
|
3177
|
+
draft.soundingPanels = preset.soundingPanels ?? initialSoundingsState.soundingPanels;
|
|
3178
|
+
draft.shouldHideLocationMarkers = preset.shouldHideLocationMarkers ?? false;
|
|
3179
|
+
}
|
|
3180
|
+
},
|
|
3068
3181
|
updateSelectedSource: (draft, payloadAction) => {
|
|
3069
3182
|
const {
|
|
3070
3183
|
sourceId,
|
|
@@ -3088,11 +3201,20 @@ const slice = createSlice({
|
|
|
3088
3201
|
} = payloadAction.payload;
|
|
3089
3202
|
draft.selectedTime = selectedTime;
|
|
3090
3203
|
},
|
|
3204
|
+
updateDiagramType: (draft, payloadAction) => {
|
|
3205
|
+
draft.diagramType = payloadAction.payload.diagramType;
|
|
3206
|
+
},
|
|
3207
|
+
toggleLocationMarkers: (draft, payloadAction) => {
|
|
3208
|
+
const {
|
|
3209
|
+
shouldHideLocationMarkers
|
|
3210
|
+
} = payloadAction.payload;
|
|
3211
|
+
draft.shouldHideLocationMarkers = shouldHideLocationMarkers;
|
|
3212
|
+
},
|
|
3091
3213
|
addSoundingPanelsFromPreset: (draft, payloadAction) => {
|
|
3092
3214
|
const {
|
|
3093
3215
|
order,
|
|
3094
3216
|
entities
|
|
3095
|
-
} = payloadAction.payload;
|
|
3217
|
+
} = payloadAction.payload.panels;
|
|
3096
3218
|
draft.soundingPanels.order = order;
|
|
3097
3219
|
draft.soundingPanels.entities = entities;
|
|
3098
3220
|
},
|
|
@@ -3101,13 +3223,86 @@ const slice = createSlice({
|
|
|
3101
3223
|
newOrderOfIds
|
|
3102
3224
|
} = payloadAction.payload;
|
|
3103
3225
|
draft.soundingPanels.order = newOrderOfIds;
|
|
3226
|
+
},
|
|
3227
|
+
toggleSoundingPanelVisibility: (draft, payloadAction) => {
|
|
3228
|
+
const {
|
|
3229
|
+
id
|
|
3230
|
+
} = payloadAction.payload;
|
|
3231
|
+
const panel = draft.soundingPanels.entities[id];
|
|
3232
|
+
if (panel) {
|
|
3233
|
+
panel.isDisplayed = !panel.isDisplayed;
|
|
3234
|
+
}
|
|
3104
3235
|
}
|
|
3105
3236
|
}
|
|
3106
3237
|
});
|
|
3107
|
-
const
|
|
3108
|
-
|
|
3109
|
-
actions
|
|
3110
|
-
|
|
3238
|
+
const setSoundingsCollections = createAction('soundings/setCollections');
|
|
3239
|
+
const soundingsActions = {
|
|
3240
|
+
...slice.actions,
|
|
3241
|
+
setSoundingsCollections
|
|
3242
|
+
};
|
|
3243
|
+
const shouldHandlePanelAction = (state, action) => {
|
|
3244
|
+
return isRegisteredPanelId(state, getPanelIdFromAction(action));
|
|
3245
|
+
};
|
|
3246
|
+
const normalizeSoundingsState = state => {
|
|
3247
|
+
if ('byId' in state) {
|
|
3248
|
+
return state;
|
|
3249
|
+
}
|
|
3250
|
+
return {
|
|
3251
|
+
...initialState,
|
|
3252
|
+
byId: {
|
|
3253
|
+
...initialState.byId,
|
|
3254
|
+
default: state
|
|
3255
|
+
},
|
|
3256
|
+
registeredPanelIds: ['default']
|
|
3257
|
+
};
|
|
3258
|
+
};
|
|
3259
|
+
const soundingsReducer = (state, action) => {
|
|
3260
|
+
const normalizedState = normalizeSoundingsState(state ?? initialState);
|
|
3261
|
+
if (action.type === setSoundingsCollections.type) {
|
|
3262
|
+
const collections = action.payload;
|
|
3263
|
+
if (collections === normalizedState.soundingsCollections) {
|
|
3264
|
+
return normalizedState;
|
|
3265
|
+
}
|
|
3266
|
+
return {
|
|
3267
|
+
...normalizedState,
|
|
3268
|
+
soundingsCollections: collections
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
if (action.type === slice.actions.registerSoundingsPanel.type) {
|
|
3272
|
+
const {
|
|
3273
|
+
panelId
|
|
3274
|
+
} = action.payload;
|
|
3275
|
+
if (!panelId) {
|
|
3276
|
+
return normalizedState;
|
|
3277
|
+
}
|
|
3278
|
+
if (normalizedState.registeredPanelIds?.includes(panelId)) {
|
|
3279
|
+
return normalizedState;
|
|
3280
|
+
}
|
|
3281
|
+
return {
|
|
3282
|
+
...normalizedState,
|
|
3283
|
+
registeredPanelIds: [...(normalizedState.registeredPanelIds ?? []), panelId]
|
|
3284
|
+
};
|
|
3285
|
+
}
|
|
3286
|
+
if (!shouldHandlePanelAction(normalizedState, action)) {
|
|
3287
|
+
return normalizedState;
|
|
3288
|
+
}
|
|
3289
|
+
const panelId = getPanelIdFromAction(action);
|
|
3290
|
+
if (!panelId) {
|
|
3291
|
+
return normalizedState;
|
|
3292
|
+
}
|
|
3293
|
+
const currentPanelState = normalizedState.byId[panelId];
|
|
3294
|
+
const nextPanelState = slice.reducer(currentPanelState ?? initialSoundingsState, action);
|
|
3295
|
+
if (nextPanelState === currentPanelState) {
|
|
3296
|
+
return normalizedState;
|
|
3297
|
+
}
|
|
3298
|
+
return {
|
|
3299
|
+
...normalizedState,
|
|
3300
|
+
byId: {
|
|
3301
|
+
...normalizedState.byId,
|
|
3302
|
+
[panelId]: nextPanelState
|
|
3303
|
+
}
|
|
3304
|
+
};
|
|
3305
|
+
};
|
|
3111
3306
|
|
|
3112
3307
|
/* *
|
|
3113
3308
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -3126,12 +3321,23 @@ const {
|
|
|
3126
3321
|
* Copyright 2025 - Finnish Meteorological Institute (FMI)
|
|
3127
3322
|
* Copyright 2025 - The Norwegian Meteorological Institute (MET Norway)
|
|
3128
3323
|
* */
|
|
3129
|
-
const
|
|
3324
|
+
const emptySoundingsCollections = [];
|
|
3325
|
+
const getSoundingsStore = (store, panelId) => {
|
|
3326
|
+
const soundingsState = store?.soundings;
|
|
3327
|
+
if (!panelId || !isRegisteredPanelId(soundingsState, panelId)) {
|
|
3328
|
+
return initialSoundingsState;
|
|
3329
|
+
}
|
|
3330
|
+
const panelStore = soundingsState?.byId[panelId];
|
|
3331
|
+
return panelStore ?? initialSoundingsState;
|
|
3332
|
+
};
|
|
3333
|
+
const getSoundingsCollections = store => store?.soundings?.soundingsCollections || emptySoundingsCollections;
|
|
3130
3334
|
const getSourceSelections = createSelector(getSoundingsStore, store => {
|
|
3131
3335
|
return store.selectedSources;
|
|
3132
3336
|
}, selectorMemoizationOptions);
|
|
3133
3337
|
const getLocationSelections = createSelector(getSoundingsStore, store => store.selectedLocations, selectorMemoizationOptions);
|
|
3134
|
-
const getSelectedTime = createSelector(getSoundingsStore, store => store.selectedTime, selectorMemoizationOptions);
|
|
3338
|
+
const getSelectedTime = createSelector(getSoundingsStore, store => store.selectedTime ?? new Date().toISOString(), selectorMemoizationOptions);
|
|
3339
|
+
const getDiagramType = createSelector(getSoundingsStore, store => store.diagramType ?? 'SKEWT', selectorMemoizationOptions);
|
|
3340
|
+
const getShouldHideLocationMarkers = createSelector(getSoundingsStore, store => store.shouldHideLocationMarkers ?? false, selectorMemoizationOptions);
|
|
3135
3341
|
const getSelectedSources = createSelector(getSoundingsStore, store => {
|
|
3136
3342
|
const sources = store.selectedSources;
|
|
3137
3343
|
const activeSources = Object.keys(sources).reduce((list, key) => {
|
|
@@ -3139,11 +3345,11 @@ const getSelectedSources = createSelector(getSoundingsStore, store => {
|
|
|
3139
3345
|
if (value.isChecked === true) {
|
|
3140
3346
|
return list.concat({
|
|
3141
3347
|
collectionId: key,
|
|
3142
|
-
url: value.url,
|
|
3348
|
+
url: value.url ?? '',
|
|
3143
3349
|
instanceId: value.instanceId,
|
|
3144
3350
|
verticalRange: value.verticalRange,
|
|
3145
3351
|
parameterMappings: value.parameterMappings,
|
|
3146
|
-
name: value.name
|
|
3352
|
+
name: value.name ?? ''
|
|
3147
3353
|
});
|
|
3148
3354
|
}
|
|
3149
3355
|
return list;
|
|
@@ -3156,17 +3362,138 @@ const getSelectedSourcesAmount = createSelector(getSelectedSources, activeSource
|
|
|
3156
3362
|
const getSelectedSourcesIds = createSelector(getSelectedSources, activeSources => {
|
|
3157
3363
|
return activeSources.map(source => source.collectionId);
|
|
3158
3364
|
}, selectorMemoizationOptions);
|
|
3365
|
+
const getSoundingsPreset = createSelector(getSoundingsStore, soundingsStore => {
|
|
3366
|
+
const {
|
|
3367
|
+
selectedTime,
|
|
3368
|
+
selectedSources,
|
|
3369
|
+
...rest
|
|
3370
|
+
} = soundingsStore;
|
|
3371
|
+
const filteredSources = Object.entries(selectedSources).reduce((acc, [key, value]) => {
|
|
3372
|
+
const {
|
|
3373
|
+
instanceId,
|
|
3374
|
+
...sourceWithoutInstance
|
|
3375
|
+
} = value;
|
|
3376
|
+
return {
|
|
3377
|
+
...acc,
|
|
3378
|
+
[key]: sourceWithoutInstance
|
|
3379
|
+
};
|
|
3380
|
+
}, {});
|
|
3381
|
+
return {
|
|
3382
|
+
...rest,
|
|
3383
|
+
selectedSources: filteredSources
|
|
3384
|
+
};
|
|
3385
|
+
}, selectorMemoizationOptions);
|
|
3386
|
+
const EMPTY_SOUDINGS_PANELS = {
|
|
3387
|
+
order: [],
|
|
3388
|
+
entities: {}
|
|
3389
|
+
};
|
|
3159
3390
|
const getSoundingPanelsInOrder = createSelector(getSoundingsStore, store => {
|
|
3160
3391
|
const {
|
|
3161
3392
|
order = [],
|
|
3162
3393
|
entities = {}
|
|
3163
|
-
} = store.soundingPanels ||
|
|
3164
|
-
order: [],
|
|
3165
|
-
entities: {}
|
|
3166
|
-
};
|
|
3394
|
+
} = store.soundingPanels || EMPTY_SOUDINGS_PANELS;
|
|
3167
3395
|
return order.map(id => entities[id]);
|
|
3168
3396
|
}, selectorMemoizationOptions);
|
|
3169
3397
|
|
|
3398
|
+
var selectors = /*#__PURE__*/Object.freeze({
|
|
3399
|
+
__proto__: null,
|
|
3400
|
+
getDiagramType: getDiagramType,
|
|
3401
|
+
getLocationSelections: getLocationSelections,
|
|
3402
|
+
getSelectedSources: getSelectedSources,
|
|
3403
|
+
getSelectedSourcesAmount: getSelectedSourcesAmount,
|
|
3404
|
+
getSelectedSourcesIds: getSelectedSourcesIds,
|
|
3405
|
+
getSelectedTime: getSelectedTime,
|
|
3406
|
+
getShouldHideLocationMarkers: getShouldHideLocationMarkers,
|
|
3407
|
+
getSoundingPanelsInOrder: getSoundingPanelsInOrder,
|
|
3408
|
+
getSoundingsCollections: getSoundingsCollections,
|
|
3409
|
+
getSoundingsPreset: getSoundingsPreset,
|
|
3410
|
+
getSourceSelections: getSourceSelections
|
|
3411
|
+
});
|
|
3412
|
+
|
|
3413
|
+
/* *
|
|
3414
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
3415
|
+
* you may not use this file except in compliance with the License.
|
|
3416
|
+
* You may obtain a copy of the License at
|
|
3417
|
+
*
|
|
3418
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
3419
|
+
*
|
|
3420
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
3421
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
3422
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
3423
|
+
* See the License for the specific language governing permissions and
|
|
3424
|
+
* limitations under the License.
|
|
3425
|
+
*
|
|
3426
|
+
* Copyright 2025 - Koninklijk Nederlands Meteorologisch Instituut (KNMI)
|
|
3427
|
+
* Copyright 2025 - Finnish Meteorological Institute (FMI)
|
|
3428
|
+
* Copyright 2025 - The Norwegian Meteorological Institute (MET Norway)
|
|
3429
|
+
* */
|
|
3430
|
+
var SoundingsActionOrigin;
|
|
3431
|
+
(function (SoundingsActionOrigin) {
|
|
3432
|
+
SoundingsActionOrigin["soundingsManager"] = "soundingsManager";
|
|
3433
|
+
SoundingsActionOrigin["soundingsComponent"] = "soundingsComponent";
|
|
3434
|
+
})(SoundingsActionOrigin || (SoundingsActionOrigin = {}));
|
|
3435
|
+
|
|
3436
|
+
var types = /*#__PURE__*/Object.freeze({
|
|
3437
|
+
__proto__: null,
|
|
3438
|
+
get SoundingsActionOrigin () { return SoundingsActionOrigin; }
|
|
3439
|
+
});
|
|
3440
|
+
|
|
3441
|
+
const SoundingsMarkersSwitch = ({
|
|
3442
|
+
shouldHideMarkers,
|
|
3443
|
+
toggleMarkers
|
|
3444
|
+
}) => {
|
|
3445
|
+
const {
|
|
3446
|
+
t
|
|
3447
|
+
} = useSoundingsTranslation();
|
|
3448
|
+
return jsxs(Box, {
|
|
3449
|
+
sx: {
|
|
3450
|
+
display: 'flex',
|
|
3451
|
+
flexWrap: 'wrap',
|
|
3452
|
+
alignItems: 'flex-start',
|
|
3453
|
+
'label:first-of-type': {
|
|
3454
|
+
marginLeft: '5px',
|
|
3455
|
+
marginRight: '-5px'
|
|
3456
|
+
},
|
|
3457
|
+
'label:last-of-type': {
|
|
3458
|
+
marginLeft: '-5px'
|
|
3459
|
+
},
|
|
3460
|
+
'.switch-button label': {
|
|
3461
|
+
display: 'none'
|
|
3462
|
+
},
|
|
3463
|
+
'.markers-label': {
|
|
3464
|
+
display: 'none'
|
|
3465
|
+
},
|
|
3466
|
+
'@media (min-width: 720px)': {
|
|
3467
|
+
minWidth: '146px',
|
|
3468
|
+
'.markers-label, .switch-button label': {
|
|
3469
|
+
display: 'initial'
|
|
3470
|
+
}
|
|
3471
|
+
}
|
|
3472
|
+
},
|
|
3473
|
+
children: [jsx(Typography, {
|
|
3474
|
+
className: "markers-label",
|
|
3475
|
+
sx: {
|
|
3476
|
+
marginTop: '4px'
|
|
3477
|
+
},
|
|
3478
|
+
variant: "body2",
|
|
3479
|
+
children: t('soundings-toggle-location-markers-label')
|
|
3480
|
+
}), jsx(Box, {
|
|
3481
|
+
sx: {
|
|
3482
|
+
marginTop: '-5px'
|
|
3483
|
+
},
|
|
3484
|
+
children: jsx(SwitchButton, {
|
|
3485
|
+
activeLabel: "ON",
|
|
3486
|
+
checked: !shouldHideMarkers,
|
|
3487
|
+
inActiveLabel: "OFF",
|
|
3488
|
+
onChange: event => {
|
|
3489
|
+
toggleMarkers(!event.target.checked);
|
|
3490
|
+
},
|
|
3491
|
+
tooltip: t('soundings-toggle-location-markers-tooltip')
|
|
3492
|
+
})
|
|
3493
|
+
})]
|
|
3494
|
+
});
|
|
3495
|
+
};
|
|
3496
|
+
|
|
3170
3497
|
var MenuOptions;
|
|
3171
3498
|
(function (MenuOptions) {
|
|
3172
3499
|
MenuOptions["soundingsManager"] = "Sd Manager";
|
|
@@ -3180,7 +3507,9 @@ const buttonStyle = {
|
|
|
3180
3507
|
const SoundingsMenuBar = ({
|
|
3181
3508
|
handleClick,
|
|
3182
3509
|
isOpen,
|
|
3183
|
-
selectedSourcesAmount = 0
|
|
3510
|
+
selectedSourcesAmount = 0,
|
|
3511
|
+
shouldHideMarkers,
|
|
3512
|
+
toggleMarkers
|
|
3184
3513
|
}) => {
|
|
3185
3514
|
const {
|
|
3186
3515
|
t
|
|
@@ -3219,6 +3548,9 @@ const SoundingsMenuBar = ({
|
|
|
3219
3548
|
sx: buttonStyle,
|
|
3220
3549
|
variant: "tool",
|
|
3221
3550
|
children: t('locations')
|
|
3551
|
+
}), jsx(SoundingsMarkersSwitch, {
|
|
3552
|
+
shouldHideMarkers: shouldHideMarkers,
|
|
3553
|
+
toggleMarkers: toggleMarkers
|
|
3222
3554
|
})]
|
|
3223
3555
|
});
|
|
3224
3556
|
};
|
|
@@ -3228,13 +3560,26 @@ const MenuBarConnect = ({
|
|
|
3228
3560
|
source
|
|
3229
3561
|
}) => {
|
|
3230
3562
|
const dispatch = useDispatch();
|
|
3563
|
+
React.useEffect(() => {
|
|
3564
|
+
dispatch(soundingsActions.registerSoundingsPanel({
|
|
3565
|
+
panelId: viewId
|
|
3566
|
+
}));
|
|
3567
|
+
}, [dispatch, viewId]);
|
|
3231
3568
|
const currentActiveMapIdSources = useSelector(store => uiSelectors.getDialogMapId(store, uiTypes.DialogTypes.SoundingsSources));
|
|
3232
3569
|
const currentActiveMapIdLocations = useSelector(store => uiSelectors.getDialogMapId(store, uiTypes.DialogTypes.SoundingsLocations));
|
|
3233
3570
|
const currentActiveMapIdsoundingsManager = useSelector(store => uiSelectors.getDialogMapId(store, uiTypes.DialogTypes.SoundingsManager));
|
|
3234
3571
|
const isSourcesOpenInStore = useSelector(store => uiSelectors.getisDialogOpen(store, uiTypes.DialogTypes.SoundingsSources));
|
|
3235
3572
|
const isLocationsOpenInStore = useSelector(store => uiSelectors.getisDialogOpen(store, uiTypes.DialogTypes.SoundingsLocations));
|
|
3236
3573
|
const isSoundingsManagerOpenInStore = useSelector(store => uiSelectors.getisDialogOpen(store, uiTypes.DialogTypes.SoundingsManager));
|
|
3237
|
-
const sourcesAmount = useSelector(getSelectedSourcesAmount);
|
|
3574
|
+
const sourcesAmount = useSelector(state => getSelectedSourcesAmount(state, viewId));
|
|
3575
|
+
const shouldHideLocationMarkers = useSelector(state => getShouldHideLocationMarkers(state, viewId));
|
|
3576
|
+
const toggleLocationMarkers = React.useCallback(shouldHide => {
|
|
3577
|
+
dispatch(soundingsActions.toggleLocationMarkers({
|
|
3578
|
+
shouldHideLocationMarkers: shouldHide,
|
|
3579
|
+
panelId: viewId,
|
|
3580
|
+
origin: SoundingsActionOrigin.soundingsComponent
|
|
3581
|
+
}));
|
|
3582
|
+
}, [dispatch, viewId]);
|
|
3238
3583
|
const dispatchActiveMapId = React.useCallback((dialogType, isOpen, activeMapId) => void dispatch(uiActions.setActiveMapIdForDialog({
|
|
3239
3584
|
type: dialogType,
|
|
3240
3585
|
mapId: viewId,
|
|
@@ -3257,12 +3602,14 @@ const MenuBarConnect = ({
|
|
|
3257
3602
|
const isOpen = {
|
|
3258
3603
|
[MenuOptions.sources]: currentActiveMapIdSources === viewId && isSourcesOpenInStore,
|
|
3259
3604
|
[MenuOptions.locations]: currentActiveMapIdLocations === viewId && isLocationsOpenInStore,
|
|
3260
|
-
[MenuOptions.soundingsManager]: isSoundingsManagerOpenInStore
|
|
3605
|
+
[MenuOptions.soundingsManager]: currentActiveMapIdsoundingsManager === viewId && isSoundingsManagerOpenInStore
|
|
3261
3606
|
};
|
|
3262
3607
|
return jsx(SoundingsMenuBar, {
|
|
3263
3608
|
handleClick: handleClick,
|
|
3264
3609
|
isOpen: isOpen,
|
|
3265
|
-
selectedSourcesAmount: sourcesAmount
|
|
3610
|
+
selectedSourcesAmount: sourcesAmount,
|
|
3611
|
+
shouldHideMarkers: shouldHideLocationMarkers,
|
|
3612
|
+
toggleMarkers: toggleLocationMarkers
|
|
3266
3613
|
});
|
|
3267
3614
|
};
|
|
3268
3615
|
|
|
@@ -3402,24 +3749,33 @@ const roundToClosestTimestep = (timeToRound, availableSteps) => {
|
|
|
3402
3749
|
}
|
|
3403
3750
|
return timeToRound;
|
|
3404
3751
|
};
|
|
3405
|
-
const SoundingsTimeSliderConnect = (
|
|
3406
|
-
|
|
3407
|
-
|
|
3752
|
+
const SoundingsTimeSliderConnect = ({
|
|
3753
|
+
viewId
|
|
3754
|
+
}) => {
|
|
3755
|
+
const selectedTime = useSelector(state => getSelectedTime(state, viewId));
|
|
3756
|
+
const sourceSelections = useSelector(state => getSelectedSources(state, viewId));
|
|
3408
3757
|
const dispatch = useDispatch();
|
|
3409
|
-
const updateSelectedTime = React.useCallback(selectedTime => {
|
|
3758
|
+
const updateSelectedTime = React.useCallback((selectedTime, isInitialCorrection = false) => {
|
|
3410
3759
|
dispatch(soundingsActions.updateSelectedTime({
|
|
3411
|
-
selectedTime
|
|
3760
|
+
selectedTime,
|
|
3761
|
+
panelId: viewId,
|
|
3762
|
+
origin: isInitialCorrection ? SoundingsActionOrigin.soundingsManager : SoundingsActionOrigin.soundingsComponent
|
|
3412
3763
|
}));
|
|
3413
|
-
}, [dispatch]);
|
|
3764
|
+
}, [dispatch, viewId]);
|
|
3414
3765
|
const {
|
|
3415
3766
|
data: timesteps
|
|
3416
3767
|
} = useTimesteps(sourceSelections);
|
|
3417
3768
|
const mergedTimesteps = [...new Set(timesteps.flat())].sort();
|
|
3769
|
+
const hasInitializedTime = React.useRef(false);
|
|
3418
3770
|
// Ensure that the selected time is always one of the available timesteps
|
|
3419
3771
|
const validSelectedTime = roundToClosestTimestep(selectedTime, mergedTimesteps);
|
|
3420
3772
|
useEffect(() => {
|
|
3421
3773
|
if (selectedTime !== validSelectedTime) {
|
|
3422
|
-
|
|
3774
|
+
const isInitial = !hasInitializedTime.current;
|
|
3775
|
+
updateSelectedTime(validSelectedTime, isInitial);
|
|
3776
|
+
if (isInitial) {
|
|
3777
|
+
hasInitializedTime.current = true;
|
|
3778
|
+
}
|
|
3423
3779
|
}
|
|
3424
3780
|
}, [selectedTime, updateSelectedTime, validSelectedTime]);
|
|
3425
3781
|
return jsx(SoundingsTimeSlider, {
|
|
@@ -3458,33 +3814,86 @@ const useGetSize = viewRef => {
|
|
|
3458
3814
|
};
|
|
3459
3815
|
const SoundingsConnect = ({
|
|
3460
3816
|
viewId,
|
|
3461
|
-
|
|
3817
|
+
soundingsPreset
|
|
3462
3818
|
}) => {
|
|
3463
3819
|
const viewRef = React.useRef(null);
|
|
3464
3820
|
const size = useGetSize(viewRef);
|
|
3465
|
-
const [chosenDiagramType, setChosenDiagramType] = React.useState(diagramType);
|
|
3466
3821
|
const geojsonLayerId = React.useRef(webmapUtils.generateLayerId()).current;
|
|
3467
3822
|
const dispatch = useDispatch();
|
|
3468
|
-
const
|
|
3469
|
-
const
|
|
3470
|
-
const
|
|
3471
|
-
const
|
|
3472
|
-
|
|
3823
|
+
const soundingsPresetRef = React.useRef();
|
|
3824
|
+
const presetJustLoadedRef = React.useRef(false);
|
|
3825
|
+
const initialLocationsRef = React.useRef({});
|
|
3826
|
+
const previousLocationsRef = React.useRef({});
|
|
3827
|
+
React.useLayoutEffect(() => {
|
|
3828
|
+
dispatch(soundingsActions.registerSoundingsPanel({
|
|
3829
|
+
panelId: viewId
|
|
3830
|
+
}));
|
|
3831
|
+
if (soundingsPreset && !isEqual(soundingsPreset, soundingsPresetRef.current)) {
|
|
3832
|
+
soundingsPresetRef.current = soundingsPreset;
|
|
3833
|
+
presetJustLoadedRef.current = true;
|
|
3834
|
+
initialLocationsRef.current = soundingsPreset.selectedLocations || {};
|
|
3835
|
+
previousLocationsRef.current = {};
|
|
3836
|
+
dispatch(soundingsActions.registerSoundingsPreset({
|
|
3837
|
+
panelId: viewId,
|
|
3838
|
+
preset: soundingsPreset
|
|
3839
|
+
}));
|
|
3840
|
+
setTimeout(() => {
|
|
3841
|
+
presetJustLoadedRef.current = false;
|
|
3842
|
+
initialLocationsRef.current = {};
|
|
3843
|
+
}, 500);
|
|
3844
|
+
} else if (!soundingsPreset) {
|
|
3845
|
+
soundingsPresetRef.current = undefined;
|
|
3846
|
+
initialLocationsRef.current = {};
|
|
3847
|
+
previousLocationsRef.current = {};
|
|
3848
|
+
}
|
|
3849
|
+
}, [dispatch, soundingsPreset, viewId]);
|
|
3850
|
+
const selectedTime = useSelector(state => getSelectedTime(state, viewId));
|
|
3851
|
+
const sourceSelections = useSelector(state => getSelectedSources(state, viewId), shallowEqual);
|
|
3852
|
+
const locationSelections = useSelector(state => getLocationSelections(state, viewId), shallowEqual);
|
|
3853
|
+
const diagramType = useSelector(state => getDiagramType(state, viewId));
|
|
3854
|
+
const shouldHideLocationMarkers = useSelector(state => getShouldHideLocationMarkers(state, viewId));
|
|
3855
|
+
const setChosenDiagramType = React.useCallback(diagramType => {
|
|
3856
|
+
dispatch(soundingsActions.updateDiagramType({
|
|
3857
|
+
diagramType,
|
|
3858
|
+
panelId: viewId,
|
|
3859
|
+
origin: SoundingsActionOrigin.soundingsComponent
|
|
3860
|
+
}));
|
|
3861
|
+
}, [dispatch, viewId]);
|
|
3862
|
+
const selectedFeature = useSelector(state => genericSelectors.getSelectedFeature(state.syncGroups, viewId), shallowEqual);
|
|
3863
|
+
const selectedMapIds = useSelector(state => genericSelectors.getLinkedMaps(state, viewId), shallowEqual);
|
|
3864
|
+
const firstMapId = selectedMapIds[0];
|
|
3473
3865
|
const selectedMapPin = useSelector(state =>
|
|
3474
3866
|
// mapPins are synced so we can arbitrarily choose the first linked map
|
|
3475
|
-
mapSelectors.getPinLocation(state,
|
|
3476
|
-
const
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3867
|
+
mapSelectors.getPinLocation(state, firstMapId), shallowEqual);
|
|
3868
|
+
const collectionsRef = React.useRef();
|
|
3869
|
+
const collections = useMemo(() => {
|
|
3870
|
+
const newCollections = sourceSelections.map(({
|
|
3871
|
+
collectionId,
|
|
3872
|
+
url,
|
|
3873
|
+
name
|
|
3874
|
+
}) => ({
|
|
3875
|
+
id: collectionId,
|
|
3876
|
+
url,
|
|
3877
|
+
name: name || collectionId
|
|
3878
|
+
}));
|
|
3879
|
+
if (isEqual(newCollections, collectionsRef.current)) {
|
|
3880
|
+
return collectionsRef.current;
|
|
3881
|
+
}
|
|
3882
|
+
collectionsRef.current = newCollections;
|
|
3883
|
+
return newCollections;
|
|
3884
|
+
}, [sourceSelections]);
|
|
3485
3885
|
const {
|
|
3486
|
-
data:
|
|
3886
|
+
data: rawLocationData
|
|
3487
3887
|
} = useGetCollectionLocations(collections, true);
|
|
3888
|
+
// Stabilize locationData to prevent infinite loops caused by new array references
|
|
3889
|
+
const locationDataRef = React.useRef();
|
|
3890
|
+
const locationData = useMemo(() => {
|
|
3891
|
+
if (isEqual(rawLocationData, locationDataRef.current)) {
|
|
3892
|
+
return locationDataRef.current;
|
|
3893
|
+
}
|
|
3894
|
+
locationDataRef.current = rawLocationData;
|
|
3895
|
+
return rawLocationData;
|
|
3896
|
+
}, [rawLocationData]);
|
|
3488
3897
|
/* Make sure the map pin is visible when linking new maps */
|
|
3489
3898
|
useEffect(() => {
|
|
3490
3899
|
const toggleMapPinVisibility = displayMapPin => {
|
|
@@ -3502,25 +3911,26 @@ const SoundingsConnect = ({
|
|
|
3502
3911
|
};
|
|
3503
3912
|
}, [dispatch, selectedMapIds]);
|
|
3504
3913
|
// construct and send geojson to map for drawing locations
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3914
|
+
const geoJsonForMap = useMemo(() => ({
|
|
3915
|
+
type: 'FeatureCollection',
|
|
3916
|
+
features: (locationData || []).flatMap(({
|
|
3917
|
+
id: serviceId,
|
|
3918
|
+
features
|
|
3919
|
+
}) => features.map(feature => ({
|
|
3920
|
+
type: 'Feature',
|
|
3921
|
+
geometry: feature.geometry,
|
|
3922
|
+
id: feature.id,
|
|
3923
|
+
properties: {
|
|
3924
|
+
name: feature.properties.name,
|
|
3925
|
+
mapFeatureClass: MapFeatureClass.ObservationStation,
|
|
3926
|
+
highlightSelectedFeature: selectedFeature?.id === feature.id,
|
|
3514
3927
|
id: feature.id,
|
|
3515
|
-
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
}
|
|
3522
|
-
})))
|
|
3523
|
-
};
|
|
3928
|
+
serviceId,
|
|
3929
|
+
hidden: shouldHideLocationMarkers
|
|
3930
|
+
}
|
|
3931
|
+
})))
|
|
3932
|
+
}), [locationData, selectedFeature?.id, shouldHideLocationMarkers]);
|
|
3933
|
+
useEffect(() => {
|
|
3524
3934
|
dispatch(genericActions.addSharedData({
|
|
3525
3935
|
panelId: viewId,
|
|
3526
3936
|
data: {
|
|
@@ -3530,7 +3940,7 @@ const SoundingsConnect = ({
|
|
|
3530
3940
|
}]
|
|
3531
3941
|
}
|
|
3532
3942
|
}));
|
|
3533
|
-
}, [dispatch, geojsonLayerId,
|
|
3943
|
+
}, [dispatch, geojsonLayerId, geoJsonForMap, viewId]);
|
|
3534
3944
|
useEffect(() => () => {
|
|
3535
3945
|
if (viewId) {
|
|
3536
3946
|
dispatch(syncGroupsActions.deleteSharedData({
|
|
@@ -3541,35 +3951,143 @@ const SoundingsConnect = ({
|
|
|
3541
3951
|
// Map location selection has changed. Update soundings location
|
|
3542
3952
|
// since the location menu may be out of sync
|
|
3543
3953
|
useEffect(() => {
|
|
3954
|
+
if (presetJustLoadedRef.current) {
|
|
3955
|
+
return;
|
|
3956
|
+
}
|
|
3544
3957
|
const serviceId = selectedFeature?.serviceId;
|
|
3545
|
-
|
|
3546
|
-
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3958
|
+
const featureId = selectedFeature?.id;
|
|
3959
|
+
if (serviceId && featureId) {
|
|
3960
|
+
const currentLocation = locationSelectionsRef.current[serviceId];
|
|
3961
|
+
const initialLocation = initialLocationsRef.current[serviceId];
|
|
3962
|
+
if (currentLocation !== featureId && initialLocation !== featureId) {
|
|
3963
|
+
dispatch(soundingsActions.updateSelectedLocation({
|
|
3964
|
+
sourceId: serviceId,
|
|
3965
|
+
location: featureId,
|
|
3966
|
+
panelId: viewId,
|
|
3967
|
+
origin: SoundingsActionOrigin.soundingsComponent
|
|
3968
|
+
}));
|
|
3969
|
+
}
|
|
3550
3970
|
}
|
|
3551
|
-
}, [dispatch, selectedFeature?.id, selectedFeature?.serviceId]);
|
|
3552
|
-
//
|
|
3971
|
+
}, [dispatch, selectedFeature?.id, selectedFeature?.serviceId, viewId]);
|
|
3972
|
+
// Use ref to avoid circular dependency when reading locationSelections
|
|
3973
|
+
const locationSelectionsRef = React.useRef(locationSelections);
|
|
3974
|
+
React.useEffect(() => {
|
|
3975
|
+
locationSelectionsRef.current = locationSelections;
|
|
3976
|
+
}, [locationSelections]);
|
|
3977
|
+
// Makes position requests for all user-selected sources for the current map pin position.
|
|
3978
|
+
// Map pin change on its own implies a new position selection.
|
|
3553
3979
|
useEffect(() => {
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
if (
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3980
|
+
if (presetJustLoadedRef.current) {
|
|
3981
|
+
return;
|
|
3982
|
+
}
|
|
3983
|
+
if (!selectedFeature?.id && !selectedMapPin?.id && selectedMapPin?.lon && selectedMapPin.lat) {
|
|
3984
|
+
const newLocation = [selectedMapPin.lon, selectedMapPin.lat];
|
|
3985
|
+
// Update location for all selected sources
|
|
3986
|
+
sourceSelections.forEach(source => {
|
|
3987
|
+
if (source?.collectionId) {
|
|
3988
|
+
const currentLocation = locationSelectionsRef.current[source.collectionId];
|
|
3989
|
+
const isSameLocation = Array.isArray(currentLocation) && currentLocation[0] === newLocation[0] && currentLocation[1] === newLocation[1];
|
|
3990
|
+
if (!isSameLocation) {
|
|
3991
|
+
dispatch(soundingsActions.updateSelectedLocation({
|
|
3992
|
+
sourceId: source.collectionId,
|
|
3993
|
+
location: newLocation,
|
|
3994
|
+
panelId: viewId,
|
|
3995
|
+
origin: SoundingsActionOrigin.soundingsComponent
|
|
3996
|
+
}));
|
|
3997
|
+
}
|
|
3998
|
+
}
|
|
3999
|
+
});
|
|
3562
4000
|
}
|
|
3563
|
-
}, [selectedMapPin, selectedFeature?.id, sourceSelections, dispatch]);
|
|
4001
|
+
}, [selectedMapPin, selectedFeature?.id, sourceSelections, dispatch, viewId]);
|
|
4002
|
+
useEffect(() => {
|
|
4003
|
+
if (!locationData || locationData.length === 0) {
|
|
4004
|
+
return;
|
|
4005
|
+
}
|
|
4006
|
+
if (selectedMapIds.length === 0) {
|
|
4007
|
+
return;
|
|
4008
|
+
}
|
|
4009
|
+
let changedSourceId;
|
|
4010
|
+
for (const source of sourceSelections) {
|
|
4011
|
+
if (source?.collectionId) {
|
|
4012
|
+
const currentLocation = locationSelections[source.collectionId];
|
|
4013
|
+
const previousLocation = previousLocationsRef.current[source.collectionId];
|
|
4014
|
+
if (currentLocation !== previousLocation) {
|
|
4015
|
+
changedSourceId = source.collectionId;
|
|
4016
|
+
if (!presetJustLoadedRef.current) {
|
|
4017
|
+
break;
|
|
4018
|
+
}
|
|
4019
|
+
}
|
|
4020
|
+
}
|
|
4021
|
+
}
|
|
4022
|
+
if (!changedSourceId) {
|
|
4023
|
+
return;
|
|
4024
|
+
}
|
|
4025
|
+
const selectedLocation = locationSelections[changedSourceId];
|
|
4026
|
+
if (!selectedLocation) {
|
|
4027
|
+
return;
|
|
4028
|
+
}
|
|
4029
|
+
previousLocationsRef.current = {
|
|
4030
|
+
...previousLocationsRef.current,
|
|
4031
|
+
[changedSourceId]: selectedLocation
|
|
4032
|
+
};
|
|
4033
|
+
const serviceData = locationData.find(service => service.id === changedSourceId);
|
|
4034
|
+
if (!serviceData) {
|
|
4035
|
+
return;
|
|
4036
|
+
}
|
|
4037
|
+
if (typeof selectedLocation === 'string') {
|
|
4038
|
+
const foundFeature = serviceData.features.find(feature => feature.id === selectedLocation);
|
|
4039
|
+
if (foundFeature?.geometry.type === 'Point') {
|
|
4040
|
+
const [lon, lat] = foundFeature.geometry.coordinates;
|
|
4041
|
+
const mapPinNeedsUpdate = selectedMapPin?.id !== selectedLocation || selectedMapPin?.lon !== lon || selectedMapPin?.lat !== lat;
|
|
4042
|
+
const featureNeedsUpdate = selectedFeature?.id !== selectedLocation;
|
|
4043
|
+
if (mapPinNeedsUpdate) {
|
|
4044
|
+
selectedMapIds.forEach(mapId => {
|
|
4045
|
+
dispatch(mapActions.setMapPinLocation({
|
|
4046
|
+
mapId,
|
|
4047
|
+
mapPinLocation: {
|
|
4048
|
+
lon,
|
|
4049
|
+
lat,
|
|
4050
|
+
id: selectedLocation
|
|
4051
|
+
}
|
|
4052
|
+
}));
|
|
4053
|
+
});
|
|
4054
|
+
}
|
|
4055
|
+
if (featureNeedsUpdate) {
|
|
4056
|
+
dispatch(genericActions.addSharedData({
|
|
4057
|
+
panelId: viewId,
|
|
4058
|
+
data: {
|
|
4059
|
+
selectedFeatureId: selectedLocation
|
|
4060
|
+
}
|
|
4061
|
+
}));
|
|
4062
|
+
}
|
|
4063
|
+
}
|
|
4064
|
+
} else if (Array.isArray(selectedLocation)) {
|
|
4065
|
+
const [lon, lat] = selectedLocation;
|
|
4066
|
+
const needsUpdate = selectedMapPin?.lon !== lon || selectedMapPin?.lat !== lat;
|
|
4067
|
+
if (needsUpdate) {
|
|
4068
|
+
selectedMapIds.forEach(mapId => {
|
|
4069
|
+
dispatch(mapActions.setMapPinLocation({
|
|
4070
|
+
mapId,
|
|
4071
|
+
mapPinLocation: {
|
|
4072
|
+
lon,
|
|
4073
|
+
lat
|
|
4074
|
+
}
|
|
4075
|
+
}));
|
|
4076
|
+
});
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4079
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4080
|
+
}, [locationData, locationSelections, sourceSelections, selectedMapIds, dispatch, viewId]);
|
|
3564
4081
|
const {
|
|
3565
4082
|
error,
|
|
3566
4083
|
data,
|
|
3567
4084
|
isPending
|
|
3568
4085
|
} = useMultipleSources(sourceSelections, locationSelections, selectedTime);
|
|
3569
|
-
const soundingPanelsInOrder = useSelector(store => getSoundingPanelsInOrder(store));
|
|
4086
|
+
const soundingPanelsInOrder = useSelector(store => getSoundingPanelsInOrder(store, viewId));
|
|
3570
4087
|
const changeOrder = newOrder => {
|
|
3571
4088
|
const orderedIds = newOrder.map(collection => collection.id);
|
|
3572
4089
|
dispatch(soundingsActions.changeSoundingPanelOrder({
|
|
4090
|
+
panelId: viewId,
|
|
3573
4091
|
newOrderOfIds: orderedIds
|
|
3574
4092
|
}));
|
|
3575
4093
|
};
|
|
@@ -3627,7 +4145,7 @@ const SoundingsConnect = ({
|
|
|
3627
4145
|
},
|
|
3628
4146
|
children: jsx(SharedMouseYProvider, {
|
|
3629
4147
|
children: jsx(SortableAccordions, {
|
|
3630
|
-
chosenDiagramType:
|
|
4148
|
+
chosenDiagramType: diagramType,
|
|
3631
4149
|
data: data,
|
|
3632
4150
|
onOrderChange: changeOrder,
|
|
3633
4151
|
setChosenDiagramType: setChosenDiagramType,
|
|
@@ -3642,7 +4160,9 @@ const SoundingsConnect = ({
|
|
|
3642
4160
|
flex: '0 0 auto',
|
|
3643
4161
|
height: `${TIMESLIDER_HEIGHT}px`
|
|
3644
4162
|
},
|
|
3645
|
-
children: jsx(SoundingsTimeSliderConnect, {
|
|
4163
|
+
children: jsx(SoundingsTimeSliderConnect, {
|
|
4164
|
+
viewId: viewId
|
|
4165
|
+
})
|
|
3646
4166
|
})]
|
|
3647
4167
|
})
|
|
3648
4168
|
})]
|
|
@@ -3718,6 +4238,7 @@ const SoundingsSourceMenu = ({
|
|
|
3718
4238
|
instanceId,
|
|
3719
4239
|
url
|
|
3720
4240
|
} = sourceSelections[collection.id] || {};
|
|
4241
|
+
const sourceUrl = url || collection.url;
|
|
3721
4242
|
const hasInstances = collection.instances.length > 0;
|
|
3722
4243
|
const selectedInstanceId = instanceId || collection.instances[0]?.id || undefined;
|
|
3723
4244
|
return jsxs(ListItem, {
|
|
@@ -3732,7 +4253,7 @@ const SoundingsSourceMenu = ({
|
|
|
3732
4253
|
onChange: event => {
|
|
3733
4254
|
const verticalRange = selectedInstanceId !== undefined ? extractVerticalRange(collection, selectedInstanceId) : '';
|
|
3734
4255
|
updateCollection(collection.id, {
|
|
3735
|
-
url,
|
|
4256
|
+
url: sourceUrl,
|
|
3736
4257
|
isChecked: event.target.checked,
|
|
3737
4258
|
instanceId: selectedInstanceId,
|
|
3738
4259
|
verticalRange
|
|
@@ -3748,7 +4269,7 @@ const SoundingsSourceMenu = ({
|
|
|
3748
4269
|
const instanceId = event.target.value;
|
|
3749
4270
|
const verticalRange = extractVerticalRange(collection, instanceId);
|
|
3750
4271
|
updateCollection(collection.id, {
|
|
3751
|
-
url,
|
|
4272
|
+
url: sourceUrl,
|
|
3752
4273
|
instanceId,
|
|
3753
4274
|
verticalRange
|
|
3754
4275
|
});
|
|
@@ -3811,35 +4332,52 @@ const SoundingsSourceDialogConnect = ({
|
|
|
3811
4332
|
dialogOrder,
|
|
3812
4333
|
setDialogOrder
|
|
3813
4334
|
} = useSetupDialog(uiTypes.DialogTypes.SoundingsSources);
|
|
4335
|
+
const panelId = useSelector(store => uiSelectors.getDialogMapId(store, uiTypes.DialogTypes.SoundingsSources));
|
|
3814
4336
|
const updateCollection = React.useCallback((sourceId, value) => {
|
|
3815
4337
|
dispatch(soundingsActions.updateSelectedSource({
|
|
3816
4338
|
sourceId,
|
|
3817
|
-
value
|
|
4339
|
+
value,
|
|
4340
|
+
panelId,
|
|
4341
|
+
origin: SoundingsActionOrigin.soundingsComponent
|
|
3818
4342
|
}));
|
|
3819
|
-
}, [dispatch]);
|
|
3820
|
-
const
|
|
4343
|
+
}, [dispatch, panelId]);
|
|
4344
|
+
const soundingsCollectionsFromStore = useSelector(state => getSoundingsCollections(state));
|
|
4345
|
+
const collections = soundingsCollections ?? soundingsCollectionsFromStore;
|
|
4346
|
+
const sourceSelections = useSelector(state => getSourceSelections(state, panelId));
|
|
3821
4347
|
// Set mappings for each collection
|
|
3822
4348
|
React.useEffect(() => {
|
|
3823
|
-
soundingsCollections
|
|
4349
|
+
if (soundingsCollections && soundingsCollections.length > 0) {
|
|
4350
|
+
dispatch(soundingsActions.setSoundingsCollections(soundingsCollections));
|
|
4351
|
+
}
|
|
4352
|
+
}, [dispatch, soundingsCollections]);
|
|
4353
|
+
React.useEffect(() => {
|
|
4354
|
+
collections?.forEach(collection => {
|
|
4355
|
+
const currentSelection = sourceSelections[collection.id];
|
|
4356
|
+
if (currentSelection?.url && currentSelection?.parameterMappings) {
|
|
4357
|
+
return;
|
|
4358
|
+
}
|
|
4359
|
+
const newValue = {
|
|
4360
|
+
url: collection.url,
|
|
4361
|
+
isChecked: currentSelection?.isChecked || false,
|
|
4362
|
+
parameterMappings: collection.parameterMappings,
|
|
4363
|
+
...(collection.name && collection.name !== '' ? {
|
|
4364
|
+
name: collection.name
|
|
4365
|
+
} : {})
|
|
4366
|
+
};
|
|
3824
4367
|
dispatch(soundingsActions.updateSelectedSource({
|
|
3825
4368
|
sourceId: collection.id,
|
|
3826
|
-
value:
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
parameterMappings: collection.parameterMappings,
|
|
3830
|
-
...(collection.name && collection.name !== '' ? {
|
|
3831
|
-
name: collection.name
|
|
3832
|
-
} : {})
|
|
3833
|
-
}
|
|
4369
|
+
value: newValue,
|
|
4370
|
+
panelId,
|
|
4371
|
+
origin: SoundingsActionOrigin.soundingsManager
|
|
3834
4372
|
}));
|
|
3835
4373
|
});
|
|
3836
4374
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3837
|
-
}, [dispatch,
|
|
4375
|
+
}, [dispatch, collections, panelId]);
|
|
3838
4376
|
const {
|
|
3839
4377
|
data,
|
|
3840
4378
|
isPending,
|
|
3841
4379
|
error
|
|
3842
|
-
} = useGetCollectionsInstances(
|
|
4380
|
+
} = useGetCollectionsInstances(collections, isDialogOpen);
|
|
3843
4381
|
return jsx(SoundingsSourceMenu, {
|
|
3844
4382
|
error: error,
|
|
3845
4383
|
handleClose: onCloseDialog,
|
|
@@ -3853,6 +4391,44 @@ const SoundingsSourceDialogConnect = ({
|
|
|
3853
4391
|
});
|
|
3854
4392
|
};
|
|
3855
4393
|
|
|
4394
|
+
const RowComponent = ({
|
|
4395
|
+
index,
|
|
4396
|
+
style,
|
|
4397
|
+
service,
|
|
4398
|
+
isChecked,
|
|
4399
|
+
updateSelectedLocation
|
|
4400
|
+
}) => {
|
|
4401
|
+
const location = service.features[index];
|
|
4402
|
+
return jsx("div", {
|
|
4403
|
+
style: style,
|
|
4404
|
+
children: jsx(ListItem, {
|
|
4405
|
+
disableGutters: true,
|
|
4406
|
+
disablePadding: true,
|
|
4407
|
+
children: jsxs(ListItemButton, {
|
|
4408
|
+
dense: true,
|
|
4409
|
+
onClick: () => {
|
|
4410
|
+
updateSelectedLocation(service.id, isChecked(service.id, location.id) ? undefined : location.id);
|
|
4411
|
+
},
|
|
4412
|
+
children: [jsx(ListItemIcon, {
|
|
4413
|
+
children: jsx(Checkbox, {
|
|
4414
|
+
checked: isChecked(service.id, location.id),
|
|
4415
|
+
disableRipple: true,
|
|
4416
|
+
edge: "start",
|
|
4417
|
+
slotProps: {
|
|
4418
|
+
input: {
|
|
4419
|
+
'aria-labelledby': location.id
|
|
4420
|
+
}
|
|
4421
|
+
},
|
|
4422
|
+
tabIndex: -1
|
|
4423
|
+
})
|
|
4424
|
+
}), jsx(ListItemText, {
|
|
4425
|
+
id: location.id,
|
|
4426
|
+
primary: location.properties.name
|
|
4427
|
+
})]
|
|
4428
|
+
})
|
|
4429
|
+
})
|
|
4430
|
+
}, `${service.id}-${location.id}`);
|
|
4431
|
+
};
|
|
3856
4432
|
const LocationsMenu = ({
|
|
3857
4433
|
services,
|
|
3858
4434
|
selectedSourcesAmount,
|
|
@@ -3944,45 +4520,18 @@ const LocationsMenu = ({
|
|
|
3944
4520
|
}
|
|
3945
4521
|
},
|
|
3946
4522
|
title: service.name,
|
|
3947
|
-
children: jsx(
|
|
3948
|
-
|
|
3949
|
-
|
|
3950
|
-
|
|
3951
|
-
|
|
3952
|
-
|
|
3953
|
-
|
|
3954
|
-
|
|
3955
|
-
}
|
|
3956
|
-
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
children: jsx(ListItem, {
|
|
3960
|
-
disableGutters: true,
|
|
3961
|
-
disablePadding: true,
|
|
3962
|
-
children: jsxs(ListItemButton, {
|
|
3963
|
-
dense: true,
|
|
3964
|
-
onClick: () => {
|
|
3965
|
-
updateSelectedLocation(service.id, isChecked(service.id, location.id) ? undefined : location.id);
|
|
3966
|
-
},
|
|
3967
|
-
children: [jsx(ListItemIcon, {
|
|
3968
|
-
children: jsx(Checkbox, {
|
|
3969
|
-
checked: isChecked(service.id, location.id),
|
|
3970
|
-
disableRipple: true,
|
|
3971
|
-
edge: "start",
|
|
3972
|
-
slotProps: {
|
|
3973
|
-
input: {
|
|
3974
|
-
'aria-labelledby': location.id
|
|
3975
|
-
}
|
|
3976
|
-
},
|
|
3977
|
-
tabIndex: -1
|
|
3978
|
-
})
|
|
3979
|
-
}), jsx(ListItemText, {
|
|
3980
|
-
id: location.id,
|
|
3981
|
-
primary: location.properties.name
|
|
3982
|
-
})]
|
|
3983
|
-
})
|
|
3984
|
-
})
|
|
3985
|
-
}, `${service.id}-${location.id}`);
|
|
4523
|
+
children: jsx(List$1, {
|
|
4524
|
+
rowComponent: RowComponent,
|
|
4525
|
+
rowCount: service.features.length,
|
|
4526
|
+
rowHeight: 40,
|
|
4527
|
+
rowProps: {
|
|
4528
|
+
service,
|
|
4529
|
+
isChecked,
|
|
4530
|
+
updateSelectedLocation
|
|
4531
|
+
},
|
|
4532
|
+
style: {
|
|
4533
|
+
height: 320,
|
|
4534
|
+
width: '100%'
|
|
3986
4535
|
}
|
|
3987
4536
|
})
|
|
3988
4537
|
})
|
|
@@ -4001,35 +4550,25 @@ const LocationsMenuConnect = ({
|
|
|
4001
4550
|
dialogOrder,
|
|
4002
4551
|
setDialogOrder
|
|
4003
4552
|
} = useSetupDialog(uiTypes.DialogTypes.SoundingsLocations);
|
|
4004
|
-
const locationSelections = useSelector(getLocationSelections);
|
|
4005
|
-
const selectedSourceIds = useSelector(getSelectedSourcesIds);
|
|
4006
|
-
const sourcesAmount = useSelector(getSelectedSourcesAmount);
|
|
4007
4553
|
const panelId = useSelector(store => uiSelectors.getDialogMapId(store, uiTypes.DialogTypes.SoundingsLocations));
|
|
4008
|
-
const
|
|
4554
|
+
const locationSelections = useSelector(state => getLocationSelections(state, panelId));
|
|
4555
|
+
const selectedSourceIds = useSelector(state => getSelectedSourcesIds(state, panelId));
|
|
4556
|
+
const sourcesAmount = useSelector(state => getSelectedSourcesAmount(state, panelId));
|
|
4557
|
+
const soundingsCollectionsFromStore = useSelector(state => getSoundingsCollections(state));
|
|
4558
|
+
const collections = soundingsCollections ?? soundingsCollectionsFromStore;
|
|
4559
|
+
React.useEffect(() => {
|
|
4560
|
+
if (soundingsCollections && soundingsCollections.length > 0) {
|
|
4561
|
+
dispatch(soundingsActions.setSoundingsCollections(soundingsCollections));
|
|
4562
|
+
}
|
|
4563
|
+
}, [dispatch, soundingsCollections]);
|
|
4009
4564
|
const {
|
|
4010
4565
|
data,
|
|
4011
4566
|
isPending,
|
|
4012
4567
|
error
|
|
4013
|
-
} = useGetCollectionLocations(
|
|
4568
|
+
} = useGetCollectionLocations(collections, isDialogOpen);
|
|
4014
4569
|
const services = useMemo(() => {
|
|
4015
4570
|
return data?.filter(service => selectedSourceIds.includes(service.id)) || [];
|
|
4016
4571
|
}, [data, selectedSourceIds]);
|
|
4017
|
-
const handleFeatureSelect = (panelId, featureId) => {
|
|
4018
|
-
dispatch(genericActions.addSharedData({
|
|
4019
|
-
panelId,
|
|
4020
|
-
data: {
|
|
4021
|
-
selectedFeatureId: featureId
|
|
4022
|
-
}
|
|
4023
|
-
}));
|
|
4024
|
-
};
|
|
4025
|
-
const setMapPinLocation = mapPinLocation => {
|
|
4026
|
-
selectedMapIds.forEach(mapId => {
|
|
4027
|
-
dispatch(mapActions.setMapPinLocation({
|
|
4028
|
-
mapId,
|
|
4029
|
-
mapPinLocation
|
|
4030
|
-
}));
|
|
4031
|
-
});
|
|
4032
|
-
};
|
|
4033
4572
|
return jsx(LocationsMenu, {
|
|
4034
4573
|
error: error,
|
|
4035
4574
|
isLoading: isPending,
|
|
@@ -4043,27 +4582,9 @@ const LocationsMenuConnect = ({
|
|
|
4043
4582
|
updateSelectedLocation: (sourceId, locationId) => {
|
|
4044
4583
|
dispatch(soundingsActions.updateSelectedLocation({
|
|
4045
4584
|
sourceId,
|
|
4046
|
-
location: locationId
|
|
4585
|
+
location: locationId,
|
|
4586
|
+
panelId
|
|
4047
4587
|
}));
|
|
4048
|
-
// Use first source. Multiple sources will be implemented later.
|
|
4049
|
-
// https://gitlab.com/opengeoweb/geoweb-assets/-/issues/4254
|
|
4050
|
-
const isFirstSource = sourceId === selectedSourceIds[0];
|
|
4051
|
-
if (!isFirstSource) {
|
|
4052
|
-
return;
|
|
4053
|
-
}
|
|
4054
|
-
if (locationId) {
|
|
4055
|
-
handleFeatureSelect(panelId, locationId);
|
|
4056
|
-
}
|
|
4057
|
-
const foundFeature = services[0].features.find(feature => feature.id === locationId);
|
|
4058
|
-
// check type for typescript
|
|
4059
|
-
if (foundFeature?.geometry.type === 'Point') {
|
|
4060
|
-
const [lon, lat] = foundFeature.geometry.coordinates;
|
|
4061
|
-
setMapPinLocation({
|
|
4062
|
-
lon,
|
|
4063
|
-
lat,
|
|
4064
|
-
id: locationId
|
|
4065
|
-
});
|
|
4066
|
-
}
|
|
4067
4588
|
}
|
|
4068
4589
|
});
|
|
4069
4590
|
};
|
|
@@ -4091,8 +4612,10 @@ var preset = {
|
|
|
4091
4612
|
};
|
|
4092
4613
|
|
|
4093
4614
|
const SoundingManagerListItem = ({
|
|
4615
|
+
id,
|
|
4094
4616
|
name,
|
|
4095
|
-
isDisplayed
|
|
4617
|
+
isDisplayed,
|
|
4618
|
+
onToggleVisibility
|
|
4096
4619
|
}) => {
|
|
4097
4620
|
return jsx(Card, {
|
|
4098
4621
|
className: "sortable-item",
|
|
@@ -4126,7 +4649,16 @@ const SoundingManagerListItem = ({
|
|
|
4126
4649
|
display: 'flex',
|
|
4127
4650
|
alignItems: 'center'
|
|
4128
4651
|
},
|
|
4129
|
-
children:
|
|
4652
|
+
children: jsx(IconButton, {
|
|
4653
|
+
"aria-label": "toggle-visibility",
|
|
4654
|
+
onClick: () => onToggleVisibility(id),
|
|
4655
|
+
size: "small",
|
|
4656
|
+
sx: {
|
|
4657
|
+
width: '24px',
|
|
4658
|
+
height: '24px'
|
|
4659
|
+
},
|
|
4660
|
+
children: isDisplayed ? jsx(Visibility, {}) : jsx(VisibilityOff, {})
|
|
4661
|
+
})
|
|
4130
4662
|
}), jsxs(Box, {
|
|
4131
4663
|
sx: {
|
|
4132
4664
|
paddingRight: '8px',
|
|
@@ -4144,7 +4676,8 @@ const SoundingsManager = ({
|
|
|
4144
4676
|
onMouseDown,
|
|
4145
4677
|
order,
|
|
4146
4678
|
soundingPanelsInOrder,
|
|
4147
|
-
onOrderChange
|
|
4679
|
+
onOrderChange,
|
|
4680
|
+
onToggleVisibility
|
|
4148
4681
|
}) => {
|
|
4149
4682
|
const sortableList = React.useMemo(() => soundingPanelsInOrder.map(collection => ({
|
|
4150
4683
|
...collection
|
|
@@ -4172,8 +4705,10 @@ const SoundingsManager = ({
|
|
|
4172
4705
|
name,
|
|
4173
4706
|
isDisplayed
|
|
4174
4707
|
}) => jsx(SoundingManagerListItem, {
|
|
4708
|
+
id: id,
|
|
4175
4709
|
isDisplayed: isDisplayed,
|
|
4176
|
-
name: name
|
|
4710
|
+
name: name,
|
|
4711
|
+
onToggleVisibility: onToggleVisibility
|
|
4177
4712
|
}, id))
|
|
4178
4713
|
})
|
|
4179
4714
|
});
|
|
@@ -4187,22 +4722,33 @@ const SoundingsManagerConnect = () => {
|
|
|
4187
4722
|
setDialogOrder
|
|
4188
4723
|
} = useSetupDialog(uiTypes.DialogTypes.SoundingsManager);
|
|
4189
4724
|
const dispatch = useDispatch();
|
|
4725
|
+
const panelId = useSelector(store => uiSelectors.getDialogMapId(store, uiTypes.DialogTypes.SoundingsManager));
|
|
4190
4726
|
React.useEffect(() => {
|
|
4191
4727
|
const data = preset.SoundingManagerDummyPreset;
|
|
4192
|
-
dispatch(soundingsActions.addSoundingPanelsFromPreset(
|
|
4193
|
-
|
|
4194
|
-
|
|
4728
|
+
dispatch(soundingsActions.addSoundingPanelsFromPreset({
|
|
4729
|
+
panelId,
|
|
4730
|
+
panels: data
|
|
4731
|
+
}));
|
|
4732
|
+
}, [dispatch, panelId]);
|
|
4733
|
+
const soundingPanelsInOrder = useSelector(store => getSoundingPanelsInOrder(store, panelId));
|
|
4195
4734
|
const changeOrder = newOrder => {
|
|
4196
4735
|
const orderedIds = newOrder.map(collection => collection.id);
|
|
4197
4736
|
dispatch(soundingsActions.changeSoundingPanelOrder({
|
|
4737
|
+
panelId,
|
|
4198
4738
|
newOrderOfIds: orderedIds
|
|
4199
4739
|
}));
|
|
4200
4740
|
};
|
|
4741
|
+
const toggleVisibility = id => {
|
|
4742
|
+
dispatch(soundingsActions.toggleSoundingPanelVisibility({
|
|
4743
|
+
id
|
|
4744
|
+
}));
|
|
4745
|
+
};
|
|
4201
4746
|
return jsx(SoundingsManager, {
|
|
4202
4747
|
isOpen: isDialogOpen,
|
|
4203
4748
|
onClose: onCloseDialog,
|
|
4204
4749
|
onMouseDown: setDialogOrder,
|
|
4205
4750
|
onOrderChange: changeOrder,
|
|
4751
|
+
onToggleVisibility: toggleVisibility,
|
|
4206
4752
|
order: dialogOrder,
|
|
4207
4753
|
soundingPanelsInOrder: soundingPanelsInOrder
|
|
4208
4754
|
});
|
|
@@ -4211,7 +4757,7 @@ const SoundingsManagerConnect = () => {
|
|
|
4211
4757
|
const soundingsLookUp = payload => {
|
|
4212
4758
|
if (payload.componentType === 'Soundings') {
|
|
4213
4759
|
return jsx(SoundingsConnect, {
|
|
4214
|
-
|
|
4760
|
+
soundingsPreset: payload.initialProps,
|
|
4215
4761
|
viewId: payload.id
|
|
4216
4762
|
});
|
|
4217
4763
|
}
|
|
@@ -4246,4 +4792,4 @@ const createMockStore = mockState => configureStore({
|
|
|
4246
4792
|
middleware: getDefaultMiddleware => getDefaultMiddleware().concat(storeMiddlewares)
|
|
4247
4793
|
});
|
|
4248
4794
|
|
|
4249
|
-
export { LocationsMenuConnect, SOUNDINGS_NAMESPACE, SoundingsConnect, SoundingsManagerConnect, SoundingsSourceDialogConnect, createMockStore, initSoundingsI18n, soundingDiagrams, soundingsLookUp, soundingsReducersMap, soundingsTranslations, translateInTestsAndStories, useSoundingsTranslation };
|
|
4795
|
+
export { LocationsMenuConnect, SOUNDINGS_NAMESPACE, SoundingsActionOrigin, SoundingsConnect, SoundingsManagerConnect, SoundingsSourceDialogConnect, types as SoundingsTypes, createMockStore, initSoundingsI18n, soundingDiagrams, soundingsActions, soundingsLookUp, soundingsReducer, soundingsReducersMap, selectors as soundingsSelectors, soundingsTranslations, translateInTestsAndStories, useSoundingsTranslation };
|