@opengeoweb/warnings 15.2.0 → 16.0.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
@@ -2,28 +2,32 @@ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { useDispatch, useSelector } from 'react-redux';
3
3
  import { uiTypes, uiActions, getSingularDrawtoolDrawLayerId, drawingToolSelectors, layerSelectors, uiSelectors, layerActions, drawingToolActions, mapListener, layersListener, drawingToolListener, syncGroupsListener, openlayersListener, syncGroupsReducer, drawingToolReducer, uiReducer, layerReducer, mapReducer, useSetupDialog, genericSelectors, useUpdateSharedData, genericActions, selectorMemoizationOptions } from '@opengeoweb/store';
4
4
  import { Polygons, CoastalEvent, TemperatureLow, TemperatureHigh, Rain, Snow, Lightning, Fog, Wind, Thunderstorm, SevereMountainWaves, VulcanicEruption, Haze, FreezingPrecipitation, ModerateAircraftIcing, SevereAircraftIcing, ModerateTurbulence, SevereTurbulence, SandStorm, RadioactiveMaterials, ExitDomain, Share, Edit, Delete, DrawPolygon, Visibility, Add, breakpoints, DragHandle, Info, ArrowUpCompact, ArrowDownCompact, Copy, Update, Cancel, Success, Expire, Remove, Options, ChevronDown, ChevronUp, Close, Clock } from '@opengeoweb/theme';
5
- import { WEBMAP_REACT_NAMESPACE, defaultPolygon, emptyGeoJSON, MapControlButton, defaultSmoothLine, defaultLineString, defaultFreehandLine, defaultOval, defaultCircle, defaultBox, defaultSquare, defaultLocation, defaultPoint, defaultDelete, getDrawModeIdFromSelectionType, getIcon, rewindGeometry, getGeoJSONPropertyValue, currentlySupportedDrawModes, defaultLayers, viewUtils, OpenLayersMapView, MapControls, OpenLayersZoomControl, OpenLayersLayer, OpenLayersFeatureLayer, genericOpenLayersFeatureStyle, DEFAULT_GEOJSON_STYLE_FILL_OPACITY, FEATURE_DRAW_FILL_COLOR, FEATURE_DRAW_SECONDARY_FILL_COLOR, FEATURE_DRAW_STROKE_COLOR } from '@opengeoweb/webmap-react';
5
+ import { WEBMAP_REACT_NAMESPACE, defaultPolygon, emptyGeoJSON, MapControlButton, defaultSmoothLine, defaultLineString, defaultFreehandLine, defaultOval, defaultCircle, defaultRotatableBox, defaultSquare, defaultLocation, defaultPoint, defaultDelete, getDrawModeIdFromSelectionType, getIcon, rewindGeometry, getGeoJSONPropertyValue, currentlySupportedDrawModes, defaultLayers, viewUtils, OpenLayersMapView, MapControls, OpenLayersZoomControl, OpenLayersLayer, OpenLayersFeatureLayer, genericOpenLayersFeatureStyle, DEFAULT_GEOJSON_STYLE_FILL_OPACITY, FEATURE_DRAW_FILL_COLOR, FEATURE_DRAW_SECONDARY_FILL_COLOR, FEATURE_DRAW_STROKE_COLOR } from '@opengeoweb/webmap-react';
6
6
  import { SHARED_NAMESPACE, useConfirmationDialog, sessionStorageProvider, dateUtils, ConfirmationDialog, AlertBanner, ToggleMenu, calculateStartSize, ToolContainerDraggable, CustomIconButton, usePrevious, usePreventBrowserClose, CustomTooltip, Avatar, getInitials, SwitchButton, Filter, CustomToggleButton, FilterChip, TooltipSelect, LastUpdateTime, StatusTag, FilterOption, getAxiosErrorMessage, CustomDialog, ConfirmationButtons, ErrorBoundary } from '@opengeoweb/shared';
7
7
  import { createEntityAdapter, createSlice, createSelector, createListenerMiddleware, current, combineReducers, configureStore } from '@reduxjs/toolkit';
8
8
  import { t } from 'i18next';
9
9
  import { useTranslation } from 'react-i18next';
10
10
  import { defaultBbox } from '@opengeoweb/core';
11
- import { FORM_FIELDS_NAMESPACE, useDraftFormHelpers, ReactHookFormSelect, ReactHookFormHiddenInput, isValidGeoJsonCoordinates, ReactHookFormTextField, ReactHookFormProvider, defaultFormOptions, errorMessages, isEmpty, ReactHookFormDateTime, isXHoursAfter, isXHoursBefore } from '@opengeoweb/form-fields';
11
+ import { FORM_FIELDS_NAMESPACE, useDraftFormHelpers, ReactHookFormSelect, ReactHookFormHiddenInput, isValidGeoJsonCoordinates, ReactHookFormTextField, ReactHookFormProvider, defaultFormOptions, errorMessages, isEmpty as isEmpty$1, ReactHookFormDateTime, isXHoursAfter, isXHoursBefore } from '@opengeoweb/form-fields';
12
12
  import { SA_NAMESPACE, isInstanceOfCancelSigmet, getDefaultValidFromValue, isInstanceOfCancelAirmet, getDefaultValidUntilValue, useShortTestHelpers, ProductAction, SigmetForm, AirmetForm, isVAPhenomenon, getConfirmationDialogCancelLabel, getConfirmationDialogButtonLabel, getConfirmationDialogContent, getConfirmationDialogTitle, CancelSigmetVolcanicMovements, createAirmetPostParameter, createSigmetPostParameter, prepareCancelSigmet, getProductFormMode, findSequenceNumber, getSequenceStyling } from '@opengeoweb/sigmet-airmet';
13
13
  import { LayerType, generateMapId } from '@opengeoweb/webmap';
14
14
  import React, { useRef, useState, useEffect, useMemo, useCallback } from 'react';
15
15
  import { useAuthenticationContext as useAuthenticationContext$1 } from '@opengeoweb/authentication';
16
- import { MenuItem, Grid, Box, Typography, styled, ListItem, Paper, ListItemButton, Stack, LinearProgress, Button, FormHelperText, Card, CardContent, Tabs, Tab, useTheme, FormControl, CircularProgress, Menu, ListItemText, DialogTitle, DialogContent, Switch, RadioGroup, FormControlLabel, Radio, InputAdornment, Collapse } from '@mui/material';
16
+ import { MenuItem, Grid, Box, Typography, styled, ListItem, Paper, ListItemButton, Stack, LinearProgress, Button, FormHelperText, Card, CardContent, Tabs, Tab, useTheme, FormControl, CircularProgress, Menu, ListItemText, DialogTitle, DialogContent, Switch, RadioGroup, FormControlLabel, Radio, InputAdornment, Collapse, Tooltip } from '@mui/material';
17
17
  import { useQueryClient, useMutation, queryOptions, QueryClient, useQuery } from '@tanstack/react-query';
18
18
  import { getHeaders, handleResponse, AirmetPhenomena, SigmetPhenomena, useAuthQuery, useAuthenticationContext, optimisticUpdate, ProductStatus } from '@opengeoweb/api';
19
19
  import { snackbarListener, snackbarReducer, snackbarActions, snackbarTypes } from '@opengeoweb/snackbar';
20
20
  import { List, useListRef } from 'react-window';
21
21
  import { isEqual, cloneDeep, clamp, concat, groupBy, pick } from 'lodash';
22
22
  import { useFormContext, useForm, FormProvider } from 'react-hook-form';
23
+ import { isEmpty, createEmpty, extend } from 'ol/extent';
24
+ import GeoJSON from 'ol/format/GeoJSON';
23
25
  import { ReactSortable } from 'react-sortablejs';
