@opengeoweb/soundings 12.10.0 → 12.11.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import React, { useRef, useEffect, useMemo, useState, Fragment as Fragment$1 } from 'react';
3
3
  import { useSelector, useDispatch } from 'react-redux';
4
- import { Box, Stack, Menu, ListSubheader, Typography, MenuItem, LinearProgress, Card, List, ListItem, ListItemIcon, Checkbox, ListItemText, Grid, ListItemButton } from '@mui/material';
4
+ import { Box, Stack, Menu, ListSubheader, Typography, MenuItem, Tooltip, LinearProgress, Card, List, ListItem, ListItemIcon, Checkbox, ListItemText, Grid, ListItemButton } from '@mui/material';
5
5
  import { safelyInitI18nForTestsAndStories, sharedTranslations, SHARED_NAMESPACE, dateUtils, CustomSlider, CustomToggleButton, AlertBanner, ToolContainerDraggable, StyledSelect, SearchField, CustomAccordion } from '@opengeoweb/shared';
6
6
  import * as d3 from 'd3';
7
7
  import { useQueries } from '@tanstack/react-query';
@@ -244,7 +244,7 @@ const drawIsobars = ({
244
244
  * Copyright 2025 - Finnish Meteorological Institute (FMI)
245
245
  * Copyright 2025 - The Norwegian Meteorological Institute (MET Norway)
246
246
  * */
247
- const SOUNDING_COLORS = ['#4487f3', '#c3213c', '#509a00'];
247
+ const SOUNDING_COLORS = ['#4487f3', '#c3213c', '#509a00', '#ED6C06'];
248
248
  const getDiagramName = (t, diagramType) => {
249
249
  switch (diagramType) {
250
250
  case 'BIJVOET':
@@ -316,15 +316,6 @@ const drawAxes = ({
316
316
  const formatTicks = d3.format('.0f');
317
317
  svg.append('g').attr('type', 'y-axis').call(d3.axisLeft(yScale).tickValues(isobarValues).tickFormat(formatTicks).tickSizeInner(0).tickSizeOuter(0)).call(gee => gee.select('.domain').remove()).append('text').attr('fill', 'currentColor').attr('x', '0').attr('y', yScale(400)).attr('font-size', '11px').attr('dy', '-0.9em').attr('text-anchor', 'left').text('hPa');
318
318
  };
319
- const addLegends = ({
320
- svg,
321
- width
322
- }) => {
323
- // Add a legend for the temperature line
324
- svg.append('text').attr('x', width - 160).attr('y', 20).attr('fill', SOUNDING_COLORS[0]).text('Temperature (°C)');
325
- // Add a legend for the dewpoint line
326
- svg.append('text').attr('x', width - 137).attr('y', 40).attr('fill', SOUNDING_COLORS[0]).text('Dewpoint (°C)');
327
- };
328
319
  const mapToPlot = (diagramType, filteredPressureValues, filteredTemperatureValues, xScale, yScale, height) => {
329
320
  if (diagramType === 'BIJVOET') {
330
321
  const thetaValues = filteredTemperatureValues.map((tempValue, index) => calculateThetaFromPressTemp(pressToPascal(filteredPressureValues[index]), tempToKelvin(tempValue)));
@@ -1487,11 +1478,6 @@ const Soundings = ({
1487
1478
  maxPressure,
1488
1479
  svg
1489
1480
  });
1490
- // Add legends
1491
- addLegends({
1492
- svg,
1493
- width
1494
- });
1495
1481
  data.forEach((features, index) => {
1496
1482
  const color = SOUNDING_COLORS[index] || SOUNDING_COLORS[0];
1497
1483
  const temperatureValues = features.map(feature => feature.properties.temp);
@@ -2373,7 +2359,8 @@ const getSelectedSources = createSelector(getSoundingsStore, store => {
2373
2359
  url: value.url,
2374
2360
  instanceId: value.instanceId,
2375
2361
  verticalRange: value.verticalRange,
2376
- parameterMappings: value.parameterMappings
2362
+ parameterMappings: value.parameterMappings,
2363
+ name: value.name || ''
2377
2364
  });
2378
2365
  }
2379
2366
  return list;
@@ -2582,6 +2569,74 @@ const DiagramTypeButton = ({
2582
2569
  });
2583
2570
  };
2584
2571
 
2572
+ /* *
2573
+ * Licensed under the Apache License, Version 2.0 (the "License");
2574
+ * you may not use this file except in compliance with the License.
2575
+ * You may obtain a copy of the License at
2576
+ *
2577
+ * http://www.apache.org/licenses/LICENSE-2.0
2578
+ *
2579
+ * Unless required by applicable law or agreed to in writing, software
2580
+ * distributed under the License is distributed on an "AS IS" BASIS,
2581
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2582
+ * See the License for the specific language governing permissions and
2583
+ * limitations under the License.
2584
+ *
2585
+ * Copyright 2025 - Koninklijk Nederlands Meteorologisch Instituut (KNMI)
2586
+ * Copyright 2025 - Finnish Meteorological Institute (FMI)
2587
+ * Copyright 2025 - The Norwegian Meteorological Institute (MET Norway)
2588
+ * */
2589
+ const getDisplayValue = (instanceId, stringFormat = 'ISO') => {
2590
+ const instanceAsDate = dateUtils.isoStringToDate(instanceId);
2591
+ if (instanceAsDate) {
2592
+ return stringFormat === 'ISO' ? dateUtils.dateToIsoString(instanceAsDate) : dateUtils.dateToString(instanceAsDate, stringFormat, true);
2593
+ }
2594
+ return instanceId;
2595
+ };
2596
+
2597
+ const getLegendTitle = source => {
2598
+ const displayName = source.name || source.collectionId;
2599
+ const displayInstance = getDisplayValue(source.instanceId || '', "yyyy-MM-dd HH:mm'Z'");
2600
+ return `${displayName} ${displayInstance}`;
2601
+ };
2602
+ const SoundingsLegend = ({
2603
+ sourceSelections
2604
+ }) => {
2605
+ return jsx(Stack, {
2606
+ useFlexGap: true,
2607
+ spacing: 1,
2608
+ direction: "row",
2609
+ justifyContent: "center",
2610
+ sx: {
2611
+ flexWrap: 'wrap',
2612
+ paddingLeft: 2,
2613
+ paddingTop: 0.5
2614
+ },
2615
+ children: sourceSelections.map((source, index) => {
2616
+ const title = getLegendTitle(source);
2617
+ return jsx(Tooltip, {
2618
+ title: title,
2619
+ children: jsxs(Typography, {
2620
+ variant: "caption",
2621
+ sx: {
2622
+ color: 'geowebColors.typographyAndIcons.text',
2623
+ fontSize: '10px'
2624
+ },
2625
+ children: [jsx(Box, {
2626
+ sx: {
2627
+ width: '16px',
2628
+ height: '8px',
2629
+ backgroundColor: SOUNDING_COLORS[index],
2630
+ display: 'inline-block',
2631
+ marginRight: '4px'
2632
+ }
2633
+ }), title]
2634
+ })
2635
+ }, `${source.collectionId}-${source.instanceId}`);
2636
+ })
2637
+ });
2638
+ };
2639
+
2585
2640
  const size = 600;
2586
2641
  const SoundingsConnect = ({
2587
2642
  viewId,
@@ -2619,6 +2674,17 @@ const SoundingsConnect = ({
2619
2674
  })
2620
2675
  }), jsxs(Card, {
2621
2676
  children: [jsx(Box, {
2677
+ sx: {
2678
+ display: 'flex',
2679
+ justifyContent: 'center',
2680
+ paddingTop: '2px',
2681
+ paddingRight: '2px',
2682
+ width: size
2683
+ },
2684
+ children: jsx(SoundingsLegend, {
2685
+ sourceSelections: sourceSelections
2686
+ })
2687
+ }), jsx(Box, {
2622
2688
  sx: {
2623
2689
  display: 'flex',
2624
2690
  justifyContent: 'flex-end',
@@ -2683,10 +2749,6 @@ const SoundingsSourceMenu = ({
2683
2749
  const {
2684
2750
  t
2685
2751
  } = useSoundingsTranslation();
2686
- const getDisplayValue = instanceId => {
2687
- const instanceAsDate = dateUtils.isoStringToDate(instanceId);
2688
- return instanceAsDate ? dateUtils.dateToIsoString(instanceAsDate) : instanceId;
2689
- };
2690
2752
  return jsxs(ToolContainerDraggable, {
2691
2753
  startSize: {
2692
2754
  width: 320
@@ -2829,7 +2891,10 @@ const SoundingsSourceDialogConnect = ({
2829
2891
  value: {
2830
2892
  url: collection.url,
2831
2893
  isChecked: sourceSelections[collection.id]?.isChecked || false,
2832
- parameterMappings: collection.parameterMappings
2894
+ parameterMappings: collection.parameterMappings,
2895
+ ...(collection.name && collection.name !== '' ? {
2896
+ name: collection.name
2897
+ } : {})
2833
2898
  }
2834
2899
  }));
2835
2900
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeoweb/soundings",
3
- "version": "12.10.0",
3
+ "version": "12.11.0",
4
4
  "description": "GeoWeb soundings library for the opengeoweb project",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -8,24 +8,27 @@
8
8
  "url": "git@gitlab.com:opengeoweb/opengeoweb.git"
9
9
  },
10
10
  "dependencies": {
11
- "@opengeoweb/api": "12.10.0",
11
+ "@opengeoweb/api": "12.11.0",
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.10.0",
17
+ "@opengeoweb/shared": "12.11.0",
18
18
  "@mui/material": "^7.0.1",
19
- "@opengeoweb/store": "12.10.0",
19
+ "@opengeoweb/store": "12.11.0",
20
20
  "react-redux": "^9.2.0",
21
- "@opengeoweb/theme": "12.10.0",
21
+ "@opengeoweb/theme": "12.11.0",
22
22
  "@reduxjs/toolkit": "^2.6.1",
23
- "@opengeoweb/timeslider": "12.10.0",
23
+ "@opengeoweb/timeslider": "12.11.0",
24
24
  "react-window": "^1.8.10",
25
- "@opengeoweb/webmap": "12.10.0",
25
+ "@opengeoweb/webmap": "12.11.0",
26
26
  "lodash": "^4.17.21",
27
27
  "@types/geojson": "^7946.0.14"
28
28
  },
29
+ "devDependencies": {
30
+ "eslint-plugin-storybook": "9.0.17"
31
+ },
29
32
  "module": "./index.esm.js",
30
33
  "type": "module",
31
34
  "main": "./index.esm.js",
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import type { StoryObj } from '@storybook/react';
2
+ import type { StoryObj } from '@storybook/react-webpack5';
3
3
  import { MenuOptions } from './MenuBar';
4
4
  interface Props {
5
5
  menu?: MenuOptions;
@@ -9,7 +9,7 @@ interface Props {
9
9
  declare const SoundingsMenuBarStory: ({ menu, isDefaultOpen, selectedSourcesAmount, }: Props) => React.ReactElement;
10
10
  declare const _default: {
11
11
  title: string;
12
- component: ({ menu, isDefaultOpen, selectedSourcesAmount, }: Props) => React.ReactElement<any, string | React.JSXElementConstructor<any>>;
12
+ component: ({ menu, isDefaultOpen, selectedSourcesAmount, }: Props) => React.ReactElement;
13
13
  };
14
14
  export default _default;
15
15
  type Story = StoryObj<typeof SoundingsMenuBarStory>;
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import { Store } from '@reduxjs/toolkit';
3
2
  interface SoundingsTranslationsWrapperProps {
4
3
  children: React.ReactNode;
@@ -1,4 +1,4 @@
1
- import type { Meta, StoryObj } from '@storybook/react';
1
+ import type { Meta, StoryObj } from '@storybook/react-webpack5';
2
2
  import { Soundings } from './Soundings';
3
3
  declare const meta: Meta<typeof Soundings>;
4
4
  export default meta;
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { SourceType } from '../../store/types';
3
+ export declare const getLegendTitle: (source: SourceType) => string;
4
+ interface SoundingsLegendProps {
5
+ sourceSelections: SourceType[];
6
+ }
7
+ export declare const SoundingsLegend: ({ sourceSelections, }: SoundingsLegendProps) => React.ReactElement;
8
+ export {};
@@ -1,4 +1,3 @@
1
- /// <reference types="react" />
2
1
  import * as d3 from 'd3';
3
2
  import { i18n, TFunction } from 'i18next';
4
3
  import { SoundingDiagramType } from '../../api/edr-api/types';
@@ -17,10 +16,6 @@ interface InitializeSvg {
17
16
  margin: Margin;
18
17
  diagramType: SoundingDiagramType;
19
18
  }
20
- interface AddLegends {
21
- width: number;
22
- svg: d3.Selection<SVGElement, unknown, HTMLElement, undefined>;
23
- }
24
19
  interface DrawAxis {
25
20
  svg: d3.Selection<SVGElement, unknown, HTMLElement, undefined>;
26
21
  xScale: ScalesType;
@@ -39,11 +34,10 @@ interface PlotSounding {
39
34
  svg: d3.Selection<SVGElement, unknown, HTMLElement, undefined>;
40
35
  diagramType: SoundingDiagramType;
41
36
  }
42
- export declare const getDiagramName: (t: TFunction<'soundings', i18n>, diagramType: SoundingDiagramType) => string;
37
+ export declare const getDiagramName: (t: TFunction<"soundings", i18n>, diagramType: SoundingDiagramType) => string;
43
38
  export declare const initializeSvg: ({ svgRef, width, height, margin, diagramType, }: InitializeSvg) => d3.Selection<SVGGElement, unknown, null, undefined>;
44
39
  export declare const createScales: (diagramType: SoundingDiagramType, width: number, height: number, minPressure: number, maxPressure: number, minTemperature: number, maxTemperature: number) => [ScalesType, ScalesType];
45
40
  export declare const drawAxes: ({ svg, xScale, yScale, height, diagramType, }: DrawAxis) => void;
46
- export declare const addLegends: ({ svg, width }: AddLegends) => void;
47
41
  export declare const mapToPlot: (diagramType: SoundingDiagramType, filteredPressureValues: number[], filteredTemperatureValues: number[], xScale: ScalesType, yScale: ScalesType, height: number) => [number, number][];
48
42
  export declare const plotSounding: ({ temperatureValues, pressureValues, color, lineStyle, xScale, yScale, height, svg, diagramType, }: PlotSounding) => void;
49
43
  export declare const filterDomainRangeForParameter: (pressureDomain: number[], parameterDomain: number[]) => [number[], number[]];
@@ -0,0 +1 @@
1
+ export declare const getDisplayValue: (instanceId: string, stringFormat?: string) => string;
@@ -2,14 +2,14 @@ import { Store } from '@reduxjs/toolkit';
2
2
  import { UIModuleState, WebMapStateModuleState } from '@opengeoweb/store';
3
3
  import { SoundingsModuleState } from './types';
4
4
  export declare const soundingsReducersMap: {
5
- webmap: import("redux").Reducer<import("dist/libs/store/src/store/map/types").WebMapState, import("redux").UnknownAction, import("dist/libs/store/src/store/map/types").WebMapState>;
6
- services: import("redux").Reducer<import("dist/libs/store/src/store/map/types").ServiceState, import("redux").UnknownAction, import("dist/libs/store/src/store/map/types").ServiceState>;
7
- layers: import("redux").Reducer<import("dist/libs/store/src/store/map/types").LayerState, import("redux").UnknownAction, import("dist/libs/store/src/store/map/types").LayerState>;
8
- syncGroups: import("redux").Reducer<import("dist/libs/store/src/store/generic/syncGroups/types").SynchronizationGroupState, import("redux").UnknownAction, import("dist/libs/store/src/store/generic/syncGroups/types").SynchronizationGroupState>;
9
- loadingIndicator: import("redux").Reducer<import("@reduxjs/toolkit").EntityState<import("dist/libs/store/src/store/generic/loadingIndicator/types").LoadingIndicatorType, string>, import("redux").UnknownAction, import("@reduxjs/toolkit").EntityState<import("dist/libs/store/src/store/generic/loadingIndicator/types").LoadingIndicatorType, string>>;
10
- ui: import("redux").Reducer<import("dist/libs/store/src/store/ui/types").UIStoreType, import("redux").UnknownAction, import("dist/libs/store/src/store/ui/types").UIStoreType>;
11
- drawingtools: import("redux").Reducer<import("dist/libs/store/src/store/drawingTool/reducer").DrawingToolState, import("redux").UnknownAction, import("dist/libs/store/src/store/drawingTool/reducer").DrawingToolState>;
12
- router: import("redux").Reducer<{}, import("redux").UnknownAction, {}>;
5
+ webmap: import("redux").Reducer<import("dist/libs/store/src/store/map/types").WebMapState>;
6
+ services: import("redux").Reducer<import("dist/libs/store/src/store/map/types").ServiceState>;
7
+ layers: import("redux").Reducer<import("dist/libs/store/src/store/map/types").LayerState>;
8
+ syncGroups: import("redux").Reducer<import("dist/libs/store/src/store/generic/syncGroups/types").SynchronizationGroupState>;
9
+ loadingIndicator: import("redux").Reducer<import("@reduxjs/toolkit").EntityState<import("dist/libs/store/src/store/generic/loadingIndicator/types").LoadingIndicatorType, string>>;
10
+ ui: import("redux").Reducer<import("dist/libs/store/src/store/ui/types").UIStoreType>;
11
+ drawingtools: import("redux").Reducer<import("dist/libs/store/src/store/drawingTool/reducer").DrawingToolState>;
12
+ router: import("redux").Reducer<{}>;
13
13
  soundings: import("redux").Reducer<import("./types").SoundingsStore>;
14
14
  };
15
15
  export declare const createMockStore: (mockState?: SoundingsModuleState | WebMapStateModuleState | UIModuleState) => Store;
@@ -4,6 +4,7 @@ export interface SourceType {
4
4
  instanceId?: string;
5
5
  verticalRange?: string;
6
6
  parameterMappings?: Record<string, string>;
7
+ name?: string;
7
8
  }
8
9
  export interface UpdateSourcePayload {
9
10
  sourceId: string;
@@ -15,6 +16,7 @@ export interface SourceSelection {
15
16
  isChecked?: boolean;
16
17
  verticalRange?: string;
17
18
  parameterMappings?: Record<string, string>;
19
+ name?: string;
18
20
  }
19
21
  export interface UpdateLocationPayload {
20
22
  sourceId: string;