@opengeoweb/sigmet-airmet 9.25.3 → 9.27.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
@@ -8,7 +8,7 @@ import { useApiContext, useApi, createApiInstance, createNonAuthApiInstance, cre
8
8
  import { defaultGeoJSONStyleProperties, defaultIntersectionStyleProperties, defaultPoint, addGeoJSONProperties, defaultBox, defaultPolygon, DRAWMODE, addSelectionTypeToGeoJSON, defaultDelete, getIcon, MapControls, MapViewLayer, useMapDrawTool, addFeatureProperties, rewindGeometry } from '@opengeoweb/webmap-react';
9
9
  import i18n from 'i18next';
10
10
  import { useTranslation } from 'react-i18next';
11
- import { dateUtils, ToggleMenu, CustomTooltip, useIsMounted, StatusTag, AlertBanner, ConfirmationServiceProvider, usePreventBrowserClose, useConfirmationDialog, isAxiosError, getAxiosErrorMessage, usePoller, ErrorBoundary } from '@opengeoweb/shared';
11
+ import { PROJECTION, dateUtils, ToggleMenu, CustomTooltip, useIsMounted, StatusTag, AlertBanner, ConfirmationServiceProvider, usePreventBrowserClose, useConfirmationDialog, isAxiosError, getAxiosErrorMessage, usePoller, ErrorBoundary } from '@opengeoweb/shared';
12
12
  import { LayerManagerMapButtonConnect, LegendMapButtonConnect, MultiDimensionSelectMapButtonsConnect, MapViewConnect, TimeSliderConnect, LegendConnect, LayerManagerConnect } from '@opengeoweb/core';
13
13
  import { DrawFIRLand, ChevronLeft, Edit, Success, Clock } from '@opengeoweb/theme';
14
14
  import { LayerType, webmapUtils } from '@opengeoweb/webmap';
@@ -2890,7 +2890,7 @@ const srsAndBboxDefault = {
2890
2890
  top: 11688874,
2891
2891
  bottom: 5930186
2892
2892
  },
2893
- srs: 'EPSG:3857'
2893
+ srs: PROJECTION.EPSG_3857.value
2894
2894
  };
2895
2895
  const featurePropsStart = defaultGeoJSONStyleProperties;