24
26
  import { LocalizationProvider } from '@mui/x-date-pickers';
25
27
  import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
26
28
  import { DateTimePicker } from '@mui/x-date-pickers/DateTimePicker';
29
+ import Box$1 from '@mui/material/Box';
30
+ import Tooltip$1 from '@mui/material/Tooltip';
27
31
 
28
32
  var en = {
29
33
  "drawing-tool-form-tools": "Tools",
@@ -84,6 +88,11 @@ var en = {
84
88
  "warning-level-moderate": "Moderate",
85
89
  "warning-level-severe": "Severe",
86
90
  "warning-level-extreme": "Extreme",
91
+ "warning-level-letter-moderate": "M",
92
+ "warning-level-letter-severe": "S",
93
+ "warning-level-letter-extreme": "E",
94
+ "warning-level-letter-SIG": "SIG",
95
+ "warning-level-letter-AIR": "AIR",
87
96
  "warning-level-SIG": "Sigmet",
88
97
  "warning-level-AIR": "Airmet",
89
98
  "warning-phenomenon": "Phenomenon",
@@ -347,6 +356,11 @@ var nl = {
347
356
  "warning-level-moderate": "Gematigd",
348
357
  "warning-level-severe": "Ernstig",
349
358
  "warning-level-extreme": "Extreem",
359
+ "warning-level-letter-moderate": "G",
360
+ "warning-level-letter-severe": "E",
361
+ "warning-level-letter-extreme": "X",
362
+ "warning-level-letter-SIG": "SIG",
363
+ "warning-level-letter-AIR": "AIR",
350
364
  "warning-phenomenon": "Fenomeen",
351
365
  "warning-phenomenon-wind": "Windstoten",
352
366
  "warning-phenomenon-fog": "Dichte mist",
@@ -567,6 +581,11 @@ var fi = {
567
581
  "warning-level-moderate": "Kohtalainen",
568
582
  "warning-level-severe": "Vakava",
569
583
  "warning-level-extreme": "Äärimmäinen",
584
+ "warning-level-letter-moderate": "K",
585
+ "warning-level-letter-severe": "V",
586
+ "warning-level-letter-extreme": "Ä",
587
+ "warning-level-letter-SIG": "SIG",
588
+ "warning-level-letter-AIR": "AIR",
570
589
  "warning-phenomenon": "Sääilmiö",
571
590
  "warning-phenomenon-wind": "Tuuli",
572
591
  "warning-phenomenon-fog": "Sumu",
@@ -739,6 +758,11 @@ var no = {
739
758
  "warning-level-moderate": "Moderat",
740
759
  "warning-level-severe": "Stor",
741
760
  "warning-level-extreme": "Ekstrem",
761
+ "warning-level-letter-moderate": "M",
762
+ "warning-level-letter-severe": "S",
763
+ "warning-level-letter-extreme": "E",
764
+ "warning-level-letter-SIG": "SIG",
765
+ "warning-level-letter-AIR": "AIR",
742
766
  "warning-phenomenon": "Fenomen",
743
767
  "warning-phenomenon-wind": "Vind",
744
768
  "warning-phenomenon-fog": "Tåke",
@@ -883,6 +907,11 @@ var areaObjectLoaderType = uiTypes.DialogTypes.AreaObjectLoader;
883
907
  function _OverloadYield(e, d) {
884
908
  this.v = e, this.k = d;
885
909
  }
910
+ function _arrayLikeToArray(r, a) {
911
+ (null == a || a > r.length) && (a = r.length);
912
+ for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e];
913
+ return n;
914
+ }
886
915
  function asyncGeneratorStep(n, t, e, r, o, a, c) {
887
916
  try {
888
917
  var i = n[a](c),
@@ -908,6 +937,23 @@ function _asyncToGenerator(n) {
908
937
  });
909
938
  };
910
939
  }
940
+ function _createForOfIteratorHelperLoose(r, e) {
941
+ var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
942
+ if (t) return (t = t.call(r)).next.bind(t);
943
+ if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e) {
944
+ t && (r = t);
945
+ var o = 0;
946
+ return function () {
947
+ return o >= r.length ? {
948
+ done: true
949
+ } : {
950
+ done: false,
951
+ value: r[o++]
952
+ };
953
+ };
954
+ }
955
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
956
+ }
911
957
  function _objectWithoutPropertiesLoose(r, e) {
912
958
  if (null == r) return {};
913
959
  var t = {};
@@ -1092,6 +1138,13 @@ function _regeneratorValues(e) {
1092
1138
  }
1093
1139
  throw new TypeError(typeof e + " is not iterable");
1094
1140
  }
1141
+ function _unsupportedIterableToArray(r, a) {
1142
+ if (r) {
1143
+ if ("string" == typeof r) return _arrayLikeToArray(r, a);
1144
+ var t = {}.toString.call(r).slice(8, -1);
1145
+ return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
1146
+ }
1147
+ }
1095
1148
  function _regeneratorRuntime() {
1096
1149
 
1097
1150
  var r = _regenerator(),
@@ -2156,7 +2209,8 @@ var isWarningWithinInterval = function isWarningWithinInterval(warning, timeFilt
2156
2209
  date: rangeStart.getUTCDate() + 1,
2157
2210
  hours: 0,
2158
2211
  minutes: 0,
2159
- seconds: 0
2212
+ seconds: 0,
2213
+ milliseconds: 0
2160
2214
  });
2161
2215
  } else {
2162
2216
  // TOMORROW
@@ -2164,16 +2218,18 @@ var isWarningWithinInterval = function isWarningWithinInterval(warning, timeFilt
2164
2218
  date: now.getUTCDate() + 1,
2165
2219
  hours: 0,
2166
2220
  minutes: 0,
2167
- seconds: 0
2221
+ seconds: 0,
2222
+ milliseconds: 0
2168
2223
  });
2169
2224
  rangeEnd = dateUtils.set(rangeStart, {
2170
2225
  date: rangeStart.getUTCDate() + 1,
2171
2226
  hours: 0,
2172
2227
  minutes: 0,
2173
- seconds: 0
2228
+ seconds: 0,
2229
+ milliseconds: 0
2174
2230
  });
2175
2231
  }
2176
- return warningEnd >= rangeStart && warningStart <= rangeEnd;
2232
+ return warningEnd >= rangeStart && warningStart < rangeEnd;
2177
2233
  };