2896
2896
  const featurePropsEnd = {
@@ -2957,9 +2957,6 @@ const getMaxHoursOfValidity = (phenomenon, fir, config) => {
2957
2957
  const getValidFromDelayTimeMinutesFromConfig = config => {
2958
2958
  return config.valid_from_delay_minutes;
2959
2959
  };
2960
- const getDefaultValidityMinutesFromConfig = config => {
2961
- return config.default_validity_minutes;
2962
- };
2963
2960
  const getOmitChangeFromConfig = config => {
2964
2961
  return config.omit_change_va_and_rdoact_cloud === true;
2965
2962
  };
@@ -4329,7 +4326,7 @@ const Progress = ({
4329
4326
  const intersectingPolygonPointsTotal = interceptionGeometry && interceptionGeometry.coordinates[0] ? interceptionGeometry.coordinates[0].length : 0;
4330
4327
  const showMaxFeaturePointsWarning = intersectionPointCount > 7 && hasMaxFeaturePoints(geoJSONIntersection, maxPoints) && !activeTool && !errors.startGeometry && !isFir(geoJSON);
4331
4328
  const showMoreThan6PointsWarning = totalDrawnPoints > 7 && intersectionPointCount < 1 && !activeTool && !errors.startGeometry && !isFir(geoJSON);
4332
- const showIntersectionAbove6PointsWarning = intersectingPolygonPointsTotal > 7 && intersectionPointCount > 6 && maxPoints > 7 && !activeTool && !errors.startGeometry && !isFir(geoJSON);
4329
+ const showIntersectionAbove6PointsWarning = intersectingPolygonPointsTotal > 7 && intersectionPointCount > 1 && maxPoints > 7 && !activeTool && !errors.startGeometry && !isFir(geoJSON);
4333
4330
  return jsx(ProductFormFieldLayout, Object.assign({
4334
4331
  title: t('progress'),
4335
4332
  sx: styles$2.containerItem
@@ -4686,7 +4683,7 @@ const StartGeometry = ({
4686
4683
  const intersectingPolygonPointsTotal = interceptionGeometry && interceptionGeometry.coordinates[0] ? interceptionGeometry.coordinates[0].length : 0;
4687
4684
  const showMaxFeaturePointsWarning = intersectionPointCount > 7 && hasMaxFeaturePoints(geoJSONIntersection, maxPoints) && !activeTool && !errors.startGeometry && !isFir(geoJSON);
4688
4685
  const showMoreThan6PointsWarning = totalDrawnPoints > 7 && intersectionPointCount < 1 && !activeTool && !errors.startGeometry && !isFir(geoJSON);
4689
- const showIntersectionAbove6PointsWarning = intersectingPolygonPointsTotal > 7 && intersectionPointCount > 6 && maxPoints > 7 && !activeTool && !errors.startGeometry && !isFir(geoJSON);
4686
+ const showIntersectionAbove6PointsWarning = intersectingPolygonPointsTotal > 7 && intersectionPointCount > 1 && maxPoints > 7 && !activeTool && !errors.startGeometry && !isFir(geoJSON);
4690
4687
  return !_isReadOnly ? jsxs(ProductFormFieldLayout, Object.assign({
4691
4688
  title: t('start-position'),
4692
4689
  sx: styles$2.drawSection,
@@ -4798,9 +4795,16 @@ const getValidFromXHoursBeforeMessage = hours => translateKeyOutsideComponents('
4798
4795
  });
4799
4796
  const getDefaultValidFromValue = productConfig => {
4800
4797
  const validFromDelayTimeMinutes = getValidFromDelayTimeMinutesFromConfig(productConfig);
4801
- return dateUtils.dateToString(dateUtils.add(dateUtils.utc(), {
4798
+ const dateWithDelay = dateUtils.add(dateUtils.utc(), {
4802
4799
  minutes: validFromDelayTimeMinutes
4803
- }));
4800
+ });
4801
+ const minutes = dateWithDelay.getUTCMinutes();
4802
+ // Calculate the minutes needed to round up to the next half hour
4803
+ const extraMinutes = minutes <= 30 ? 30 - minutes : 60 - minutes;
4804
+ const roundedDate = dateUtils.add(dateWithDelay, {
4805
+ minutes: extraMinutes
4806
+ });
4807
+ return dateUtils.dateToString(roundedDate);
4804
4808
  };
4805
4809
  const ValidFrom = ({
4806
4810
  productConfig,
@@ -4849,12 +4853,16 @@ const ValidFrom = ({
4849
4853
  }));
4850
4854
  };
4851
4855
 
4852
- const getDefaultValidUntilValue = productConfig => {
4853
- const defaultValidityMinutes = getDefaultValidityMinutesFromConfig(productConfig);
4854
- const validFromDelayTimeMinutes = getValidFromDelayTimeMinutesFromConfig(productConfig);
4855
- return dateUtils.dateToString(dateUtils.add(dateUtils.utc(), {
4856
- minutes: defaultValidityMinutes + validFromDelayTimeMinutes
4857
- }));
4856
+ const getDefaultValidUntilValue = (productConfig, phenomenon, fir, validFrom) => {
4857
+ const maxHoursOfValidity = getMaxHoursOfValidity(phenomenon, fir || '', productConfig);
4858
+ // Set default validity to 2 hours for thunderstorms, otherwise use maxHoursOfValidity
4859
+ const defaultHoursOfValidity = ['EMBD_TS', 'EMBD_TSGR', 'FRQ_TS', 'FRQ_TSGR', 'OBSC_TS', 'OBSC_TSGR', 'SQL_TSGR', 'ISOL_TS', 'ISOL_TSGR', 'OCNL_TS', 'OCNL_TSGR'].includes(phenomenon) ? 2 : maxHoursOfValidity;
4860
+ // Use validFrom if provided, otherwise use current UTC time
4861
+ const baseDate = validFrom ? new Date(validFrom) : dateUtils.utc();
4862
+ const dateWithValidity = dateUtils.add(baseDate, {
4863
+ hours: defaultHoursOfValidity
4864
+ });
4865
+ return dateUtils.dateToString(dateWithValidity);
4858
4866
  };
4859
4867
  const ValidUntil = ({
4860
4868
  productConfig,
@@ -4867,13 +4875,33 @@ const ValidUntil = ({
4867
4875
  } = useSigmetAirmetTranslation();
4868
4876
  const {
4869
4877
  getValues,
4870
- trigger
4878
+ trigger,
4879
+ watch,
4880
+ setValue
4871
4881
  } = useFormContext();
4872
4882
  const {
4873
4883
  isRequired
4874
4884
  } = useDraftFormHelpers();
4875
4885
  const dateAndTime = t('date-and-time');
4876
4886
  const label = getFieldLabel(dateAndTime, isReadOnly);
4887
+ const [defaultValidUntilValue, setDefaultValidUntilValue] = React__default.useState(getDefaultValidUntilValue(productConfig, getValues('phenomenon'), getValues('locationIndicatorATSR'), getValues('validDateStart')));
4888
+ const phenomenon = watch('phenomenon');
4889
+ const locationIndicatorATSR = watch('locationIndicatorATSR');
4890
+ const validFrom = watch('validDateStart');
4891
+ React__default.useEffect(() => {
4892
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
4893
+ const updateValues = () => {
4894
+ const newDefaultValidUntilValue = getDefaultValidUntilValue(productConfig, phenomenon, locationIndicatorATSR, validFrom);
4895
+ if (newDefaultValidUntilValue !== defaultValidUntilValue) {
4896
+ setDefaultValidUntilValue(newDefaultValidUntilValue);
4897
+ setValue('validDateEnd', newDefaultValidUntilValue, {
4898
+ shouldValidate: false
4899
+ });
4900
+ trigger('validDateEnd');
4901
+ }
4902
+ };
4903
+ updateValues();
4904
+ }, [phenomenon, locationIndicatorATSR, validFrom, setValue, productConfig, trigger, defaultValidUntilValue]);
4877
4905
  return jsx(ProductFormFieldLayout, Object.assign({
4878
4906
  title: t('valid-until')
4879
4907
  }, {
@@ -4881,14 +4909,12 @@ const ValidUntil = ({
4881
4909
  disablePast: true,
4882
4910
  name: "validDateEnd",
4883
4911
  label: label,
4884
- defaultNullValue: getDefaultValidUntilValue(productConfig),
4912
+ defaultNullValue: defaultValidUntilValue,
4885
4913
  rules: {
4886
4914
  validate: {
4887
4915
  isRequired,
4888
4916
  isValidDate: dateUtils.isValidIsoDateString,
4889
- // Validity end has to be after validity start
4890
4917
  isAfter: value => value ? dateUtils.isAfter(value, getValues('validDateStart')) || t('valid-until-time') : true,
4891
- // Validity end can be no more than 4 hours after validity start (6 for VA/TC SIGMET)
4892
4918
  isXHoursAfter: value => isXHoursAfter(value, getValues('validDateStart'), getMaxHoursOfValidity(getValues('phenomenon'), getValues('locationIndicatorATSR'), productConfig)) || t('valid-until-time-error', {
4893
4919
  hours: getMaxHoursOfValidity(getValues('phenomenon'), getValues('locationIndicatorATSR'), productConfig)
4894
4920
  })
@@ -4897,11 +4923,13 @@ const ValidUntil = ({
4897
4923
  disabled: isDisabled,
4898
4924
  isReadOnly: isReadOnly,
4899
4925
  onChange: () => {
4926
+ // Trigger validation after any change
4900
4927
  triggerValidations(['validDateStart', 'observationOrForecastTime'], getValues, trigger);
4901
4928
  _onChange();
4902
4929
  },
4930
+ "data-testid": "valid-until",
4903
4931
  sx: styles$2.helperText
4904
- })
4932
+ }, defaultValidUntilValue)
4905
4933
  }));
4906
4934
  };
4907
4935
 
@@ -5702,11 +5730,28 @@ const useTAC = (initialProduct, getTAC, hasErrors = () => false, omitChange) =>
5702
5730
  };
5703
5731
  return [TAC, delayedQuery];
5704
5732
  };
5733
+ const getSequenceStyling = (product, hasTac = false) => {
5734
+ if (hasTac && !product || product && product.status === 'DRAFT') {
5735
+ return {
5736
+ fontWeight: 'lighter',
5737
+ color: 'geowebColors.typographyAndIcons.inactiveText'
5738
+ };
5739
+ }
5740
+ return {};
5741
+ };
5705
5742
  const ProductFormTAC = ({
5706
- tac
5743
+ tac,
5744
+ product
5707
5745
  }) => {
5746
+ var _a;
5747
+ const {
5748
+ t
5749
+ } = useSigmetAirmetTranslation();
5750
+ const noTAC = t('tac-missing-data');
5708
5751
  const tacLines = tac.split('\n');
5709
- const hasTac = tacLines.length && tacLines.toString() !== noTAC;
5752
+ const hasTac = tacLines.length > 0 && tac !== noTAC;
5753
+ const sequenceNumberInTac = hasTac ? (_a = tacLines[0].split(' ')[2]) !== null && _a !== void 0 ? _a : null : null;
5754
+ const sequenceStyle = getSequenceStyling(product, hasTac);
5710
5755
  return jsx(Typography, Object.assign({
5711
5756
  variant: "body2",
5712
5757
  component: "div",
@@ -5716,21 +5761,24 @@ const ProductFormTAC = ({
5716
5761
  },
5717
5762
  "data-testid": "productform-tac-message"
5718
5763
  }, {
5719
- children: tacLines.map(line => jsx(Box, Object.assign({
5764
+ children: jsx(Box, Object.assign({
5720
5765
  component: "p",
5721
5766
  sx: {
5722
5767
  margin: 0,
5723
- fontSize: hasTac ? '1.125rem' : '1rem',
5768
+ fontSize: '1.125rem',
5724
5769
  fontWeight: 'normal',
5725
- fontStretch: 'normal',
5726
- fontStyle: 'normal',
5727
5770
  lineHeight: 1.56,
5728
5771
  letterSpacing: '0.5px'
5729
5772
  },
5730
5773
  "data-testid": "productform-tac-message-line"
5731
5774
  }, {
5732
- children: line
5733
- }), line))
5775
+ children: tac.split(' ').map((word, index) => jsx(Box, Object.assign({
5776
+ component: "span",
5777
+ sx: hasTac && word === sequenceNumberInTac ? sequenceStyle : {}
5778
+ }, {
5779
+ children: word + (index < tac.split(' ').length - 1 ? ' ' : '')
5780
+ }), index))
5781
+ }))
5734
5782
  }));
5735
5783
  };
5736
5784
 
@@ -5769,7 +5817,8 @@ const IssuedAt = ({
5769
5817
 
5770
5818
  const Tac = ({
5771
5819
  tac,
5772
- children
5820
+ children,
5821
+ product
5773
5822
  }) => {
5774
5823
  return jsx(ProductFormFieldLayout, Object.assign({
5775
5824
  title: "TAC",
@@ -5782,7 +5831,8 @@ const Tac = ({
5782
5831
  xs: 12
5783
5832
  }, {
5784
5833
  children: [jsx(ProductFormTAC, {
5785
- tac: tac
5834
+ tac: tac,
5835
+ product: product
5786
5836
  }), children]
5787
5837
  }))
5788
5838
  }));
@@ -10002,7 +10052,8 @@ const SigmetForm = ({
10002
10052
  initialCancelSigmet: _initialCancelSigmet = null,
10003
10053
  showMap: _showMap = true,
10004
10054
  productConfig: _productConfig = sigmetConfig,
10005
- setDialogActionsDisabled
10055
+ setDialogActionsDisabled,
10056
+ product
10006
10057
  }) => {
10007
10058
  const {
10008
10059
  t
@@ -10251,7 +10302,8 @@ const SigmetForm = ({
10251
10302
  date: getProductIssueDate(_initialSigmet, _initialCancelSigmet),
10252
10303
  isReadOnly: isReadOnly
10253
10304
  }), jsxs(Tac, Object.assign({
10254
- tac: tac
10305
+ tac: tac,
10306
+ product: product
10255
10307
  }, {
10256
10308
  children: [jsx(ReactHookFormHiddenInput, {
10257
10309
  name: "sequence",
@@ -10334,7 +10386,8 @@ const AirmetForm = ({
10334
10386
  initialAirmet: _initialAirmet = null,
10335
10387
  initialCancelAirmet: _initialCancelAirmet = null,
10336
10388
  showMap: _showMap = true,
10337
- productConfig: _productConfig = airmetConfig
10389
+ productConfig: _productConfig = airmetConfig,
10390
+ product
10338
10391
  }) => {
10339
10392
  const {
10340
10393
  api
@@ -10524,7 +10577,8 @@ const AirmetForm = ({
10524
10577
  isReadOnly: isReadOnly,
10525
10578
  date: getProductIssueDate(_initialAirmet, _initialCancelAirmet)
10526
10579
  }), jsxs(Tac, Object.assign({
10527
- tac: tac
10580
+ tac: tac,
10581
+ product: product
10528
10582
  }, {
10529
10583
  children: [jsx(ReactHookFormHiddenInput, {
10530
10584
  name: "sequence",
@@ -11306,13 +11360,15 @@ const ProductFormDialogContent = ({
11306
11360
  initialSigmet: product !== null && !isInstanceOfCancelSigmet(product) ? product : null,
11307
11361
  initialCancelSigmet: product !== null && isInstanceOfCancelSigmet(product) ? product : null,
11308
11362
  productConfig: productConfig,
11309
- setDialogActionsDisabled: setDialogActionsDisabled
11363
+ setDialogActionsDisabled: setDialogActionsDisabled,
11364
+ product: product
11310
11365
  }) : jsx(AirmetForm, {
11311
11366
  mode: mode,
11312
11367
  isCancelAirmet: product !== null && isInstanceOfCancelAirmet(product),
11313
11368
  initialAirmet: product !== null && !isInstanceOfCancelAirmet(product) ? product : null,
11314
11369
  initialCancelAirmet: product !== null && isInstanceOfCancelAirmet(product) ? product : null,
11315
- productConfig: productConfig
11370
+ productConfig: productConfig,
11371
+ product: product
11316
11372
  }), jsx(DraftFieldHelper, {}), jsx(Backdrop, Object.assign({
11317
11373
  "data-testid": "loader",
11318
11374
  open: showLoader,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengeoweb/sigmet-airmet",
3
- "version": "9.25.3",
3
+ "version": "9.27.0",
4
4
  "description": "GeoWeb Sigmet/Airmet library for the opengeoweb project",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -30,7 +30,9 @@
30
30
  "react-i18next": "^14.1.2"
31
31
  },
32
32
  "peerDependencies": {
33
- "react": "18"
33
+ "react": "18",
34
+ "@emotion/react": "*",
35
+ "@emotion/styled": "*"
34
36
  },
35
37
  "module": "./index.esm.js",
36
38
  "type": "module",
@@ -5,7 +5,7 @@ export declare const srsAndBboxDefault: {
5
5
  top: number;
6
6
  bottom: number;
7
7
  };
8
- srs: string;
8
+ srs: "EPSG:3857";
9
9
  };
10
10
  export declare const simplePolygonGeoJSON: GeoJSON.FeatureCollection;
11
11
  export declare const simplePolygonGeoJSONHalfOfNL: GeoJSON.FeatureCollection;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { FormMode, Airmet, CancelAirmet, ProductConfig } from '../../../types';
2
+ import { FormMode, Airmet, CancelAirmet, ProductConfig, AviationProduct } from '../../../types';
3
3
  export interface AirmetFormProps {
4
4
  mode: FormMode;
5
5
  isCancelAirmet?: boolean;
@@ -7,6 +7,7 @@ export interface AirmetFormProps {
7
7
  initialCancelAirmet?: CancelAirmet;
8
8
  showMap?: boolean;
9
9
  productConfig?: ProductConfig;
10
+ product?: AviationProduct;
10
11
  }
11
12
  declare const AirmetForm: React.FC<AirmetFormProps>;
12
13
  export default AirmetForm;
@@ -1,7 +1,9 @@
1
1
  import React from 'react';
2
+ import { AviationProduct } from '../../../types';
2
3
  interface TacProps {
3
4
  tac: string;
4
5
  children: React.ReactNode;
6
+ product?: AviationProduct;
5
7
  }
6
8
  declare const Tac: React.FC<TacProps>;
7
9
  export default Tac;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
2
  import { ConfigurableFormFieldProps, ProductConfig } from '../../../types';
3
- export declare const getDefaultValidUntilValue: (productConfig: ProductConfig) => string;
3
+ export declare const getDefaultValidUntilValue: (productConfig: ProductConfig, phenomenon?: string, fir?: string, validFrom?: string) => string;
4
4
  declare const ValidUntil: React.FC<ConfigurableFormFieldProps>;
5
5
  export default ValidUntil;
@@ -11,6 +11,14 @@ export declare const useTAC: (initialProduct: AviationProduct, getTAC: (product:
11
11
  }>, hasErrors?: () => boolean, omitChange?: boolean) => [string, any];
12
12
  interface ProductFormTACProps {
13
13
  tac: string;
14
+ product?: AviationProduct;
14
15
  }
16
+ export declare const getSequenceStyling: (product?: ProductFormTACProps['product'], hasTac?: boolean) => {
17
+ fontWeight: string;
18
+ color: string;
19
+ } | {
20
+ fontWeight?: undefined;
21
+ color?: undefined;
22
+ };
15
23
  declare const ProductFormTAC: React.FC<ProductFormTACProps>;
16
24
  export default ProductFormTAC;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { CancelSigmet, Sigmet, FormMode, ProductConfig } from '../../../types';
2
+ import { CancelSigmet, Sigmet, FormMode, ProductConfig, AviationProduct } from '../../../types';
3
3
  export interface SigmetFormProps {
4
4
  mode: FormMode;
5
5
  isCancelSigmet?: boolean;
@@ -8,6 +8,7 @@ export interface SigmetFormProps {
8
8
  showMap?: boolean;
9
9
  productConfig?: ProductConfig;
10
10
  setDialogActionsDisabled?: (disabled: boolean) => void;
11
+ product?: AviationProduct;
11
12
  }
12
13
  declare const SigmetForm: React.FC<SigmetFormProps>;
13
14
  export default SigmetForm;