2178
2234
  var getApiParams = function getApiParams(timeFilter) {
2179
2235
  if (timeFilter.mode === TimeFilterMode.all) {
@@ -4279,7 +4335,7 @@ var drawToolConfig = [{
4279
4335
  secondaryMode: defaultOval
4280
4336
  }, {
4281
4337
  primaryMode: defaultSquare,
4282
- secondaryMode: defaultBox
4338
+ secondaryMode: defaultRotatableBox
4283
4339
  }, {
4284
4340
  primaryMode: defaultPoint,
4285
4341
  secondaryMode: defaultLocation
@@ -6864,12 +6920,30 @@ var AreaObjectLoader = function AreaObjectLoader(_ref) {
6864
6920
  });
6865
6921
  };
6866
6922
 
6923
+ var EXTENT_PADDING = 50;
6924
+ function getGeojsonExtent(featureCollection, viewSrs, dataSrs) {
6925
+ var format = new GeoJSON();
6926
+ var features = format.readFeatures(featureCollection, {
6927
+ dataProjection: dataSrs,
6928
+ featureProjection: viewSrs
6929
+ });
6930
+ var extent = createEmpty();
6931
+ for (var _iterator = _createForOfIteratorHelperLoose(features), _step; !(_step = _iterator()).done;) {
6932
+ var feat = _step.value;
6933
+ var geo = feat.getGeometry();
6934
+ if (geo) {
6935
+ extend(extent, geo.getExtent());
6936
+ }
6937
+ }
6938
+ return extent;
6939
+ }
6867
6940
  var WarningsMapView = function WarningsMapView(_ref) {
6868
6941
  var _defaultMapPreset$lay, _defaultMapPreset$lay2, _viewRef$current;
6869
6942
  var geojsonFeature = _ref.geojsonFeature,
6870
6943
  defaultMapPreset = _ref.defaultMapPreset,
6871
6944
  _ref$isSnapshot = _ref.isSnapshot,
6872
6945
  isSnapshot = _ref$isSnapshot === void 0 ? false : _ref$isSnapshot;
6946
+ var containerRef = useRef(null);
6873
6947
  var defaultMapPresetBbox = geojsonFeature != null && geojsonFeature.features.length ? undefined : defaultBbox;
6874
6948
  var defaultBbox$1 = (defaultMapPreset == null ? void 0 : defaultMapPreset.proj) || defaultMapPresetBbox;
6875
6949
  var defaultBaseLayer = (defaultMapPreset == null || (_defaultMapPreset$lay = defaultMapPreset.layers) == null ? void 0 : _defaultMapPreset$lay.find(function (layer) {
@@ -6885,12 +6959,36 @@ var WarningsMapView = function WarningsMapView(_ref) {
6885
6959
  };
6886
6960
  var viewRef = useRef(viewUtils.makeView());
6887
6961
  React.useEffect(function () {
6962
+ var _geojsonFeature$featu;
6888
6963
  if (viewRef.current.getProjection().getCode() !== (defaultBbox$1 == null ? void 0 : defaultBbox$1.srs)) {
6889
6964
  viewRef.current = viewUtils.makeView(defaultBbox$1 == null ? void 0 : defaultBbox$1.srs);
6890
6965
  }
6891
- defaultBbox$1 != null && defaultBbox$1.bbox ? viewUtils.setViewFromExtent(viewRef.current, defaultBbox$1 == null ? void 0 : defaultBbox$1.bbox) : viewUtils.setViewFromFeature(viewRef.current, geojsonFeature);
6966
+ var isNew = (defaultBbox$1 == null ? void 0 : defaultBbox$1.bbox) && !(geojsonFeature != null && geojsonFeature.features.length);
6967
+ if (isNew) {
6968
+ viewUtils.setViewFromExtent(viewRef.current, defaultBbox$1 == null ? void 0 : defaultBbox$1.bbox);
6969
+ return;
6970
+ }
6971
+ if (geojsonFeature != null && (_geojsonFeature$featu = geojsonFeature.features) != null && _geojsonFeature$featu.length) {
6972
+ var viewSrs = viewRef.current.getProjection().getCode();
6973
+ var extent = getGeojsonExtent(geojsonFeature, viewSrs, 'EPSG:4326');
6974
+ if (!isEmpty(extent)) {
6975
+ var el = containerRef.current;
6976
+ var rect = el == null ? void 0 : el.getBoundingClientRect();
6977
+ var size = rect && rect.width > 0 && rect.height > 0 ? [Math.round(rect.width), Math.round(rect.height)] : undefined;
6978
+ viewRef.current.fit(extent, {
6979
+ size: size,
6980
+ padding: [EXTENT_PADDING, EXTENT_PADDING, EXTENT_PADDING, EXTENT_PADDING],
6981
+ maxZoom: 12,
6982
+ duration: 0
6983
+ });
6984
+ return;
6985
+ }
6986
+ }
6987
+ // fallback
6988
+ viewUtils.setViewFromFeature(viewRef.current, geojsonFeature);
6892
6989
  }, [defaultBbox$1, geojsonFeature]);
6893
6990
  return jsx("div", {
6991
+ ref: containerRef,
6894
6992
  style: {
6895
6993
  height: '200px',
6896
6994
  width: '100%'
@@ -7198,18 +7296,18 @@ var WarningLevel;
7198
7296
  var LevelColors = {
7199
7297
  moderate: {
7200
7298
  color: '#FAE21E',
7201
- textColor: '#051039',
7202
- borderColor: '#FBFE02'
7299
+ textColor: '#3A3400',
7300
+ borderColor: '#A08F07'
7203
7301
  },
7204
7302
  severe: {
7205
7303
  color: '#E27000',
7206
7304
  textColor: '#051039',
7207
- borderColor: '#FEAE02'
7305
+ borderColor: '#9C4D00'
7208
7306
  },
7209
7307
  extreme: {
7210
7308
  color: '#D62A20',
7211
7309
  textColor: '#ffffff',
7212
- borderColor: '#FF0000'
7310
+ borderColor: '#890101'
7213
7311
  }
7214
7312
  };
7215
7313
  var getLevelStyle = function getLevelStyle(levelColor) {
@@ -7327,7 +7425,7 @@ var ProbabilityField = function ProbabilityField(_ref) {
7327
7425
  var onChangeProbability = function onChangeProbability() {
7328
7426
  void trigger('probability');
7329
7427
  // We don't want to trigger the missing value validation
7330
- if (!isEmpty(getValues('level'))) {
7428
+ if (!isEmpty$1(getValues('level'))) {
7331
7429
  void trigger('level');
7332
7430
  }
7333
7431
  };
@@ -7436,7 +7534,7 @@ var _isMaxHoursAfterCurrentTime = function isMaxHoursAfterCurrentTime(value, t)
7436
7534
  });
7437
7535
  };
7438
7536
  var _isMinHoursAfterValidFrom = function isMinHoursAfterValidFrom(value, validFromValue, t) {
7439
- if (isEmpty(value) || isEmpty(validFromValue) || !dateUtils.isValidIsoDateString(validFromValue)) {
7537
+ if (isEmpty$1(value) || isEmpty$1(validFromValue) || !dateUtils.isValidIsoDateString(validFromValue)) {
7440
7538
  return true;
7441
7539
  }
7442
7540
  var duration = dateUtils.differenceInHours(new Date(value), new Date(validFromValue));
@@ -14091,4 +14189,705 @@ ComponentsLookUpWrapper) {
14091
14189
  }
14092
14190
  };
14093
14191
 
14094
- export { DrawingToolConnect, Wrapper as DrawingToolForm, DrawingToolFormConnect, DrawingToolMapButtonConnect, ObjectManagerConnect, ObjectManagerMapButtonConnect, PublicWarningsFormDialog, PublicWarningsFormDialogConnect, WARN_NAMESPACE, componentsLookUp, createMockStore, isAlreadyEdited, selectors as publicWarningsSelectors, useObjectDrawDialogAction, warningFormConfirmationOptions, warningsDrawingsActions, warningsDrawingsReducer, warningsFiltersActions, warningsFiltersReducer, warningsFormActions, warningsFormListener, warningsFormReducer, warningsMiddlewares, warningsReducersMap, warningsTranslations };
14192
+ /* *
14193
+ * Licensed under the Apache License, Version 2.0 (the "License");
14194
+ * you may not use this file except in compliance with the License.
14195
+ * You may obtain a copy of the License at
14196
+ *
14197
+ * http://www.apache.org/licenses/LICENSE-2.0
14198
+ *
14199
+ * Unless required by applicable law or agreed to in writing, software
14200
+ * distributed under the License is distributed on an "AS IS" BASIS,
14201
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14202
+ * See the License for the specific language governing permissions and
14203
+ * limitations under the License.
14204
+ *
14205
+ * Copyright 2026 - Koninklijk Nederlands Meteorologisch Instituut (KNMI)
14206
+ * Copyright 2026 - Finnish Meteorological Institute (FMI)
14207
+ * Copyright 2026 - The Norwegian Meteorological Institute (MET Norway)
14208
+ * */
14209
+ var draftStripes = function draftStripes(stripeColor, bgColor) {
14210
+ return "repeating-linear-gradient(\n -45deg,\n transparent,\n transparent 8px,\n " + stripeColor + " 8px,\n " + stripeColor + " 9px\n ), " + bgColor;
14211
+ };
14212
+ var TimelineColors = {
14213
+ // Public warnings - Extreme (Red)
14214
+ extreme: {
14215
+ published: {
14216
+ background: LevelColors.extreme.color,
14217
+ border: LevelColors.extreme.borderColor,
14218
+ iconColor: LevelColors.extreme.textColor,
14219
+ letterColor: LevelColors.extreme.textColor
14220
+ },
14221
+ draft: {
14222
+ background: '#F1D0D0',
14223
+ stripeColor: 'rgba(255, 255, 255, 0.5)',
14224
+ border: LevelColors.extreme.borderColor,
14225
+ iconColor: LevelColors.extreme.color,
14226
+ letterColor: LevelColors.extreme.color
14227
+ },
14228
+ expired: {
14229
+ background: '#EFEFEF',
14230
+ border: LevelColors.extreme.borderColor,
14231
+ iconColor: LevelColors.extreme.color,
14232
+ letterColor: LevelColors.extreme.color
14233
+ }
14234
+ },
14235
+ // Public warnings - Severe (Orange)
14236
+ severe: {
14237
+ published: {
14238
+ background: LevelColors.severe.color,
14239
+ border: LevelColors.severe.borderColor,
14240
+ iconColor: 'white',
14241
+ letterColor: 'white'
14242
+ },
14243
+ draft: {
14244
+ background: '#FADDC2',
14245
+ stripeColor: 'rgba(255, 255, 255, 0.5)',
14246
+ border: '#E27000',
14247
+ iconColor: '#9C4D00',
14248
+ letterColor: '#9C4D00'
14249
+ },
14250
+ expired: {
14251
+ background: '#EFEFEF',
14252
+ border: '#E27000',
14253
+ iconColor: '#9C4D00',
14254
+ letterColor: '#9C4D00'
14255
+ }
14256
+ },
14257
+ // Public warnings - Moderate (Yellow)
14258
+ moderate: {
14259
+ published: {
14260
+ background: LevelColors.moderate.color,
14261
+ border: LevelColors.moderate.borderColor,
14262
+ iconColor: '#3A3400',
14263
+ letterColor: '#3A3400'
14264
+ },
14265
+ draft: {
14266
+ background: '#FFFACE',
14267
+ stripeColor: 'rgba(250, 226, 28, 0.5)',
14268
+ // Yellow stripes
14269
+ border: LevelColors.moderate.borderColor,
14270
+ iconColor: '#3A3400',
14271
+ letterColor: '#3A3400'
14272
+ },
14273
+ expired: {
14274
+ background: '#EFEFEF',
14275
+ border: LevelColors.moderate.borderColor,
14276
+ iconColor: '#3A3400',
14277
+ letterColor: '#3A3400'
14278
+ }
14279
+ },
14280
+ // Aviation (SIGMET/AIRMET) - Blue
14281
+ aviation: {
14282
+ published: {
14283
+ background: '#186DFF',
14284
+ border: '#0800B9',
14285
+ iconColor: '#FFFFFF',
14286
+ letterColor: '#FFFFFF'
14287
+ },
14288
+ draft: {
14289
+ background: '#E3EDFF',
14290
+ stripeColor: 'rgba(255, 255, 255, 0.5)',
14291
+ border: '#0800B9',
14292
+ iconColor: '#0800B9',
14293
+ letterColor: '#0800B9'
14294
+ },
14295
+ expired: {
14296
+ background: '#EFEFEF',
14297
+ border: '#0800B9',
14298
+ iconColor: '#186DFF',
14299
+ letterColor: '#186DFF'
14300
+ }
14301
+ },
14302
+ // Default/fallback
14303
+ "default": {
14304
+ published: {
14305
+ background: '#FFFFFF',
14306
+ border: '#AAAAAA',
14307
+ iconColor: '#333333',
14308
+ letterColor: '#333333'
14309
+ },
14310
+ draft: {
14311
+ background: '#FFFFFF',
14312
+ stripeColor: 'rgba(255, 255, 255, 0.5)',
14313
+ border: '#AAAAAA',
14314
+ iconColor: '#333333',
14315
+ letterColor: '#333333'
14316
+ },
14317
+ expired: {
14318
+ background: '#EFEFEF',
14319
+ border: '#AAAAAA',
14320
+ iconColor: '#333333',
14321
+ letterColor: '#333333'
14322
+ }
14323
+ }
14324
+ };
14325
+ var getThemeForLevel = function getThemeForLevel(level, isAviation) {
14326
+ if (isAviation) {
14327
+ return TimelineColors.aviation;
14328
+ }
14329
+ switch (level) {
14330
+ case WarningLevel.extreme:
14331
+ return TimelineColors.extreme;
14332
+ case WarningLevel.severe:
14333
+ return TimelineColors.severe;
14334
+ case WarningLevel.moderate:
14335
+ return TimelineColors.moderate;
14336
+ default:
14337
+ return TimelineColors["default"];
14338
+ }
14339
+ };
14340
+ var getBlockStyle = function getBlockStyle(level, status, isAviation) {
14341
+ var theme = getThemeForLevel(level, isAviation);
14342
+ if (status === PublicWarningStatus.DRAFT || status === PublicWarningStatus.DRAFT_PUBLISHED) {
14343
+ var _theme$draft = theme.draft,
14344
+ stripeColor = _theme$draft.stripeColor,
14345
+ background = _theme$draft.background,
14346
+ border = _theme$draft.border,
14347
+ iconColor = _theme$draft.iconColor,
14348
+ letterColor = _theme$draft.letterColor;
14349
+ return {
14350
+ background: draftStripes(stripeColor, background),
14351
+ border: "1px solid " + border,
14352
+ borderColor: border,
14353
+ iconColor: iconColor,
14354
+ letterColor: letterColor
14355
+ };
14356
+ }
14357
+ if (status === PublicWarningStatus.EXPIRED) {
14358
+ return {
14359
+ background: theme.expired.background,
14360
+ border: "1px solid " + theme.expired.border,
14361
+ borderColor: theme.expired.border,
14362
+ iconColor: theme.expired.iconColor,
14363
+ letterColor: theme.expired.letterColor
14364
+ };
14365
+ }
14366
+ // Published (default)
14367
+ return {
14368
+ background: theme.published.background,
14369
+ border: "1px solid " + theme.published.border,
14370
+ borderColor: theme.published.border,
14371
+ iconColor: theme.published.iconColor,
14372
+ letterColor: theme.published.letterColor
14373
+ };
14374
+ };
14375
+
14376
+ /* *
14377
+ * Licensed under the Apache License, Version 2.0 (the "License");
14378
+ * you may not use this file except in compliance with the License.
14379
+ * You may obtain a copy of the License at
14380
+ *
14381
+ * http://www.apache.org/licenses/LICENSE-2.0
14382
+ *
14383
+ * Unless required by applicable law or agreed to in writing, software
14384
+ * distributed under the License is distributed on an "AS IS" BASIS,
14385
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14386
+ * See the License for the specific language governing permissions and
14387
+ * limitations under the License.
14388
+ *
14389
+ * Copyright 2026 - Koninklijk Nederlands Meteorologisch Instituut (KNMI)
14390
+ * Copyright 2026 - Finnish Meteorological Institute (FMI)
14391
+ * Copyright 2026 - The Norwegian Meteorological Institute (MET Norway)
14392
+ * */
14393
+ var EDGE_PADDING = 24;
14394
+ var SIZE_THRESHOLDS = {
14395
+ xxs: 24,
14396
+ xs: 50,
14397
+ sm: 100
14398
+ };
14399
+ var getTimelineX = function getTimelineX(targetTime, timelineStart, timelineEnd, drawableWidth) {
14400
+ var totalTimelineDuration = timelineEnd.getTime() - timelineStart.getTime();
14401
+ if (totalTimelineDuration <= 0) {
14402
+ return 0;
14403
+ }
14404
+ var elapsedMs = targetTime.getTime() - timelineStart.getTime();
14405
+ return EDGE_PADDING + elapsedMs / totalTimelineDuration * drawableWidth;
14406
+ };
14407
+ var getTimeFromX = function getTimeFromX(x, timelineStart, timelineEnd, drawableWidth) {
14408
+ var totalTimelineDuration = timelineEnd.getTime() - timelineStart.getTime();
14409
+ if (drawableWidth <= 0) {
14410
+ return new Date(timelineStart);
14411
+ }
14412
+ var adjustedX = x - EDGE_PADDING;
14413
+ var ratio = adjustedX / drawableWidth;
14414
+ var timeMs = timelineStart.getTime() + ratio * totalTimelineDuration;
14415
+ return new Date(timeMs);
14416
+ };
14417
+ var generateTicks = function generateTicks(timelineStart, timelineEnd) {
14418
+ var ticks = [];
14419
+ var hourInterval = 3;
14420
+ var current = new Date(timelineStart);
14421
+ current.setUTCMinutes(0, 0, 0);
14422
+ if (current < timelineStart) {
14423
+ current.setUTCHours(current.getUTCHours() + 1);
14424
+ }
14425
+ while (current <= timelineEnd) {
14426
+ var hour = current.getUTCHours();
14427
+ if (hour === 0) {
14428
+ ticks.push({
14429
+ time: new Date(current),
14430
+ type: 'day'
14431
+ });
14432
+ } else if (hour % hourInterval === 0) {
14433
+ ticks.push({
14434
+ time: new Date(current),
14435
+ type: 'major'
14436
+ });
14437
+ } else {
14438
+ ticks.push({
14439
+ time: new Date(current),
14440
+ type: 'dashed'
14441
+ });
14442
+ }
14443
+ current.setUTCHours(current.getUTCHours() + 1);
14444
+ }
14445
+ return ticks;
14446
+ };
14447
+ var getTickLineStyle = function getTickLineStyle(tickType) {
14448
+ if (tickType === 'day') {
14449
+ return {
14450
+ width: '2px',
14451
+ borderLeft: '2px solid #ABC3FF'
14452
+ };
14453
+ }
14454
+ if (tickType === 'dashed') {
14455
+ return {
14456
+ width: '1px',
14457
+ borderLeft: '1px dashed #E7ECFA'
14458
+ };
14459
+ }
14460
+ return {
14461
+ width: '1px',
14462
+ borderLeft: '1px solid #90caf9'
14463
+ };
14464
+ };
14465
+ var getBlockSize = function getBlockSize(width) {
14466
+ if (width < SIZE_THRESHOLDS.xxs) {
14467
+ return 'xxs';
14468
+ }
14469
+ if (width < SIZE_THRESHOLDS.xs) {
14470
+ return 'xs';
14471
+ }
14472
+ if (width < SIZE_THRESHOLDS.sm) {
14473
+ return 's';
14474
+ }
14475
+ return 'l';
14476
+ };
14477
+
14478
+ /**
14479
+ * Gets the author/editor from a warning.
14480
+ * For airmet/sigmet warnings, author is in sigmetAirmetDetails.
14481
+ * For public/maritime warnings, editor is on the base warning.
14482
+ */
14483
+ var getWarningAuthor = function getWarningAuthor(warning) {
14484
+ if ('sigmetAirmetDetails' in warning) {
14485
+ var _warning$sigmetAirmet, _warning$sigmetAirmet2;
14486
+ return (_warning$sigmetAirmet = (_warning$sigmetAirmet2 = warning.sigmetAirmetDetails) == null ? void 0 : _warning$sigmetAirmet2.author) != null ? _warning$sigmetAirmet : warning.editor;
14487
+ }
14488
+ return warning.editor;
14489
+ };
14490
+ var formatPeriod = function formatPeriod(from, until) {
14491
+ var ff = new Date(from);
14492
+ var uu = new Date(until);
14493
+ var dateOpts = {
14494
+ day: 'numeric',
14495
+ month: 'short',
14496
+ timeZone: 'UTC'
14497
+ };
14498
+ var timeOpts = {
14499
+ hour: '2-digit',
14500
+ minute: '2-digit',
14501
+ hour12: false,
14502
+ timeZone: 'UTC'
14503
+ };
14504
+ var fDate = ff.toLocaleDateString('en-GB', dateOpts);
14505
+ var uDate = uu.toLocaleDateString('en-GB', dateOpts);
14506
+ var fTime = ff.toLocaleTimeString('en-GB', timeOpts);
14507
+ var uTime = uu.toLocaleTimeString('en-GB', timeOpts);
14508
+ return fDate === uDate ? fDate + " " + fTime + " \u2013 " + uTime + " UTC" : fDate + " " + fTime + " \u2013 " + uDate + " " + uTime + " UTC";
14509
+ };
14510
+ var getTooltipContent = function getTooltipContent(warning, t) {
14511
+ var warningDetail = warning.warningDetail,
14512
+ status = warning.status,
14513
+ type = warning.type;
14514
+ var author = getWarningAuthor(warning);
14515
+ var isAviation = type === 'sigmet' || type === 'airmet';
14516
+ var phenomenonEntry = warningPhenomena.find(function (entry) {
14517
+ return entry.key === warningDetail.phenomenon;
14518
+ });
14519
+ var phenomenonLabel = phenomenonEntry ? t(phenomenonEntry.translationKey) : warningDetail.phenomenon;
14520
+ var line1 = isAviation ? [type.toUpperCase(), phenomenonLabel].filter(Boolean).join(' · ') : [phenomenonLabel, warningDetail.level, warningDetail.probability ? warningDetail.probability + "%" : null].filter(Boolean).join(' · ');
14521
+ var period = warningDetail.validFrom && warningDetail.validUntil ? formatPeriod(warningDetail.validFrom, warningDetail.validUntil) : null;
14522
+ var meta = [author, status].filter(Boolean).join(' · ');
14523
+ return jsxs(Box, {
14524
+ sx: {
14525
+ fontSize: 12,
14526
+ lineHeight: 1.6
14527
+ },
14528
+ children: [jsx(Box, {
14529
+ sx: {
14530
+ fontWeight: 600
14531
+ },
14532
+ children: line1
14533
+ }), period ? jsx(Box, {
14534
+ children: period
14535
+ }) : null, meta ? jsx(Box, {
14536
+ children: meta
14537
+ }) : null]
14538
+ });
14539
+ };
14540
+ var WarningBlock = function WarningBlock(_ref) {
14541
+ var warning = _ref.warning,
14542
+ left = _ref.left,
14543
+ top = _ref.top,
14544
+ width = _ref.width;
14545
+ var _useWarningsTranslati = useWarningsTranslation(),
14546
+ t = _useWarningsTranslati.t;
14547
+ var warningDetail = warning.warningDetail,
14548
+ status = warning.status,
14549
+ type = warning.type;
14550
+ var author = getWarningAuthor(warning);
14551
+ var isAviation = type === 'sigmet' || type === 'airmet';
14552
+ var level = warningDetail.level || null;
14553
+ var letter = level ? t("warning-level-letter-" + level) : '';
14554
+ var _getBlockStyle = getBlockStyle(level, status, isAviation),
14555
+ background = _getBlockStyle.background,
14556
+ border = _getBlockStyle.border,
14557
+ iconColor = _getBlockStyle.iconColor,
14558
+ letterColor = _getBlockStyle.letterColor;
14559
+ var size = getBlockSize(width);
14560
+ var elements = [];
14561
+ if (size === 's' || size === 'l') {
14562
+ elements.push(jsx(Box, {
14563
+ sx: {
14564
+ fontSize: 16,
14565
+ fontWeight: 600,
14566
+ lineHeight: '80%',
14567
+ color: letterColor
14568
+ },
14569
+ children: letter
14570
+ }, "letter"));
14571
+ }
14572
+ if (size !== 'xxs') {
14573
+ elements.push(jsx(Box, {
14574
+ sx: {
14575
+ display: 'flex',
14576
+ alignItems: 'center',
14577
+ justifyContent: 'center',
14578
+ color: iconColor,
14579
+ fontSize: 18
14580
+ },
14581
+ children: getPhenomenaIcon(warningDetail.phenomenon) || null
14582
+ }, "icon"));
14583
+ }
14584
+ if (size === 'l') {
14585
+ elements.push(jsx(Box, {
14586
+ sx: {
14587
+ border: '0.5px solid white',
14588
+ borderRadius: '50%'
14589
+ },
14590
+ children: jsx(WarningAvatar, {
14591
+ editor: author != null ? author : ''
14592
+ })
14593
+ }, "avatar"));
14594
+ }
14595
+ return jsx(Tooltip, {
14596
+ placement: "top",
14597
+ title: getTooltipContent(warning, t),
14598
+ children: jsx(Box, {
14599
+ "data-testid": "warning-block",
14600
+ sx: {
14601
+ position: 'absolute',
14602
+ left: left,
14603
+ top: top,
14604
+ width: width,
14605
+ height: 28,
14606
+ padding: '4px 8px',
14607
+ background: background,
14608
+ border: border,
14609
+ borderRadius: 1,
14610
+ display: 'flex',
14611
+ alignItems: 'center',
14612
+ justifyContent: elements.length === 1 ? 'center' : 'space-between',
14613
+ overflow: 'hidden'
14614
+ },
14615
+ children: elements
14616
+ })
14617
+ });
14618
+ };
14619
+
14620
+ var WARNING_BLOCK_HEIGHT = 34;
14621
+ var DEFAULT_VISIBLE_ROWS = 10;
14622
+ var TIMELINE_BAR_HEIGHT = 40;
14623
+ var PIXELS_PER_HOUR = 30;
14624
+ var MS_PER_HOUR = 60 * 60 * 1000;
14625
+ var MS_PER_DAY = 24 * MS_PER_HOUR;
14626
+ var WarningsTimeline = function WarningsTimeline(_ref) {
14627
+ var warnings = _ref.warnings;
14628
+ var timelineWarnings = React.useMemo(function () {
14629
+ var _warnings$filter;
14630
+ return (_warnings$filter = warnings == null ? void 0 : warnings.filter(function (warning) {
14631
+ return Boolean(warning.warningDetail.validFrom) && Boolean(warning.warningDetail.validUntil);
14632
+ })) != null ? _warnings$filter : [];
14633
+ }, [warnings]);
14634
+ var warningsAreaRef = React.useRef(null);
14635
+ var timeAxisRef = React.useRef(null);
14636
+ var _React$useState = React.useState(0),
14637
+ containerWidth = _React$useState[0],
14638
+ setContainerWidth = _React$useState[1];
14639
+ React.useEffect(function () {
14640
+ if (!warningsAreaRef.current) {
14641
+ return undefined;
14642
+ }
14643
+ var resizeObserver = new ResizeObserver(function (entries) {
14644
+ for (var _iterator = _createForOfIteratorHelperLoose(entries), _step; !(_step = _iterator()).done;) {
14645
+ var entry = _step.value;
14646
+ setContainerWidth(entry.contentRect.width);
14647
+ }
14648
+ });
14649
+ resizeObserver.observe(warningsAreaRef.current);
14650
+ return function () {
14651
+ return resizeObserver.disconnect();
14652
+ };
14653
+ }, []);
14654
+ var handleWarningsScroll = React.useCallback(function () {
14655
+ if (warningsAreaRef.current && timeAxisRef.current) {
14656
+ timeAxisRef.current.scrollLeft = warningsAreaRef.current.scrollLeft;
14657
+ }
14658
+ }, []);
14659
+ var _React$useState2 = React.useState(function () {
14660
+ return new Date();
14661
+ }),
14662
+ now = _React$useState2[0],
14663
+ setNow = _React$useState2[1];
14664
+ React.useEffect(function () {
14665
+ var id = setInterval(function () {
14666
+ return setNow(new Date());
14667
+ }, MS_PER_HOUR / 60);
14668
+ return function () {
14669
+ return clearInterval(id);
14670
+ };
14671
+ }, []);
14672
+ var _React$useMemo = React.useMemo(function () {
14673
+ var snapshotNow = new Date();
14674
+ var defaultStart = new Date(snapshotNow.getTime() - MS_PER_DAY);
14675
+ var defaultEnd = new Date(snapshotNow.getTime() + 3 * MS_PER_DAY);
14676
+ if (!timelineWarnings.length) {
14677
+ return {
14678
+ timelineStart: defaultStart,
14679
+ timelineEnd: defaultEnd
14680
+ };
14681
+ }
14682
+ var warningMin = Number.POSITIVE_INFINITY;
14683
+ var warningMax = Number.NEGATIVE_INFINITY;
14684
+ for (var _iterator2 = _createForOfIteratorHelperLoose(timelineWarnings), _step2; !(_step2 = _iterator2()).done;) {
14685
+ var warning = _step2.value;
14686
+ var _warning$warningDetai = warning.warningDetail,
14687
+ validFrom = _warning$warningDetai.validFrom,
14688
+ validUntil = _warning$warningDetai.validUntil;
14689
+ if (validFrom) {
14690
+ warningMin = Math.min(warningMin, new Date(validFrom).getTime());
14691
+ }
14692
+ if (validUntil) {
14693
+ warningMax = Math.max(warningMax, new Date(validUntil).getTime());
14694
+ }
14695
+ }
14696
+ // Floor earliest warning to previous 3-hour boundary, then subtract 3h to get some 'air'
14697
+ var warningStartDate = new Date(warningMin);
14698
+ warningStartDate.setUTCMinutes(0, 0, 0);
14699
+ var flooredHour = warningStartDate.getUTCHours() - warningStartDate.getUTCHours() % 3 - 3;
14700
+ warningStartDate.setUTCHours(flooredHour);
14701
+ var minTime = Math.min(defaultStart.getTime(), warningStartDate.getTime());
14702
+ // End is bound by the last warning
14703
+ return {
14704
+ timelineStart: new Date(minTime),
14705
+ timelineEnd: new Date(warningMax)
14706
+ };
14707
+ }, [timelineWarnings]),
14708
+ timelineStart = _React$useMemo.timelineStart,
14709
+ timelineEnd = _React$useMemo.timelineEnd;
14710
+ var totalMs = timelineEnd.getTime() - timelineStart.getTime();
14711
+ var totalHours = totalMs / MS_PER_HOUR;
14712
+ var contentWidth = Math.max(containerWidth, totalHours * PIXELS_PER_HOUR);
14713
+ var fullWidth = contentWidth + 2 * EDGE_PADDING;
14714
+ var ticks = generateTicks(timelineStart, timelineEnd);
14715
+ var _React$useState3 = React.useState(null),
14716
+ hoverTimelineX = _React$useState3[0],
14717
+ setHoverTimelineX = _React$useState3[1];
14718
+ var hoverTime = hoverTimelineX !== null ? getTimeFromX(hoverTimelineX, timelineStart, timelineEnd, contentWidth).toLocaleString('en-GB', {
14719
+ day: 'numeric',
14720
+ month: 'short',
14721
+ hour: '2-digit',
14722
+ minute: '2-digit',
14723
+ timeZone: 'UTC'
14724
+ }) + " UTC" : '';
14725
+ var handleTimeAxisMouseMove = React.useCallback(function (event) {
14726
+ var _timeAxisRef$current$, _timeAxisRef$current;
14727
+ var rect = event.currentTarget.getBoundingClientRect();
14728
+ // Only show tooltip when mouse is below the top 10px (away from scrollbar)
14729
+ if (event.clientY - rect.top < 10) {
14730
+ setHoverTimelineX(null);
14731
+ return;
14732
+ }
14733
+ setHoverTimelineX(event.clientX - rect.left + ((_timeAxisRef$current$ = (_timeAxisRef$current = timeAxisRef.current) == null ? void 0 : _timeAxisRef$current.scrollLeft) != null ? _timeAxisRef$current$ : 0));
14734
+ }, []);
14735
+ var handleTimeAxisMouseLeave = React.useCallback(function () {
14736
+ setHoverTimelineX(null);
14737
+ }, []);
14738
+ var currentTimeX = getTimelineX(now, timelineStart, timelineEnd, contentWidth);
14739
+ var showCurrentTime = now.getTime() >= timelineStart.getTime() && now.getTime() <= timelineEnd.getTime();
14740
+ return jsxs(Box$1, {
14741
+ sx: {
14742
+ width: '100%',
14743
+ height: '100%',
14744
+ display: 'flex',
14745
+ flexDirection: 'column'
14746
+ },
14747
+ children: [jsx(Box$1, {
14748
+ onScroll: handleWarningsScroll,
14749
+ ref: warningsAreaRef,
14750
+ sx: {
14751
+ flex: 1,
14752
+ overflow: 'auto',
14753
+ minHeight: 0
14754
+ },
14755
+ children: jsx(Box$1, {
14756
+ sx: {
14757
+ width: fullWidth,
14758
+ position: 'relative'
14759
+ },
14760
+ children: jsxs(Box$1, {
14761
+ sx: {
14762
+ position: 'relative',
14763
+ height: Math.max(timelineWarnings.length * WARNING_BLOCK_HEIGHT, DEFAULT_VISIBLE_ROWS * WARNING_BLOCK_HEIGHT)
14764
+ },
14765
+ children: [ticks.map(function (tick) {
14766
+ var x = getTimelineX(tick.time, timelineStart, timelineEnd, contentWidth);
14767
+ var lineStyle = getTickLineStyle(tick.type);
14768
+ return jsx(Box$1, {
14769
+ sx: Object.assign({
14770
+ position: 'absolute',
14771
+ left: x,
14772
+ top: 0,
14773
+ bottom: 0
14774
+ }, lineStyle)
14775
+ }, tick.time.toISOString());
14776
+ }), showCurrentTime ? jsx(Box$1, {
14777
+ sx: {
14778
+ position: 'absolute',
14779
+ left: currentTimeX,
14780
+ top: 0,
14781
+ bottom: 0,
14782
+ width: '3px',
14783
+ bgcolor: '#0051DD',
14784
+ zIndex: 10
14785
+ }
14786
+ }) : null, timelineWarnings.map(function (warning, index) {
14787
+ var warningDetail = warning.warningDetail;
14788
+ var validFrom = new Date(warningDetail.validFrom);
14789
+ var validUntil = new Date(warningDetail.validUntil);
14790
+ var left = getTimelineX(validFrom, timelineStart, timelineEnd, contentWidth);
14791
+ var right = getTimelineX(validUntil, timelineStart, timelineEnd, contentWidth);
14792
+ var blockWidth = Math.max(0, right - left);
14793
+ return jsx(WarningBlock, {
14794
+ left: left,
14795
+ top: index * WARNING_BLOCK_HEIGHT,
14796
+ warning: warning,
14797
+ width: blockWidth
14798
+ }, warning.id);
14799
+ })]
14800
+ })
14801
+ })
14802
+ }), jsx(Tooltip$1, {
14803
+ enterDelay: 150,
14804
+ followCursor: true,
14805
+ leaveDelay: 0,
14806
+ placement: "top",
14807
+ slotProps: {
14808
+ popper: {
14809
+ sx: {
14810
+ pointerEvents: 'none'
14811
+ }
14812
+ }
14813
+ },
14814
+ title: hoverTime,
14815
+ children: jsx(Box$1, {
14816
+ onMouseLeave: handleTimeAxisMouseLeave,
14817
+ onMouseMove: handleTimeAxisMouseMove,
14818
+ ref: timeAxisRef,
14819
+ sx: {
14820
+ height: TIMELINE_BAR_HEIGHT,
14821
+ overflow: 'hidden',
14822
+ borderTop: '1px solid #ccc'
14823
+ },
14824
+ children: jsx(Box$1, {
14825
+ sx: {
14826
+ width: fullWidth,
14827
+ position: 'relative',
14828
+ height: '100%'
14829
+ },
14830
+ children: ticks.filter(function (tick) {
14831
+ return tick.type === 'day' || tick.time.getUTCHours() % 3 === 0;
14832
+ }).map(function (tick) {
14833
+ var x = getTimelineX(tick.time, timelineStart, timelineEnd, contentWidth);
14834
+ var hour = tick.time.getUTCHours();
14835
+ var hourLabel = String(hour).padStart(2, '0') + ":00";
14836
+ var isDayBoundary = tick.type === 'day';
14837
+ var dateStr = tick.time.toLocaleDateString('en-GB', {
14838
+ day: 'numeric',
14839
+ month: 'short',
14840
+ timeZone: 'UTC'
14841
+ });
14842
+ return jsxs(Box$1, {
14843
+ sx: {
14844
+ position: 'absolute',
14845
+ left: x,
14846
+ top: 2,
14847
+ transform: 'translateX(-50%)',
14848
+ textAlign: 'center',
14849
+ lineHeight: 1.1
14850
+ },
14851
+ children: [jsx(Box$1, {
14852
+ component: "span",
14853
+ sx: {
14854
+ fontSize: isDayBoundary ? 14 : 12,
14855
+ fontWeight: isDayBoundary ? 'bold' : 'normal',
14856
+ color: isDayBoundary ? '#333' : '#666'
14857
+ },
14858
+ children: hourLabel
14859
+ }), isDayBoundary ? jsx(Box$1, {
14860
+ sx: {
14861
+ fontSize: 12,
14862
+ color: '#666'
14863
+ },
14864
+ children: dateStr
14865
+ }) : null]
14866
+ }, "label-" + tick.time.toISOString());
14867
+ })
14868
+ })
14869
+ })
14870
+ })]
14871
+ });
14872
+ };
14873
+
14874
+ var WarningsTimelineConnect = function WarningsTimelineConnect(_ref) {
14875
+ _ref.panelId;
14876
+ var _useWarningsTranslati = useWarningsTranslation(),
14877
+ t = _useWarningsTranslati.t;
14878
+ var _useAuthenticationCon = useAuthenticationContext$1(),
14879
+ isLoggedIn = _useAuthenticationCon.isLoggedIn;
14880
+ var warnings = [];
14881
+ if (!isLoggedIn) {
14882
+ return jsx(AlertBanner, {
14883
+ dataTestId: "warnings-timeline-auth-error",
14884
+ severity: "error",
14885
+ title: t('error-auth-login')
14886
+ });
14887
+ }
14888
+ return jsx(WarningsTimeline, {
14889
+ warnings: warnings
14890
+ });
14891
+ };
14892
+
14893
+ export { DrawingToolConnect, Wrapper as DrawingToolForm, DrawingToolFormConnect, DrawingToolMapButtonConnect, ObjectManagerConnect, ObjectManagerMapButtonConnect, PublicWarningsFormDialog, PublicWarningsFormDialogConnect, WARN_NAMESPACE, WarningsTimeline, WarningsTimelineConnect, componentsLookUp, createMockStore, isAlreadyEdited, selectors as publicWarningsSelectors, useObjectDrawDialogAction, warningFormConfirmationOptions, warningsDrawingsActions, warningsDrawingsReducer, warningsFiltersActions, warningsFiltersReducer, warningsFormActions, warningsFormListener, warningsFormReducer, warningsMiddlewares, warningsReducersMap, warningsTranslations };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeoweb/warnings",
3
- "version": "15.2.0",
3
+ "version": "16.0.0",
4
4
  "description": "GeoWeb warinings library for the opengeoweb project",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -8,24 +8,24 @@
8
8
  "url": "git@gitlab.com:opengeoweb/opengeoweb.git"
9
9
  },
10
10
  "dependencies": {
11
- "@opengeoweb/api": "15.2.0",
12
- "@opengeoweb/shared": "15.2.0",
13
- "@opengeoweb/store": "15.2.0",
14
- "@opengeoweb/webmap-react": "15.2.0",
11
+ "@opengeoweb/api": "16.0.0",
12
+ "@opengeoweb/shared": "16.0.0",
13
+ "@opengeoweb/store": "16.0.0",
14
+ "@opengeoweb/webmap-react": "16.0.0",
15
15
  "@tanstack/react-query": "^5.85.5",
16
16
  "react-redux": "^9.2.0",
17
- "@opengeoweb/theme": "15.2.0",
18
- "@opengeoweb/form-fields": "15.2.0",
17
+ "@opengeoweb/theme": "16.0.0",
18
+ "@opengeoweb/form-fields": "16.0.0",
19
19
  "react-hook-form": "^7.50.1",
20
20
  "lodash": "^4.17.21",
21
21
  "@reduxjs/toolkit": "^2.6.1",
22
- "@opengeoweb/snackbar": "15.2.0",
22
+ "@opengeoweb/snackbar": "16.0.0",
23
23
  "react-window": "^2.2.6",
24
24
  "axios": "^1.7.7",
25
- "@opengeoweb/core": "15.2.0",
26
- "@opengeoweb/webmap": "15.2.0",
27
- "@opengeoweb/authentication": "15.2.0",
28
- "@opengeoweb/sigmet-airmet": "15.2.0",
25
+ "@opengeoweb/core": "16.0.0",
26
+ "@opengeoweb/webmap": "16.0.0",
27
+ "@opengeoweb/authentication": "16.0.0",
28
+ "@opengeoweb/sigmet-airmet": "16.0.0",
29
29
  "react-i18next": "^15.1.1",
30
30
  "i18next": "^25.0.1",
31
31
  "@mui/material": "^7.0.1",
package/src/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export * from './lib/components/DrawingTool';
4
4
  export * from './lib/components/DrawingToolForm';
5
5
  export * from './lib/components/PublicWarningsFormDialog';
6
6
  export * from './lib/components/ComponentsLookUp';
7
+ export * from './lib/components/WarningsTimeline';
7
8
  export * from './lib/store';
8
9
  export { WARN_NAMESPACE } from './lib/utils/i18n';
9
10
  export { warningsTranslations };
@@ -1,6 +1,7 @@
1
1
  import type { FeatureCollection } from 'geojson';
2
2
  import React from 'react';
3
3
  import type { MapPreset } from '@opengeoweb/store';
4
+ export declare const EXTENT_PADDING = 50;
4
5
  interface WarningsMapViewProps {
5
6
  geojsonFeature?: FeatureCollection | undefined;
6
7
  defaultMapPreset?: MapPreset;
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import type { Warning } from '../../store/warningsForm/types';
3
+ interface WarningBlockProps {
4
+ warning: Warning;
5
+ left: number;
6
+ top: number;
7
+ width: number;
8
+ }
9
+ export declare const WarningBlock: React.FC<WarningBlockProps>;
10
+ export {};
@@ -0,0 +1,6 @@
1
+ import React from 'react';
2
+ import type { Warning } from '../../store/warningsForm/types';
3
+ export interface WarningsTimelineProps {
4
+ warnings?: Warning[];
5
+ }
6
+ export declare const WarningsTimeline: React.FC<WarningsTimelineProps>;
@@ -0,0 +1,12 @@
1
+ import type { StoryObj } from '@storybook/react-webpack5';
2
+ import { WarningsTimeline } from './WarningsTimeline';
3
+ declare const _default: {
4
+ title: string;
5
+ component: import("react").FC<import("./WarningsTimeline").WarningsTimelineProps>;
6
+ tags: string[];
7
+ };
8
+ export default _default;
9
+ type Story = StoryObj<typeof WarningsTimeline>;
10
+ export declare const ShortRange: Story;
11
+ export declare const LongRange: Story;
12
+ export declare const NoWarnings: Story;
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ export interface WarningsTimelineConnectProps {
3
+ panelId: string;
4
+ }
5
+ export declare const WarningsTimelineConnect: React.FC<WarningsTimelineConnectProps>;
@@ -0,0 +1,4 @@
1
+ export { WarningsTimeline } from './WarningsTimeline';
2
+ export type { WarningsTimelineProps } from './WarningsTimeline';
3
+ export { WarningsTimelineConnect } from './WarningsTimelineConnect';
4
+ export type { WarningsTimelineConnectProps } from './WarningsTimelineConnect';
@@ -0,0 +1,16 @@
1
+ import { PublicWarningStatus } from '../../store/warningsForm/types';
2
+ import { WarningLevel } from '../PublicWarningsForm/LevelField';
3
+ /**
4
+ * Timeline Block Color Theme
5
+ *
6
+ * Organized by warning type (public warnings by level, aviation)
7
+ * Each type has colors for each status: published, draft, expired
8
+ */
9
+ export interface BlockStyle {
10
+ background: string;
11
+ border: string;
12
+ borderColor: string;
13
+ iconColor: string;
14
+ letterColor: string;
15
+ }
16
+ export declare const getBlockStyle: (level: WarningLevel | null, status: PublicWarningStatus | undefined, isAviation: boolean) => BlockStyle;
@@ -0,0 +1,15 @@
1
+ export declare const EDGE_PADDING = 24;
2
+ export type TickType = 'day' | 'major' | 'dashed';
3
+ export interface Tick {
4
+ time: Date;
5
+ type: TickType;
6
+ }
7
+ export type BlockSize = 'xxs' | 'xs' | 's' | 'l';
8
+ export declare const getTimelineX: (targetTime: Date, timelineStart: Date, timelineEnd: Date, drawableWidth: number) => number;
9
+ export declare const getTimeFromX: (x: number, timelineStart: Date, timelineEnd: Date, drawableWidth: number) => Date;
10
+ export declare const generateTicks: (timelineStart: Date, timelineEnd: Date) => Tick[];
11
+ export declare const getTickLineStyle: (tickType: TickType) => {
12
+ width: string;
13
+ borderLeft: string;
14
+ };
15
+ export declare const getBlockSize: (width: number) => BlockSize;