geonetwork-ui 2.11.0-dev.1cf4ab0c6 → 2.11.0-dev.30db8c2d6

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.
Files changed (67) hide show
  1. package/fesm2022/geonetwork-ui.mjs +1415 -1282
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +165 -90
  4. package/index.d.ts.map +1 -1
  5. package/package.json +6 -5
  6. package/src/libs/api/metadata-converter/src/lib/dcat-ap/dcat-ap.converter.ts +2 -0
  7. package/src/libs/api/metadata-converter/src/lib/fixtures/mel.records.dataset+featurecatalog.ts +317 -0
  8. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +35 -8
  9. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +19 -0
  10. package/src/libs/api/metadata-converter/src/lib/iso19115-3/iso19115-3.converter.ts +2 -0
  11. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +98 -0
  12. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +7 -0
  13. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +2 -1
  14. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +67 -10
  15. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +5 -34
  16. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +6 -13
  17. package/src/libs/common/domain/src/lib/model/search/aggregation.model.ts +2 -0
  18. package/src/libs/common/domain/src/lib/model/search/filter.model.ts +12 -2
  19. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +1 -1
  20. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +42 -62
  21. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +32 -19
  22. package/src/libs/feature/map/src/index.ts +0 -2
  23. package/src/libs/feature/map/src/lib/feature-map.module.ts +1 -8
  24. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +8 -3
  25. package/src/libs/feature/record/src/lib/state/mdview.effects.ts +3 -1
  26. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +1 -1
  27. package/src/libs/feature/search/src/index.ts +2 -0
  28. package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.html +7 -1
  29. package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.ts +26 -4
  30. package/src/libs/feature/search/src/lib/geocoding/geocoding.service.ts +105 -0
  31. package/src/libs/feature/search/src/lib/location-search/location-search.component.html +18 -0
  32. package/src/libs/feature/search/src/lib/location-search/location-search.component.ts +114 -0
  33. package/src/libs/feature/search/src/lib/search-filters-summary-item/search-filters-summary-item.component.ts +1 -0
  34. package/src/libs/feature/search/src/lib/state/reducer.ts +1 -4
  35. package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +56 -4
  36. package/src/libs/feature/search/src/lib/utils/service/fields.ts +58 -16
  37. package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.html +2 -2
  38. package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.ts +2 -2
  39. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.css +0 -4
  40. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +12 -3
  41. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +11 -3
  42. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +7 -4
  43. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +12 -9
  44. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.model.ts +2 -2
  45. package/src/libs/ui/inputs/src/lib/search-feature-catalog/search-feature-catalog.component.ts +2 -1
  46. package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.html +8 -2
  47. package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.ts +34 -5
  48. package/src/libs/ui/layout/src/lib/block-list/block-list.component.css +1 -0
  49. package/src/libs/util/app-config/src/lib/app-config.ts +34 -0
  50. package/src/libs/util/app-config/src/lib/fixtures.ts +37 -1
  51. package/src/libs/util/app-config/src/lib/model.ts +24 -1
  52. package/src/libs/util/shared/src/lib/utils/geojson.ts +16 -0
  53. package/translations/de.json +8 -2
  54. package/translations/en.json +10 -4
  55. package/translations/es.json +8 -2
  56. package/translations/fr.json +15 -9
  57. package/translations/it.json +8 -2
  58. package/translations/nl.json +8 -2
  59. package/translations/pt.json +8 -2
  60. package/translations/sk.json +8 -2
  61. package/src/libs/feature/map/src/lib/geocoding/geocoding.component.css +0 -0
  62. package/src/libs/feature/map/src/lib/geocoding/geocoding.component.html +0 -41
  63. package/src/libs/feature/map/src/lib/geocoding/geocoding.component.ts +0 -112
  64. package/src/libs/feature/map/src/lib/geocoding.service.ts +0 -57
  65. package/src/libs/feature/map/src/lib/style/index.ts +0 -2
  66. package/src/libs/feature/map/src/lib/style/map-style.fixtures.ts +0 -47
  67. package/src/libs/feature/map/src/lib/style/map-style.service.ts +0 -108
@@ -6,7 +6,7 @@ import GeoJSON from 'ol/format/GeoJSON.js';
6
6
  import { parse as parse$1 } from 'ol/xml.js';
7
7
  import { format } from 'date-fns/format';
8
8
  import { Namespace, Literal, lit, parse as parse$2, sym, BlankNode, graph } from 'rdflib';
9
- import { lastValueFrom, fromEvent, startWith, map as map$2, shareReplay, filter, pairwise, of, switchMap, Subject, forkJoin, combineLatest, from, exhaustMap, throwError, takeLast, firstValueFrom, merge, BehaviorSubject, timer, ReplaySubject, Subscription, first, distinctUntilChanged as distinctUntilChanged$1, animationFrameScheduler, debounceTime as debounceTime$1, Observable, buffer, tap as tap$2, combineLatestWith, take as take$1, catchError as catchError$1, takeUntil, EMPTY, mergeMap as mergeMap$1, withLatestFrom as withLatestFrom$1 } from 'rxjs';
9
+ import { lastValueFrom, fromEvent, startWith, map as map$2, shareReplay, filter, pairwise, of, switchMap, Subject, forkJoin, combineLatest, from, exhaustMap, throwError, takeLast, firstValueFrom, merge, BehaviorSubject, timer, ReplaySubject, Subscription, first, distinctUntilChanged as distinctUntilChanged$1, animationFrameScheduler, debounceTime as debounceTime$1, Observable, buffer, tap as tap$2, combineLatestWith, take as take$1, catchError as catchError$1, EMPTY, mergeMap as mergeMap$1, withLatestFrom as withLatestFrom$1, takeUntil } from 'rxjs';
10
10
  import * as i0 from '@angular/core';
11
11
  import { InjectionToken, inject, Injectable, NgModule, Injector, provideAppInitializer, makeEnvironmentProviders, ElementRef, afterNextRender, booleanAttribute, Input, Directive, HostListener, Renderer2, DestroyRef, EventEmitter, Output, ViewChild, ChangeDetectionStrategy, Component, ViewEncapsulation, ChangeDetectorRef, HostBinding, ViewContainerRef, TemplateRef, ViewChildren, ContentChild, input, output, signal, viewChild, computed, ContentChildren, NgZone, ComponentFactoryResolver, viewChildren } from '@angular/core';
12
12
  import { HttpClient, HttpHeaders, HttpParams, HTTP_INTERCEPTORS, provideHttpClient, withInterceptorsFromDi, HttpEventType } from '@angular/common/http';
@@ -26,7 +26,6 @@ import { getLength } from 'ol/sphere.js';
26
26
  import { LineString } from 'ol/geom.js';
27
27
  import * as i1 from '@ngrx/store';
28
28
  import { createAction, props, createReducer, on, createFeatureSelector, createSelector, Store, select, StoreModule } from '@ngrx/store';
29
- import { queryDataGouvFr, queryGeonames, queryGeoadmin } from '@geospatial-sdk/geocoding';
30
29
  import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
31
30
  import { FeaturesClickEventType, FeaturesHoverEventType, MapClickEventType, MapExtentChangeEventType, SourceLoadErrorType, computeMapContextDiff, createViewFromLayer } from '@geospatial-sdk/core';
32
31
  import { createMapFromContext, applyContextDiffToMap, listen } from '@geospatial-sdk/openlayers';
@@ -37,11 +36,8 @@ import { createLegendFromLayer } from '@geospatial-sdk/legend';
37
36
  import { mouseOnly, noModifierKeys, primaryAction, platformModifierKeyOnly } from 'ol/events/condition.js';
38
37
  import { defaults, DragPan, MouseWheelZoom } from 'ol/interaction.js';
39
38
  import { extend } from 'ol/extent.js';
40
- import * as TOML from '@ltd/j-toml';
41
- import { Style, Stroke, Fill, Circle } from 'ol/style.js';
42
- import CircleStyle from 'ol/style/Circle.js';
43
39
  import EmblaCarousel from 'embla-carousel';
44
- import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, iconoirTrash, iconoirSquareDashed, iconoirImport, iconoirCheckCircle, iconoirReduce, iconoirNavArrowUp, iconoirNavArrowDown, iconoirExpand, iconoirSettings, iconoirDownload, iconoirPlus, iconoirBin, iconoirMediaImageXmark, iconoirMediaImage, iconoirAppWindow, iconoirCode, iconoirDatabase, iconoirAppleWallet, iconoirBank, iconoirList, iconoirTranslate, iconoirLock, iconoirUser, iconoirArrowLeft, iconoirLightBulbOn, iconoirBadgeCheck, iconoirSystemShut, iconoirCircle, iconoirAttachment, iconoirRefresh } from '@ng-icons/iconoir';
40
+ import { iconoirNavArrowLeft, iconoirNavArrowRight, iconoirLongArrowDownLeft, iconoirSearch, iconoirCalendar, iconoirArrowUp, iconoirLink, iconoirFramePlusIn, iconoirCloudUpload, iconoirUpload, iconoirTrash, iconoirSquareDashed, iconoirCheckCircle, iconoirReduce, iconoirNavArrowUp, iconoirNavArrowDown, iconoirExpand, iconoirSettings, iconoirDownload, iconoirPlus, iconoirBin, iconoirMediaImageXmark, iconoirMediaImage, iconoirAppWindow, iconoirCode, iconoirDatabase, iconoirAppleWallet, iconoirBank, iconoirList, iconoirTranslate, iconoirLock, iconoirUser, iconoirArrowLeft, iconoirLightBulbOn, iconoirImport, iconoirBadgeCheck, iconoirSystemShut, iconoirCircle, iconoirAttachment, iconoirRefresh } from '@ng-icons/iconoir';
45
41
  import { MatButtonModule } from '@angular/material/button';
46
42
  import * as i1$7 from '@angular/cdk/overlay';
47
43
  import { ScrollStrategyOptions, OverlayModule, CdkConnectedOverlay, ScrollDispatcher, Overlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
@@ -74,6 +70,8 @@ import { MatTabsModule } from '@angular/material/tabs';
74
70
  import * as i2$2 from '@ngrx/effects';
75
71
  import { Actions, createEffect, ofType, EffectsModule } from '@ngrx/effects';
76
72
  import { valid as valid$1 } from 'geojson-validation';
73
+ import { queryGeoplateforme, queryGeonames, queryGeoadmin } from '@geospatial-sdk/geocoding';
74
+ import pointer from 'jsonpointer';
77
75
  import { TemplatePortal } from '@angular/cdk/portal';
78
76
  import { parse as parse$3 } from 'marked';
79
77
  import * as i2$3 from '@angular/cdk/scrolling';
@@ -101,6 +99,7 @@ import { TextFieldModule } from '@angular/cdk/text-field';
101
99
  import * as i2$5 from '@ngrx/router-store';
102
100
  import { getRouterSelectors, routerReducer, StoreRouterConnectingModule, FullRouterStateSerializer } from '@ngrx/router-store';
103
101
  import { navigation } from '@ngrx/router-store/data-persistence';
102
+ import * as TOML from '@ltd/j-toml';
104
103
 
105
104
  class MetadataMapperContext {
106
105
  }
@@ -1139,7 +1138,7 @@ function kindToCodeListValue(record) {
1139
1138
  }
1140
1139
 
1141
1140
  function extractCharacterString() {
1142
- return pipe(fallback(findChildElement('gco:CharacterString', false), findChildElement('gmx:Anchor', false), findChildElement('gmx:MimeFileType', false)), readText());
1141
+ return pipe(fallback(findChildElement('gco:CharacterString', false), findChildElement('gmx:Anchor', false), findChildElement('gmx:MimeFileType', false), findChildElement('gco:LocalName', false)), readText());
1143
1142
  }
1144
1143
  /**
1145
1144
  * Translated values will also be collected in the translations object
@@ -2202,6 +2201,7 @@ class Iso19139Converter extends BaseConverter {
2202
2201
  lineage: readLineage$1,
2203
2202
  sourceRecords: readSourceRecords$1,
2204
2203
  associatedRecords: readAssociatedRecords$1,
2204
+ featureTypeDescriptions: () => undefined,
2205
2205
  onlineResources: readOnlineResources$2,
2206
2206
  temporalExtents: readTemporalExtents,
2207
2207
  spatialExtents: readSpatialExtents$1,
@@ -2241,6 +2241,7 @@ class Iso19139Converter extends BaseConverter {
2241
2241
  lineage: writeLineage$1,
2242
2242
  sourceRecords: writeSourceRecords$1,
2243
2243
  associatedRecords: writeAssociatedRecords$1,
2244
+ featureTypeDescriptions: () => undefined,
2244
2245
  onlineResources: writeOnlineResources$1,
2245
2246
  temporalExtents: writeTemporalExtents,
2246
2247
  spatialExtents: writeSpatialExtents,
@@ -2367,6 +2368,7 @@ class Iso19139Converter extends BaseConverter {
2367
2368
  const sourceRecords = this.readers['sourceRecords'](rootEl, tr);
2368
2369
  const associatedRecords = this.readers['associatedRecords'](rootEl, tr);
2369
2370
  const updateFrequency = this.readers['updateFrequency'](rootEl, tr);
2371
+ const featureTypeDescriptions = this.readers['featureTypeDescriptions'](rootEl, tr);
2370
2372
  return this.afterRecordRead({
2371
2373
  ...this.readBaseRecord(rootEl, tr),
2372
2374
  kind,
@@ -2377,6 +2379,7 @@ class Iso19139Converter extends BaseConverter {
2377
2379
  ...(spatialRepresentation && { spatialRepresentation }),
2378
2380
  temporalExtents,
2379
2381
  updateFrequency,
2382
+ ...(featureTypeDescriptions?.length && { featureTypeDescriptions }),
2380
2383
  translations: tr,
2381
2384
  });
2382
2385
  }
@@ -2633,6 +2636,31 @@ function readDefaultLanguage$1(rootEl) {
2633
2636
  function readOtherLanguages(rootEl) {
2634
2637
  return pipe(findChildrenElement('mdb:otherLocale', false), mapArray(readLocaleElement()), map((languages) => languages.filter((lang) => lang !== null)))(rootEl);
2635
2638
  }
2639
+ function extractCharacterStringOrText() {
2640
+ return fallback(extractCharacterString(), readText());
2641
+ }
2642
+ function extractListedValue() {
2643
+ return pipe(combine(pipe(findChildElement('gfc:code', false), extractCharacterString()), pipe(findChildElement('gfc:label', false), extractCharacterString())), map(([code, label]) => ({
2644
+ ...(code && { code }),
2645
+ ...(label && { label }),
2646
+ })));
2647
+ }
2648
+ function extractFeatureAttribute() {
2649
+ return pipe(combine(pipe(findChildElement('gfc:memberName', false), extractCharacterStringOrText()), pipe(findChildElement('gfc:definition', false), extractCharacterString()), pipe(findChildElement('gfc:code', false), extractCharacterString()), pipe(findNestedElement('gfc:valueType', 'gco:TypeName', 'gco:aName'), extractCharacterString()), pipe(findNestedElements('gfc:listedValue', 'gfc:FC_ListedValue'), mapArray(extractListedValue()), filterArray((value) => !!(value.code || value.label)))), map(([name, description, code, type, values]) => ({
2650
+ name: name ?? '',
2651
+ ...(description && { description }),
2652
+ ...(code && { code }),
2653
+ ...(type && { type }),
2654
+ ...(values.length > 0 && { values }),
2655
+ })));
2656
+ }
2657
+ function readFeatureTypeDescriptions(rootEl) {
2658
+ return pipe(findNestedElements('mdb:contentInfo', 'mrc:MD_FeatureCatalogue', 'mrc:featureCatalogue', 'gfc:FC_FeatureCatalogue', 'gfc:featureType', 'gfc:FC_FeatureType'), mapArray(pipe(combine(pipe(findChildElement('gfc:typeName', false), extractCharacterStringOrText()), pipe(findChildElement('gfc:definition', false), extractCharacterString()), pipe(findNestedElements('gfc:carrierOfCharacteristics', 'gfc:FC_FeatureAttribute'), mapArray(extractFeatureAttribute()))), map(([name, description, attributes]) => ({
2659
+ name: name ?? '',
2660
+ ...(description && { description }),
2661
+ attributes,
2662
+ })))))(rootEl);
2663
+ }
2636
2664
 
2637
2665
  function writeUniqueIdentifier$1(record, rootEl) {
2638
2666
  pipe(findNestedChildOrCreate('mdb:metadataIdentifier', 'mcc:MD_Identifier', 'mcc:code'), writeCharacterString(record.uniqueIdentifier))(rootEl);
@@ -2803,6 +2831,7 @@ class Iso191153Converter extends Iso19139Converter {
2803
2831
  this.readers['lineage'] = readLineage;
2804
2832
  this.readers['sourceRecords'] = readSourceRecords;
2805
2833
  this.readers['associatedRecords'] = readAssociatedRecords;
2834
+ this.readers['featureTypeDescriptions'] = readFeatureTypeDescriptions;
2806
2835
  this.readers['onlineResources'] = readOnlineResources$1;
2807
2836
  this.readers['defaultLanguage'] = readDefaultLanguage$1;
2808
2837
  this.readers['otherLanguages'] = readOtherLanguages;
@@ -3459,6 +3488,7 @@ class DcatApConverter extends BaseConverter {
3459
3488
  lineage: () => '',
3460
3489
  sourceRecords: () => [],
3461
3490
  associatedRecords: () => [],
3491
+ featureTypeDescriptions: () => undefined,
3462
3492
  temporalExtents: () => [],
3463
3493
  spatialRepresentation: () => undefined,
3464
3494
  extras: () => undefined,
@@ -3494,6 +3524,7 @@ class DcatApConverter extends BaseConverter {
3494
3524
  lineage: () => undefined,
3495
3525
  sourceRecords: () => [],
3496
3526
  associatedRecords: () => [],
3527
+ featureTypeDescriptions: () => undefined,
3497
3528
  onlineResources: () => undefined,
3498
3529
  temporalExtents: () => undefined,
3499
3530
  spatialExtents: () => undefined,
@@ -18904,9 +18935,15 @@ class Gn4FieldMapper {
18904
18935
  isOpenData: (output, source) => this.addExtra({
18905
18936
  isOpenData: selectField(source, 'isOpenData') !== 'false',
18906
18937
  }, output),
18907
- featureTypes: (output, source) => this.addExtra({
18908
- featureTypes: selectField(source, 'featureTypes'),
18909
- }, output),
18938
+ featureTypes: (output, source) => {
18939
+ const featureTypes = getAsArray(selectField(source, 'featureTypes'));
18940
+ if (!featureTypes.length)
18941
+ return output;
18942
+ return {
18943
+ ...output,
18944
+ featureTypeDescriptions: this.featureTypesField(featureTypes),
18945
+ };
18946
+ },
18910
18947
  related: (output, source) => {
18911
18948
  const related = selectField(source, 'related');
18912
18949
  const fcatSource = selectField(getFirstValue(selectField(related, 'fcats')) ?? {}, '_source');
@@ -19042,6 +19079,27 @@ class Gn4FieldMapper {
19042
19079
  },
19043
19080
  };
19044
19081
  this.genericField = (output) => output;
19082
+ this.featureTypesField = (featureTypes) => featureTypes.map((featureType) => ({
19083
+ name: featureType.typeName ?? '',
19084
+ ...(featureType.definition && {
19085
+ description: featureType.definition,
19086
+ }),
19087
+ attributes: getAsArray(featureType.attributeTable ?? []).map((attr) => {
19088
+ const values = (attr.values ?? [])
19089
+ .filter((value) => value.code || value.label)
19090
+ .map((value) => ({
19091
+ ...(value.code && { code: value.code }),
19092
+ ...(value.label && { label: value.label }),
19093
+ }));
19094
+ return {
19095
+ name: attr.name ?? '',
19096
+ ...(attr.definition && { description: attr.definition }),
19097
+ ...(attr.code && { code: attr.code }),
19098
+ ...(attr.type && { type: attr.type }),
19099
+ ...(values.length > 0 && { values }),
19100
+ };
19101
+ }),
19102
+ }));
19045
19103
  this.constraintField = (type, output, constraintArray) => {
19046
19104
  let outputField;
19047
19105
  switch (type) {
@@ -19596,6 +19654,19 @@ function isBoundingBox(value) {
19596
19654
  value.length === 4 &&
19597
19655
  value.every((item) => typeof item === 'number'));
19598
19656
  }
19657
+ /**
19658
+ * Checks that a bounding box's coordinates stay within the valid
19659
+ * longitude (-180/180) and latitude (-90/90) ranges.
19660
+ */
19661
+ function isBoundingBoxWithinWorldExtent(bbox) {
19662
+ const [minX, minY, maxX, maxY] = bbox;
19663
+ return (minX >= -180 &&
19664
+ maxX <= 180 &&
19665
+ minY >= -90 &&
19666
+ maxY <= 90 &&
19667
+ minX <= maxX &&
19668
+ minY <= maxY);
19669
+ }
19599
19670
  function getGeometryBoundingBox(geometry) {
19600
19671
  // use the bounding box if specified in the GeoJSON object
19601
19672
  if (geometry.bbox) {
@@ -20439,7 +20510,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
20439
20510
  }] } });
20440
20511
 
20441
20512
  var name = "geonetwork-ui";
20442
- var version = "2.11.0-dev.1cf4ab0c6";
20513
+ var version = "2.11.0-dev.30db8c2d6";
20443
20514
  var engines = {
20444
20515
  node: ">=24"
20445
20516
  };
@@ -20481,10 +20552,10 @@ var dependencies = {
20481
20552
  "@biesbjerg/ngx-translate-extract-marker": "~1.0.0",
20482
20553
  "@camptocamp/ogc-client": "1.3.1-dev.200c02a",
20483
20554
  "@duckdb/duckdb-wasm": "~1.32.0",
20484
- "@geospatial-sdk/core": "0.0.5-dev.78",
20485
- "@geospatial-sdk/geocoding": "0.0.5-dev.78",
20486
- "@geospatial-sdk/legend": "0.0.5-dev.78",
20487
- "@geospatial-sdk/openlayers": "0.0.5-dev.78",
20555
+ "@geospatial-sdk/core": "0.0.5-dev.86.sha-124eae3",
20556
+ "@geospatial-sdk/geocoding": "0.0.5-dev.86.sha-124eae3",
20557
+ "@geospatial-sdk/legend": "0.0.5-dev.86.sha-124eae3",
20558
+ "@geospatial-sdk/openlayers": "0.0.5-dev.86.sha-124eae3",
20488
20559
  "@ltd/j-toml": "~1.38.0",
20489
20560
  "@messageformat/core": "~3.4.0",
20490
20561
  "@ng-icons/core": "~32.5.0",
@@ -20501,6 +20572,7 @@ var dependencies = {
20501
20572
  "embla-carousel": "~8.6.0",
20502
20573
  "flag-icons": "~7.5.0",
20503
20574
  "geojson-validation": "~1.0.2",
20575
+ jsonpointer: "^5.0.1",
20504
20576
  marked: "~17.0.4",
20505
20577
  "ngx-dropzone": "~3.1.0",
20506
20578
  "ngx-translate-messageformat-compiler": "~7.2.0",
@@ -20677,6 +20749,7 @@ class ElasticsearchService {
20677
20749
  // runtime fields are computed using a Painless script
20678
20750
  // see: https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-mapping-fields.html
20679
20751
  this.runtimeFields = {};
20752
+ this.fieldAliases = {};
20680
20753
  }
20681
20754
  // we're using getters in case the defined languages change over time
20682
20755
  get metadataLang() {
@@ -20748,6 +20821,9 @@ class ElasticsearchService {
20748
20821
  registerRuntimeField(fieldName, expression, type = 'keyword') {
20749
20822
  this.runtimeFields[fieldName] = { script: expression, type };
20750
20823
  }
20824
+ registerFieldAlias(fieldIdentifier, esFieldName) {
20825
+ this.fieldAliases[fieldIdentifier] = esFieldName;
20826
+ }
20751
20827
  getMetadataByIdsPayload(uuids) {
20752
20828
  return {
20753
20829
  query: {
@@ -20869,6 +20945,55 @@ class ElasticsearchService {
20869
20945
  }
20870
20946
  return Object.values(filters).find(isBoundingBox);
20871
20947
  }
20948
+ // builds a query matching records whose dates intersect the filter range
20949
+ buildDateRangeQuery(searchField, dateRange) {
20950
+ // fields ending with 'DateRange' maps as ES range type
20951
+ if (searchField.endsWith('DateRange')) {
20952
+ return {
20953
+ range: {
20954
+ [searchField]: {
20955
+ ...(dateRange.start && { gte: formatDate(dateRange.start) }),
20956
+ ...(dateRange.end && { lte: formatDate(dateRange.end) }),
20957
+ format: 'yyyy-MM-dd',
20958
+ relation: 'intersects',
20959
+ },
20960
+ },
20961
+ };
20962
+ }
20963
+ const minField = `${searchField}Min`;
20964
+ const maxField = `${searchField}Max`;
20965
+ if (minField in this.runtimeFields && maxField in this.runtimeFields) {
20966
+ // min/max runtime fields form an interval per record; match if it intersects the filter range
20967
+ const filter = [
20968
+ dateRange.start && {
20969
+ range: {
20970
+ [maxField]: {
20971
+ gte: formatDate(dateRange.start),
20972
+ format: 'yyyy-MM-dd',
20973
+ },
20974
+ },
20975
+ },
20976
+ dateRange.end && {
20977
+ range: {
20978
+ [minField]: {
20979
+ lte: formatDate(dateRange.end),
20980
+ format: 'yyyy-MM-dd',
20981
+ },
20982
+ },
20983
+ },
20984
+ ].filter(Boolean);
20985
+ return { bool: { filter } };
20986
+ }
20987
+ return {
20988
+ range: {
20989
+ [searchField]: {
20990
+ ...(dateRange.start && { gte: formatDate(dateRange.start) }),
20991
+ ...(dateRange.end && { lte: formatDate(dateRange.end) }),
20992
+ format: 'yyyy-MM-dd',
20993
+ },
20994
+ },
20995
+ };
20996
+ }
20872
20997
  filtersToQuery(filters, spatialFilterExtent = this.findSpatialFilterExtent(filters)) {
20873
20998
  const addQuote = (key) => (/^\/.+\/$/.test(key) ? key : `"${key}"`);
20874
20999
  const makeQuery = (filter) => {
@@ -20893,7 +21018,7 @@ class ElasticsearchService {
20893
21018
  .filter((fieldname) => !Array.isArray(filters[fieldname]))
20894
21019
  .filter((fieldname) => filters[fieldname] &&
20895
21020
  JSON.stringify(filters[fieldname]) !== '{}')
20896
- .map((fieldname) => `${fieldname}:(${makeQuery(filters[fieldname])})`)
21021
+ .map((fieldname) => `${this.fieldAliases[fieldname] ?? fieldname}:(${makeQuery(filters[fieldname])})`)
20897
21022
  .join(' AND ');
20898
21023
  if (filters['gn-ui-crossFieldFilter']) {
20899
21024
  queryString = `${queryString} AND (${filters['gn-ui-crossFieldFilter']})`;
@@ -20905,15 +21030,7 @@ class ElasticsearchService {
20905
21030
  query: queryString,
20906
21031
  },
20907
21032
  },
20908
- ...queryRanges.map(([searchField, dateRange]) => ({
20909
- range: {
20910
- [searchField]: {
20911
- ...(dateRange.start && { gte: formatDate(dateRange.start) }),
20912
- ...(dateRange.end && { lte: formatDate(dateRange.end) }),
20913
- format: 'yyyy-MM-dd',
20914
- },
20915
- },
20916
- })),
21033
+ ...queryRanges.map(([searchField, dateRange]) => this.buildDateRangeQuery(searchField, dateRange)),
20917
21034
  spatialFilterExtent && {
20918
21035
  geo_shape: {
20919
21036
  geom: {
@@ -21199,6 +21316,12 @@ class ElasticsearchService {
21199
21316
  order: {
21200
21317
  [`_${aggregation.sort[1]}`]: aggregation.sort[0],
21201
21318
  },
21319
+ ...(aggregation.includeValues && {
21320
+ include: aggregation.includeValues,
21321
+ }),
21322
+ ...(aggregation.excludeValues && {
21323
+ exclude: aggregation.excludeValues,
21324
+ }),
21202
21325
  },
21203
21326
  };
21204
21327
  case 'histogram':
@@ -21333,42 +21456,16 @@ class Gn4Repository {
21333
21456
  ? this.gn4Mapper.readRecords(records)
21334
21457
  : of(null)));
21335
21458
  }
21336
- mapEmbeddedFeatureCatalog(featureTypes) {
21337
- return {
21338
- featureTypes: featureTypes.map((featureType) => ({
21339
- name: featureType.typeName || '',
21340
- definition: featureType.definition || '',
21341
- attributes: Array.isArray(featureType.attributeTable)
21342
- ? featureType.attributeTable.map((attr) => {
21343
- const values = attr.values
21344
- ?.filter((v) => v.code || v.label)
21345
- .map((v) => ({
21346
- code: v.code,
21347
- label: v.label,
21348
- }));
21349
- return {
21350
- name: attr.name,
21351
- code: attr.code,
21352
- definition: attr.definition,
21353
- type: attr.type,
21354
- ...(values?.length > 0 ? { values } : {}),
21355
- };
21356
- })
21357
- : [],
21358
- })),
21359
- };
21360
- }
21361
- getFeatureCatalog(record, visited = new Set() // prevent looping
21459
+ queryLinkedFeatureCatalog(record, visited = new Set() // prevent looping
21362
21460
  ) {
21363
- if (record.extras?.['featureTypes'] &&
21364
- Array.isArray(record.extras['featureTypes']) &&
21365
- record.extras['featureTypes'].length > 0) {
21366
- return of(this.mapEmbeddedFeatureCatalog(record.extras['featureTypes']));
21461
+ if ('featureTypeDescriptions' in record &&
21462
+ record.featureTypeDescriptions?.length > 0) {
21463
+ return of({ featureTypes: record.featureTypeDescriptions });
21367
21464
  }
21368
21465
  const featureCatalogIdentifier = record.extras['featureCatalogIdentifier'];
21369
21466
  if (featureCatalogIdentifier && !visited.has(featureCatalogIdentifier)) {
21370
21467
  visited.add(featureCatalogIdentifier);
21371
- return this.getRecord(featureCatalogIdentifier).pipe(switchMap((record) => record ? this.getFeatureCatalog(record, visited) : of(null)));
21468
+ return this.getRecord(featureCatalogIdentifier).pipe(switchMap((record) => record ? this.queryLinkedFeatureCatalog(record, visited) : of(null)));
21372
21469
  }
21373
21470
  return of(null);
21374
21471
  }
@@ -22587,48 +22684,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
22587
22684
  type: Injectable
22588
22685
  }] });
22589
22686
 
22590
- const GEOCODING_PROVIDER = new InjectionToken('geocoding-provider');
22591
- class GeocodingService {
22592
- constructor() {
22593
- this.provider = inject(GEOCODING_PROVIDER);
22594
- }
22595
- query(text) {
22596
- let queryObservable;
22597
- switch (this.provider[0]) {
22598
- case 'geoadmin':
22599
- queryObservable = from(queryGeoadmin(text, this.provider[1]));
22600
- break;
22601
- case 'geonames':
22602
- queryObservable = from(queryGeonames(text, this.provider[1]));
22603
- break;
22604
- case 'data-gouv-fr':
22605
- queryObservable = from(queryDataGouvFr(text, this.provider[1]));
22606
- break;
22607
- default:
22608
- return throwError(() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`));
22609
- }
22610
- return queryObservable.pipe(catchError((error) => throwError(error)));
22611
- }
22612
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
22613
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, providedIn: 'root' }); }
22614
- }
22615
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, decorators: [{
22616
- type: Injectable,
22617
- args: [{
22618
- providedIn: 'root',
22619
- }]
22620
- }] });
22621
-
22622
22687
  class FeatureMapModule {
22623
22688
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
22624
22689
  static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, imports: [i1.StoreFeatureModule] }); }
22625
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, providers: [
22626
- MapFacade,
22627
- {
22628
- provide: GEOCODING_PROVIDER,
22629
- useValue: ['geonames', { maxRows: 5 }],
22630
- },
22631
- ], imports: [StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer)] }); }
22690
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, providers: [MapFacade], imports: [StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer)] }); }
22632
22691
  }
22633
22692
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureMapModule, decorators: [{
22634
22693
  type: NgModule,
@@ -22636,13 +22695,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
22636
22695
  imports: [
22637
22696
  StoreModule.forFeature(MAP_FEATURE_KEY, mapReducer),
22638
22697
  ],
22639
- providers: [
22640
- MapFacade,
22641
- {
22642
- provide: GEOCODING_PROVIDER,
22643
- useValue: ['geonames', { maxRows: 5 }],
22644
- },
22645
- ],
22698
+ providers: [MapFacade],
22646
22699
  }]
22647
22700
  }] });
22648
22701
 
@@ -23085,1060 +23138,352 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
23085
23138
  }]
23086
23139
  }] });
23087
23140
 
23088
- const flatten = (base, obj, keepLevel = false) => Object.keys(obj).reduce((prev, curr) => {
23089
- const path = base ? `${base}.${curr}` : curr;
23090
- const val = obj[curr];
23091
- if (keepLevel) {
23092
- return { ...prev, [path]: flatten('', val) };
23141
+ class AnchorLinkDirective {
23142
+ constructor() {
23143
+ this.changeDetector = inject(ChangeDetectorRef);
23144
+ this.disabled = false;
23145
+ this.observer = new MutationObserver(() => {
23146
+ this.refreshDisabledState();
23147
+ });
23148
+ this.inView = false;
23149
+ this.initialized = false;
23093
23150
  }
23094
- else if (typeof val === 'object' && !Array.isArray(val)) {
23095
- return {
23096
- ...prev,
23097
- ...flatten(path, val),
23098
- };
23151
+ get elementClass() {
23152
+ if (this.disabled) {
23153
+ return this.disabledClass;
23154
+ }
23155
+ if (this.inView) {
23156
+ return `${this.inViewClass} ${this.enabledClass}`;
23157
+ }
23158
+ else {
23159
+ return `${this.outOfViewClass} ${this.enabledClass}`;
23160
+ }
23099
23161
  }
23100
- else {
23101
- return { ...prev, [path]: val };
23162
+ ngOnInit() {
23163
+ this.observer.observe(document.body, {
23164
+ childList: true,
23165
+ subtree: true,
23166
+ });
23167
+ this.refreshDisabledState();
23102
23168
  }
23103
- }, {});
23104
- const checkKeys = (input, mandatory, optional) => {
23105
- const keys = Object.keys(input);
23106
- const missing = mandatory.filter((key) => keys.indexOf(key) === -1);
23107
- const unrecognized = keys.filter((key) => mandatory.indexOf(key) === -1 && optional.indexOf(key) === -1);
23108
- return {
23109
- missing,
23110
- unrecognized,
23111
- };
23112
- };
23113
- /**
23114
- * Only keeps recognized keys, flatten nested values (to allow having "." in keys),
23115
- * pushes warnings and errors to the given arrays; returns null in case of error
23116
- */
23117
- function parseConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
23118
- if (typeof fullConfigObj[sectionName] !== 'object') {
23119
- if (mandatoryKeys.length === 0)
23120
- return null;
23121
- outErrors.push(`The [${sectionName}] mandatory section is missing.`);
23122
- return null;
23169
+ ngAfterViewChecked() {
23170
+ if (!this.initialized && !this.disabled) {
23171
+ const target = document.getElementById(this.targetId);
23172
+ if (target) {
23173
+ this.initializeIntersectionObserver(target);
23174
+ this.initialized = true;
23175
+ }
23176
+ }
23123
23177
  }
23124
- const sectionConf = fullConfigObj[sectionName];
23125
- const keysCheck = checkKeys(sectionConf, mandatoryKeys, optionalKeys);
23126
- if (keysCheck.missing.length) {
23127
- // note: this is not thrown to allow merging several Errors down the line
23128
- outErrors.push(`In the [${sectionName}] section: ${keysCheck.missing.join(', ')}`);
23129
- return null;
23178
+ initializeIntersectionObserver(target) {
23179
+ this.intersectionObserver = new IntersectionObserver((entries) => {
23180
+ entries.forEach((entry) => {
23181
+ this.inView = entry.isIntersecting;
23182
+ this.changeDetector.detectChanges();
23183
+ });
23184
+ }, {
23185
+ root: null,
23186
+ rootMargin: '-30% 0% -60% 0%',
23187
+ });
23188
+ this.intersectionObserver.observe(target);
23130
23189
  }
23131
- else if (keysCheck.unrecognized.length) {
23132
- outWarnings.push(`In the [${sectionName}] section: ${keysCheck.unrecognized.join(', ')}`);
23133
- keysCheck.unrecognized.forEach((key) => delete sectionConf[key]);
23190
+ ngOnDestroy() {
23191
+ this.observer.disconnect();
23192
+ if (this.intersectionObserver) {
23193
+ this.intersectionObserver.disconnect();
23194
+ }
23134
23195
  }
23135
- return sectionConf;
23196
+ refreshDisabledState() {
23197
+ const targetNotPresent = !document.getElementById(this.targetId);
23198
+ if (targetNotPresent !== this.disabled) {
23199
+ this.disabled = targetNotPresent;
23200
+ this.changeDetector.detectChanges();
23201
+ }
23202
+ }
23203
+ scrollToTarget() {
23204
+ const target = document.getElementById(this.targetId);
23205
+ if (!target)
23206
+ return;
23207
+ target.scrollIntoView({
23208
+ behavior: 'smooth',
23209
+ block: 'start',
23210
+ });
23211
+ }
23212
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
23213
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: AnchorLinkDirective, isStandalone: true, selector: "[gnUiAnchorLink]", inputs: { targetId: ["gnUiAnchorLink", "targetId"], disabledClass: ["gnUiAnchorLinkDisabledClass", "disabledClass"], enabledClass: ["gnUiAnchorLinkEnabledClass", "enabledClass"], inViewClass: ["gnUiAnchorLinkInViewClass", "inViewClass"], outOfViewClass: ["gnUiAnchorLinkOutOfViewClass", "outOfViewClass"] }, host: { listeners: { "click": "scrollToTarget()" }, properties: { "class": "this.elementClass" } }, ngImport: i0 }); }
23136
23214
  }
23137
- /**
23138
- * Same as parseConfigSection but keeps all keys, recognized or not
23139
- * Also the first level is the language code (e.g. 'en')
23140
- * This is optional
23141
- */
23142
- function parseTranslationsConfigSection(fullConfigObj, sectionName) {
23143
- if (typeof fullConfigObj[sectionName] !== 'object') {
23144
- return {};
23215
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, decorators: [{
23216
+ type: Directive,
23217
+ args: [{
23218
+ selector: '[gnUiAnchorLink]',
23219
+ standalone: true,
23220
+ }]
23221
+ }], propDecorators: { targetId: [{
23222
+ type: Input,
23223
+ args: ['gnUiAnchorLink']
23224
+ }], disabledClass: [{
23225
+ type: Input,
23226
+ args: ['gnUiAnchorLinkDisabledClass']
23227
+ }], enabledClass: [{
23228
+ type: Input,
23229
+ args: ['gnUiAnchorLinkEnabledClass']
23230
+ }], inViewClass: [{
23231
+ type: Input,
23232
+ args: ['gnUiAnchorLinkInViewClass']
23233
+ }], outOfViewClass: [{
23234
+ type: Input,
23235
+ args: ['gnUiAnchorLinkOutOfViewClass']
23236
+ }], elementClass: [{
23237
+ type: HostBinding,
23238
+ args: ['class']
23239
+ }], scrollToTarget: [{
23240
+ type: HostListener,
23241
+ args: ['click']
23242
+ }] } });
23243
+
23244
+ class PaginationDotsComponent {
23245
+ constructor() {
23246
+ this.containerClass = '';
23145
23247
  }
23146
- return flatten('', fullConfigObj[sectionName], true);
23248
+ // 1-based
23249
+ get steps() {
23250
+ return Array.from({ length: this.listComponent.pagesCount }, (_, i) => i + 1);
23251
+ }
23252
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23253
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PaginationDotsComponent, isStandalone: true, selector: "gn-ui-pagination-dots", inputs: { listComponent: "listComponent", containerClass: "containerClass" }, ngImport: i0, template: "@if (listComponent.pagesCount > 1) {\n <div\n class=\"overflow-hidden flex flex-row justify-center gap-[14px] p-1\"\n [ngClass]=\"containerClass\"\n >\n @for (step of steps; track step) {\n <button\n type=\"button\"\n class=\"pagination-dot\"\n (click)=\"listComponent.goToPage(step)\"\n [ngClass]=\"\n listComponent.currentPage === step ? 'bg-primary' : 'bg-gray-400'\n \"\n ></button>\n }\n </div>\n}\n", styles: [".pagination-dot{width:6px;height:6px;border-radius:6px;position:relative;flex-shrink:0}.pagination-dot:after{content:\"\";position:absolute;left:-7px;top:-7px;width:20px;height:20px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], viewProviders: [
23254
+ provideIcons({
23255
+ iconoirNavArrowRight,
23256
+ iconoirNavArrowLeft,
23257
+ }),
23258
+ ] }); }
23147
23259
  }
23148
- /**
23149
- * Same as parseConfigSection but handles an array of configs; this is
23150
- * considered optional; returns null in case of error in at least one of
23151
- * the sections
23152
- */
23153
- function parseMultiConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
23154
- const sections = fullConfigObj[sectionName];
23155
- if (!sections) {
23156
- return [];
23260
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, decorators: [{
23261
+ type: Component,
23262
+ args: [{ selector: 'gn-ui-pagination-dots', standalone: true, imports: [CommonModule], viewProviders: [
23263
+ provideIcons({
23264
+ iconoirNavArrowRight,
23265
+ iconoirNavArrowLeft,
23266
+ }),
23267
+ ], template: "@if (listComponent.pagesCount > 1) {\n <div\n class=\"overflow-hidden flex flex-row justify-center gap-[14px] p-1\"\n [ngClass]=\"containerClass\"\n >\n @for (step of steps; track step) {\n <button\n type=\"button\"\n class=\"pagination-dot\"\n (click)=\"listComponent.goToPage(step)\"\n [ngClass]=\"\n listComponent.currentPage === step ? 'bg-primary' : 'bg-gray-400'\n \"\n ></button>\n }\n </div>\n}\n", styles: [".pagination-dot{width:6px;height:6px;border-radius:6px;position:relative;flex-shrink:0}.pagination-dot:after{content:\"\";position:absolute;left:-7px;top:-7px;width:20px;height:20px}\n"] }]
23268
+ }], propDecorators: { listComponent: [{
23269
+ type: Input
23270
+ }], containerClass: [{
23271
+ type: Input
23272
+ }] } });
23273
+
23274
+ class CarouselComponent {
23275
+ constructor() {
23276
+ this.changeDetector = inject(ChangeDetectorRef);
23277
+ this.containerClass = '';
23278
+ this.stepsContainerClass = 'w-full bottom-0 top-auto';
23279
+ this.currentStepChange = new EventEmitter();
23280
+ this.steps = [];
23281
+ this.currentStep = 0;
23282
+ this.refreshSteps = () => {
23283
+ this.steps = this.emblaApi.scrollSnapList();
23284
+ this.currentStep = this.emblaApi.selectedScrollSnap();
23285
+ this.currentStepChange.emit(this.currentStep);
23286
+ this.changeDetector.detectChanges();
23287
+ };
23157
23288
  }
23158
- if (!Array.isArray(sections)) {
23159
- outErrors.push(`Expected [[${sectionName}]] to be an array of sections.`);
23160
- return null;
23289
+ // Paginable API
23290
+ get isFirstPage() {
23291
+ return this.currentStep === 0;
23161
23292
  }
23162
- const result = sections.map((section) => parseConfigSection({ [sectionName]: section }, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors));
23163
- if (result.some((r) => r === null)) {
23164
- return null;
23293
+ get isLastPage() {
23294
+ return this.currentStep === this.steps.length - 1;
23165
23295
  }
23166
- return result;
23167
- }
23168
- function checkMetadataLanguage(parsedConfigSection, outWarnings) {
23169
- const lang2 = toLang2(parsedConfigSection.metadata_language.toLowerCase());
23170
- if (lang2?.length !== 2) {
23171
- outWarnings.push(`In the [global] section: metadata_language = "${parsedConfigSection.metadata_language}" is not a recognized ISO 639 language code`);
23296
+ get currentPage() {
23297
+ return this.currentStep + 1; // this is 1-based
23172
23298
  }
23173
- return parsedConfigSection;
23174
- }
23175
- function checkNewRecordDefaultLanguage(parsedConfigSection, outWarnings) {
23176
- const lang2 = toLang2(parsedConfigSection.new_record_default_language.toLowerCase());
23177
- if (!(lang2 in LANG_2_TO_3_MAPPER)) {
23178
- outWarnings.push(`In the [editing] section: new_record_default_language = "${parsedConfigSection.new_record_default_language}" is not a recognized ISO 639 language code`);
23179
- return {
23180
- ...parsedConfigSection,
23181
- new_record_default_language: undefined,
23182
- };
23299
+ get pagesCount() {
23300
+ return this.steps.length;
23183
23301
  }
23184
- return {
23185
- ...parsedConfigSection,
23186
- new_record_default_language: lang2,
23187
- };
23188
- }
23189
- function checkNewRecordStandard(parsedConfigSection, outWarnings) {
23190
- const standard = parsedConfigSection.new_record_standard;
23191
- const normalizedStandard = typeof standard === 'string' ? standard.trim().toLowerCase() : null;
23192
- if (normalizedStandard === 'iso19139' ||
23193
- normalizedStandard === 'iso19115-3') {
23194
- return {
23195
- ...parsedConfigSection,
23196
- new_record_standard: normalizedStandard,
23197
- };
23302
+ goToPage(stepIndex) {
23303
+ this.emblaApi.scrollTo(stepIndex - 1); // this is 0-based
23198
23304
  }
23199
- outWarnings.push(`In the [editing] section: new_record_standard = "${standard}" is not a supported metadata standard`);
23200
- return {
23201
- ...parsedConfigSection,
23202
- new_record_standard: undefined,
23203
- };
23305
+ goToPrevPage() {
23306
+ if (this.isFirstPage)
23307
+ return;
23308
+ this.emblaApi.scrollPrev();
23309
+ }
23310
+ goToNextPage() {
23311
+ if (this.isLastPage)
23312
+ return;
23313
+ this.emblaApi.scrollNext();
23314
+ }
23315
+ ngAfterViewInit() {
23316
+ this.emblaApi = EmblaCarousel(this.carouselOverflowContainer.nativeElement, {
23317
+ duration: 15,
23318
+ });
23319
+ this.emblaApi
23320
+ .on('init', this.refreshSteps)
23321
+ .on('reInit', this.refreshSteps)
23322
+ .on('select', this.refreshSteps);
23323
+ }
23324
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23325
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: CarouselComponent, isStandalone: true, selector: "gn-ui-carousel", inputs: { containerClass: "containerClass", stepsContainerClass: "stepsContainerClass" }, outputs: { currentStepChange: "currentStepChange" }, viewQueries: [{ propertyName: "carouselOverflowContainer", first: true, predicate: ["carouselOverflowContainer"], descendants: true }], ngImport: i0, template: "<div #carouselOverflowContainer class=\"w-full block\">\n <div class=\"carousel-container flex\" [ngClass]=\"containerClass\">\n <ng-content></ng-content>\n </div>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + stepsContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host{position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PaginationDotsComponent, selector: "gn-ui-pagination-dots", inputs: ["listComponent", "containerClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23204
23326
  }
23327
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, decorators: [{
23328
+ type: Component,
23329
+ args: [{ selector: 'gn-ui-carousel', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, PaginationDotsComponent], template: "<div #carouselOverflowContainer class=\"w-full block\">\n <div class=\"carousel-container flex\" [ngClass]=\"containerClass\">\n <ng-content></ng-content>\n </div>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + stepsContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host{position:relative}\n"] }]
23330
+ }], propDecorators: { carouselOverflowContainer: [{
23331
+ type: ViewChild,
23332
+ args: ['carouselOverflowContainer']
23333
+ }], containerClass: [{
23334
+ type: Input
23335
+ }], stepsContainerClass: [{
23336
+ type: Input
23337
+ }], currentStepChange: [{
23338
+ type: Output
23339
+ }] } });
23205
23340
 
23206
- /**
23207
- * This loader extends the default one based on JSON files but also loads custom translations
23208
- * defined in the app configuration
23209
- * Implements a fallback on default lang if translated labels are empty
23210
- */
23211
- class FileWithOverridesTranslateLoader extends FileTranslateLoader {
23212
- getTranslation(lang) {
23213
- const baseLang = lang.substring(0, 2); // removing the right part of e.g. en_EN
23214
- return super.getTranslation(baseLang).pipe(map$1((translations) => ({
23215
- ...translations,
23216
- ...getCustomTranslations(baseLang),
23217
- })));
23341
+ class ProgressBarComponent {
23342
+ constructor() {
23343
+ this.value = 0;
23344
+ this.type = 'default';
23345
+ }
23346
+ get progress() {
23347
+ return this.value > 0 ? (this.value < 100 ? this.value : 100) : 0;
23348
+ }
23349
+ get color() {
23350
+ switch (this.type) {
23351
+ case 'default':
23352
+ return {
23353
+ outerBar: 'bg-gray-200',
23354
+ innerBar: 'bg-gray-100',
23355
+ text: 'text-gray-900',
23356
+ };
23357
+ case 'primary':
23358
+ return {
23359
+ outerBar: 'bg-primary',
23360
+ innerBar: 'bg-primary-lighter',
23361
+ text: 'text-white',
23362
+ };
23363
+ case 'secondary':
23364
+ return {
23365
+ outerBar: 'bg-secondary',
23366
+ innerBar: 'bg-secondary-lighter',
23367
+ text: 'text-white',
23368
+ };
23369
+ case 'light':
23370
+ return {
23371
+ outerBar: 'bg-primary-white',
23372
+ innerBar: 'bg-primary',
23373
+ text: 'text-main',
23374
+ };
23375
+ }
23218
23376
  }
23377
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23378
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: ProgressBarComponent, isStandalone: true, selector: "gn-ui-progress-bar", inputs: { value: "value", type: "type" }, ngImport: i0, template: "@switch (type) {\n <!-- Light Theme -->\n @case ('light') {\n <div class=\"flex items-center relative\">\n <div\n class=\"flex-shrink-0 {{ color.text }} font-medium mr-2\n text-opacity-100 !text-slate-800\"\n data-cy=\"progressPercentage\"\n >\n {{ progress }}%\n </div>\n <div class=\"flex-grow h-[4px] w-[52px] {{ color.outerBar }} rounded-full\">\n <div\n [style.width.%]=\"progress\"\n class=\"{{ color.innerBar }} transition-width duration-500\n ease-in-out rounded-full shadow-sm w-[52px] h-[4px]\"\n ></div>\n </div>\n </div>\n }\n <!-- Default / Primary / Secondary Themes -->\n @default {\n <div class=\"flex h-full {{ color.outerBar }} rounded-t-lg rounded-b-lg\">\n <div\n [style.width.%]=\"progress\"\n class=\"flex {{ color.innerBar }} my-1 mx-1 transition-width\n duration-500 ease-in-out rounded-t-md rounded-b-md shadow-xl\"\n >\n <div\n class=\"flex items-center pl-2 py-1 {{ color.text }} font-bold text-4\"\n >\n {{ progress }}%\n </div>\n </div>\n </div>\n }\n}\n", styles: [".font-bold{font-weight:var(--progress-bar-font-weight, \"bold\")}\n"] }); }
23219
23379
  }
23380
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, decorators: [{
23381
+ type: Component,
23382
+ args: [{ selector: 'gn-ui-progress-bar', standalone: true, imports: [], template: "@switch (type) {\n <!-- Light Theme -->\n @case ('light') {\n <div class=\"flex items-center relative\">\n <div\n class=\"flex-shrink-0 {{ color.text }} font-medium mr-2\n text-opacity-100 !text-slate-800\"\n data-cy=\"progressPercentage\"\n >\n {{ progress }}%\n </div>\n <div class=\"flex-grow h-[4px] w-[52px] {{ color.outerBar }} rounded-full\">\n <div\n [style.width.%]=\"progress\"\n class=\"{{ color.innerBar }} transition-width duration-500\n ease-in-out rounded-full shadow-sm w-[52px] h-[4px]\"\n ></div>\n </div>\n </div>\n }\n <!-- Default / Primary / Secondary Themes -->\n @default {\n <div class=\"flex h-full {{ color.outerBar }} rounded-t-lg rounded-b-lg\">\n <div\n [style.width.%]=\"progress\"\n class=\"flex {{ color.innerBar }} my-1 mx-1 transition-width\n duration-500 ease-in-out rounded-t-md rounded-b-md shadow-xl\"\n >\n <div\n class=\"flex items-center pl-2 py-1 {{ color.text }} font-bold text-4\"\n >\n {{ progress }}%\n </div>\n </div>\n </div>\n }\n}\n", styles: [".font-bold{font-weight:var(--progress-bar-font-weight, \"bold\")}\n"] }]
23383
+ }], propDecorators: { value: [{
23384
+ type: Input
23385
+ }], type: [{
23386
+ type: Input
23387
+ }] } });
23220
23388
 
23221
- const MISSING_CONFIG_ERROR = `Application configuration was not initialized correctly.
23222
- This error might show up in case of an invalid/malformed configuration file.
23223
-
23224
- Note: make sure that you have called \`loadAppConfig\` from '../../../../../libs/util/app-config/src' before starting the Angular application.`;
23225
- let globalConfig = null;
23226
- function getGlobalConfig() {
23227
- if (globalConfig === null)
23228
- throw new Error(MISSING_CONFIG_ERROR);
23229
- return globalConfig;
23230
- }
23231
- let themeConfig = null;
23232
- function getThemeConfig() {
23233
- if (themeConfig === null)
23234
- throw new Error(MISSING_CONFIG_ERROR);
23235
- return themeConfig;
23236
- }
23237
- let mapConfig = null;
23238
- function getOptionalMapConfig() {
23239
- return mapConfig;
23240
- }
23241
- let searchConfig = null;
23242
- function getOptionalSearchConfig() {
23243
- return searchConfig;
23244
- }
23245
- let editorConfig = null;
23246
- function getOptionalEditorConfig() {
23247
- return editorConfig;
23248
- }
23249
- let metadataQualityConfig = null;
23250
- function getMetadataQualityConfig() {
23251
- return (metadataQualityConfig ||
23252
- {
23253
- ENABLED: false,
23389
+ class PopoverComponent {
23390
+ constructor() {
23391
+ this.viewContainerRef = inject(ViewContainerRef);
23392
+ this.renderer = inject(Renderer2);
23393
+ }
23394
+ getContent() {
23395
+ if (this.content instanceof TemplateRef) {
23396
+ if (this.view) {
23397
+ this.view.destroy();
23398
+ }
23399
+ this.view = this.viewContainerRef.createEmbeddedView(this.content);
23400
+ this.view.detectChanges();
23401
+ const wrapper = this.renderer.createElement('div'); // Create a wrapper div
23402
+ this.view.rootNodes.forEach((node) => {
23403
+ this.renderer.appendChild(wrapper, node); // Append each root node to the wrapper
23404
+ });
23405
+ return wrapper;
23406
+ }
23407
+ return this.content;
23408
+ }
23409
+ ngAfterViewInit() {
23410
+ this.tippyInstance = tippy(this.popoverContent.nativeElement, {
23411
+ content: this.getContent(),
23412
+ allowHTML: true,
23413
+ theme: this.theme,
23254
23414
  });
23255
- }
23256
- let customTranslations = null;
23257
- function getCustomTranslations(langCode) {
23258
- if (customTranslations === null)
23259
- throw new Error(MISSING_CONFIG_ERROR);
23260
- return langCode in customTranslations ? customTranslations[langCode] : {};
23261
- }
23262
- let appConfigLoaded = false;
23263
- function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
23264
- console.log(`[geonetwork-ui] Loading application configuration from ${configUrl}`);
23265
- return fetch(configUrl)
23266
- .then((resp) => {
23267
- if (!resp.ok)
23268
- throw new Error('Configuration file could not be loaded');
23269
- return resp.text();
23270
- })
23271
- .then((conf) => {
23272
- let parsed;
23273
- try {
23274
- parsed = TOML.parse(conf, { joiner: '\n', bigint: false });
23275
- }
23276
- catch (e) {
23277
- throw new Error(`An error occurred when parsing the configuration file: ${e.message}`);
23278
- }
23279
- const errors = [];
23280
- const warnings = [];
23281
- let parsedGlobalSection = parseConfigSection(parsed, 'global', ['geonetwork4_api_url'], [
23282
- 'datahub_url',
23283
- 'edit_url_template',
23284
- 'proxy_path',
23285
- 'metadata_language',
23286
- 'login_url',
23287
- 'logout_url',
23288
- 'settings_url',
23289
- 'web_component_embedder_url',
23290
- 'languages',
23291
- 'contact_email',
23292
- 'reuse_form_url',
23293
- ], warnings, errors);
23294
- if (parsedGlobalSection?.metadata_language) {
23295
- parsedGlobalSection = checkMetadataLanguage(parsedGlobalSection, warnings);
23296
- }
23297
- globalConfig =
23298
- parsedGlobalSection === null
23299
- ? null
23300
- : {
23301
- GN4_API_URL: parsedGlobalSection.geonetwork4_api_url,
23302
- DATAHUB_URL: parsedGlobalSection.datahub_url,
23303
- EDIT_URL_TEMPLATE: parsedGlobalSection.edit_url_template,
23304
- PROXY_PATH: parsedGlobalSection.proxy_path,
23305
- METADATA_LANGUAGE: parsedGlobalSection.metadata_language
23306
- ? parsedGlobalSection.metadata_language.toLowerCase()
23307
- : undefined,
23308
- LOGIN_URL: parsedGlobalSection.login_url,
23309
- LOGOUT_URL: parsedGlobalSection.logout_url,
23310
- SETTINGS_URL: parsedGlobalSection.settings_url,
23311
- WEB_COMPONENT_EMBEDDER_URL: parsedGlobalSection.web_component_embedder_url,
23312
- LANGUAGES: parsedGlobalSection.languages,
23313
- CONTACT_EMAIL: parsedGlobalSection.contact_email,
23314
- REUSE_FORM_URL: parsedGlobalSection.reuse_form_url,
23315
- };
23316
- const parsedLayersSections = parseMultiConfigSection(parsed, 'map_layer', ['type'], ['name', 'url', 'data', 'styleUrl', 'accessToken'], warnings, errors);
23317
- const parsedMapSection = parseConfigSection(parsed, 'map', [], [
23318
- 'max_zoom',
23319
- 'do_not_tile_wms',
23320
- 'max_extent',
23321
- 'max_feature_count',
23322
- 'baselayer',
23323
- 'do_not_use_default_basemap',
23324
- 'external_viewer_url_template',
23325
- 'external_viewer_open_new_tab',
23326
- ], warnings, errors);
23327
- mapConfig =
23328
- parsedMapSection === null || parsedLayersSections === null
23329
- ? null
23330
- : {
23331
- MAX_ZOOM: parsedMapSection.max_zoom,
23332
- DO_NOT_TILE_WMS: parsedMapSection.do_not_tile_wms,
23333
- MAX_EXTENT: parsedMapSection.max_extent,
23334
- MAX_FEATURE_COUNT: parsedMapSection.max_feature_count,
23335
- EXTERNAL_VIEWER_URL_TEMPLATE: parsedMapSection.external_viewer_url_template,
23336
- EXTERNAL_VIEWER_OPEN_NEW_TAB: parsedMapSection.external_viewer_open_new_tab,
23337
- DO_NOT_USE_DEFAULT_BASEMAP: !!parsedMapSection.do_not_use_default_basemap,
23338
- MAP_LAYERS: parsedLayersSections.map((map_layer) => ({
23339
- TYPE: map_layer.type,
23340
- URL: map_layer.url,
23341
- NAME: map_layer.name,
23342
- DATA: map_layer.data,
23343
- STYLE_URL: map_layer.styleUrl,
23344
- ACCESS_TOKEN: map_layer.accessToken,
23345
- })),
23346
- };
23347
- const parsedThemeSection = parseConfigSection(parsed, 'theme', ['primary_color', 'secondary_color', 'main_color', 'background_color'], [
23348
- 'header_foreground_color',
23349
- 'main_font',
23350
- 'title_font',
23351
- 'fonts_stylesheet_url',
23352
- 'thumbnail_placeholder',
23353
- 'header_background',
23354
- 'favicon',
23355
- ], warnings, errors);
23356
- themeConfig =
23357
- parsedThemeSection === null
23358
- ? null
23359
- : {
23360
- PRIMARY_COLOR: parsedThemeSection.primary_color,
23361
- SECONDARY_COLOR: parsedThemeSection.secondary_color,
23362
- MAIN_COLOR: parsedThemeSection.main_color,
23363
- BACKGROUND_COLOR: parsedThemeSection.background_color,
23364
- HEADER_FOREGROUND_COLOR: parsedThemeSection.header_foreground_color,
23365
- THUMBNAIL_PLACEHOLDER: parsedThemeSection.thumbnail_placeholder,
23366
- HEADER_BACKGROUND: parsedThemeSection.header_background,
23367
- TITLE_FONT: parsedThemeSection.title_font,
23368
- MAIN_FONT: parsedThemeSection.main_font,
23369
- FONTS_STYLESHEET_URL: parsedThemeSection.fonts_stylesheet_url,
23370
- FAVICON: parsedThemeSection.favicon,
23371
- };
23372
- const parsedSearchSection = parseConfigSection(parsed, 'search', [], [
23373
- 'record_kind_quick_filter',
23374
- 'filter_geometry_data',
23375
- 'filter_geometry_url',
23376
- 'do_not_use_default_search_preset',
23377
- 'search_preset',
23378
- 'advanced_filters',
23379
- 'limit',
23380
- 'spatial_extent_max_file_size',
23381
- ], warnings, errors);
23382
- const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
23383
- searchConfig =
23384
- parsedSearchSection === null
23385
- ? null
23386
- : {
23387
- RECORD_KIND_QUICK_FILTER: parsedSearchSection.record_kind_quick_filter,
23388
- FILTER_GEOMETRY_DATA: parsedSearchSection.filter_geometry_data,
23389
- FILTER_GEOMETRY_URL: parsedSearchSection.filter_geometry_url,
23390
- DO_NOT_USE_DEFAULT_SEARCH_PRESET: !!parsedSearchSection.do_not_use_default_search_preset,
23391
- SEARCH_PRESET: parsedSearchParams.map((param) => ({
23392
- sort: param.sort,
23393
- name: param.name,
23394
- filters: param.filters,
23395
- })),
23396
- ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
23397
- LIMIT: parsedSearchSection.limit,
23398
- SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
23399
- };
23400
- const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
23401
- metadataQualityConfig =
23402
- parsedMetadataQualitySection === null
23403
- ? null
23404
- : {
23405
- ENABLED: parsedMetadataQualitySection.enabled,
23406
- SORTABLE: parsedMetadataQualitySection.sortable,
23407
- };
23408
- let parsedEditingSection = parseConfigSection(parsed, 'editing', [], ['new_record_default_language', 'new_record_standard'], warnings, errors);
23409
- if (parsedEditingSection !== null &&
23410
- parsedEditingSection.new_record_default_language !== undefined) {
23411
- parsedEditingSection = checkNewRecordDefaultLanguage(parsedEditingSection, warnings);
23415
+ }
23416
+ ngOnChanges(changes) {
23417
+ if (changes['theme']) {
23418
+ this.theme = changes['theme'].currentValue;
23419
+ if (this.tippyInstance) {
23420
+ this.tippyInstance.setProps({ theme: this.theme });
23421
+ }
23412
23422
  }
23413
- if (parsedEditingSection !== null &&
23414
- parsedEditingSection.new_record_standard !== undefined) {
23415
- parsedEditingSection = checkNewRecordStandard(parsedEditingSection, warnings);
23423
+ if (changes['content']) {
23424
+ this.content = changes['content'].currentValue;
23425
+ if (this.tippyInstance) {
23426
+ this.tippyInstance.setContent(this.getContent());
23427
+ }
23416
23428
  }
23417
- editorConfig =
23418
- parsedEditingSection === null
23419
- ? null
23420
- : {
23421
- NEW_RECORD_DEFAULT_LANGUAGE: parsedEditingSection.new_record_default_language,
23422
- NEW_RECORD_STANDARD: parsedEditingSection.new_record_standard,
23423
- };
23424
- customTranslations = parseTranslationsConfigSection(parsed, 'translations');
23425
- if (errors.length) {
23426
- throw new Error(`One or more mandatory settings were missing from the configuration file.
23427
- ${errors.join('\n')}`);
23429
+ }
23430
+ ngOnDestroy() {
23431
+ if (this.tippyInstance) {
23432
+ this.tippyInstance.destroy();
23428
23433
  }
23429
- else if (warnings.length) {
23430
- console.warn(`One or more unexpected settings were encountered in the configuration file.
23431
- ${warnings.join('\n')}`);
23434
+ if (this.view) {
23435
+ this.view.destroy();
23432
23436
  }
23433
- appConfigLoaded = true;
23434
- });
23435
- }
23436
- function isConfigLoaded() {
23437
- return appConfigLoaded;
23438
- }
23439
- function _reset() {
23440
- globalConfig = null;
23441
- themeConfig = null;
23442
- editorConfig = null;
23443
- customTranslations = null;
23444
- }
23445
- const TRANSLATE_WITH_OVERRIDES_CONFIG = {
23446
- compiler: {
23447
- provide: TranslateCompiler,
23448
- useClass: TranslateMessageFormatCompiler,
23449
- },
23450
- loader: [
23451
- {
23452
- provide: TRANSLATE_HTTP_LOADER_CONFIG,
23453
- useValue: {
23454
- prefix: './assets/i18n/',
23455
- suffix: '.json',
23456
- },
23457
- },
23458
- {
23459
- provide: TranslateLoader,
23460
- useClass: FileWithOverridesTranslateLoader,
23461
- deps: [HttpClient, TRANSLATE_HTTP_LOADER_CONFIG],
23462
- },
23463
- ],
23464
- };
23465
-
23466
- const okAppConfigFixture = () => `
23467
- [global]
23468
- geonetwork4_api_url = "/geonetwork/srv/api"
23469
- proxy_path = "/proxy/?url="
23470
- metadata_language = "fre"
23471
- login_url = "/cas/login?service="
23472
- logout_url = "/geonetwork/signout"
23473
- settings_url = "/geonetwork/settings"
23474
- web_component_embedder_url = "/datahub/wc-embedder.html"
23475
-
23476
- [map]
23477
- max_zoom = 10
23478
- max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
23479
- do_not_use_default_basemap = false
23480
- external_viewer_url_template = 'https://example.com/myviewer?'
23481
- external_viewer_open_new_tab = true
23482
- [[map_layer]]
23483
- type = "wms"
23484
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23485
- name = "masque_hdf_ign_carto_latin1"
23486
- [[map_layer]]
23487
- type = "wfs"
23488
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23489
- name = "masque_hdf_ign_carto_latin1"
23490
-
23491
- [theme]
23492
- primary_color = "#093564"
23493
- secondary_color = "#c2e9dc"
23494
- main_color = "#212029" # All-purpose text color
23495
- background_color = "#fdfbff"
23496
- thumbnail_placeholder = 'assets/img/placeholder.svg'
23497
- header_background = 'teal'
23498
- header_foreground_color = "#872e2e"
23499
- main_font = 'sans-serif'
23500
- title_font = 'serif'
23501
- fonts_stylesheet_url = "https://fonts.googleapis.com/css2?family=Open+Sans"
23502
-
23503
- [search]
23504
- record_kind_quick_filter = false
23505
- filter_geometry_url = 'https://my.domain.org/geom.json'
23506
- do_not_use_default_search_preset = false
23507
- advanced_filters = ['publicationYear', 'documentStandard', 'inspireKeyword', 'topic', 'license']
23508
-
23509
- [[search_preset]]
23510
- sort = "-createDate"
23511
- name = 'filterByOrgs'
23512
- filters.q = 'Carto'
23513
- filters.organisation = ['Org1', 'Org2']
23514
- filters.format = ['ESRI Shapefile']
23515
- filters.topic = ['boundaries']
23516
- filters.publicationYear = ['2023', '2022']
23517
- filters.spatial = ['yes']
23518
-
23519
- [translations.en]
23520
- "my.first.key" = 'First label.'
23521
- "my.second.key" = """
23522
- Second label,
23523
- on two lines."""
23524
-
23525
- [translations.de]
23526
- my.first.key = 'Erste Etikett.'
23527
-
23528
- [translations.fr]
23529
- my.sample.text = "Un bon exemple de texte."
23530
- "my.quoted.text" = 'du texte entre guillements.'
23531
- `;
23532
- const appConfigWithTranslationFixture = () => okAppConfigFixture();
23533
- const minimalAppConfigFixture = () => `
23534
- [global]
23535
- geonetwork4_api_url = "/geonetwork/srv/api"
23536
- proxy_path = "/proxy/?url="
23537
-
23538
- [theme]
23539
- primary_color = "#093564"
23540
- secondary_color = "#c2e9dc"
23541
- main_color = "#212029" # All-purpose text color
23542
- background_color = "#fdfbff"
23543
- `;
23544
- const mapConfigFixture = () => ({
23545
- MAX_ZOOM: 10,
23546
- MAX_EXTENT: [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855],
23547
- DO_NOT_USE_DEFAULT_BASEMAP: false,
23548
- DO_NOT_TILE_WMS: false,
23549
- EXTERNAL_VIEWER_URL_TEMPLATE: 'https://example.com/myviewer/#/?actions=[{"type":"CATALOG:ADD_LAYERS_FROM_CATALOGS","layers":["${layer_name}"],"sources":[{"url":"${service_url}","type":"${service_type}"}]}]',
23550
- EXTERNAL_VIEWER_OPEN_NEW_TAB: true,
23551
- MAP_LAYERS: [
23552
- {
23553
- TYPE: 'xyz',
23554
- URL: 'https://some-basemap-server',
23555
- },
23556
- {
23557
- TYPE: 'wms',
23558
- URL: 'https://some-wms-server',
23559
- NAME: 'some_layername',
23560
- },
23561
- {
23562
- TYPE: 'wfs',
23563
- URL: 'https://some-wfs-server',
23564
- NAME: 'some_layername',
23565
- },
23566
- ],
23567
- });
23568
- const malformedConfigFixture = () => `
23569
- {
23570
- "I thought": "we were still doing json"
23437
+ }
23438
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23439
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: PopoverComponent, isStandalone: true, selector: "gn-ui-popover", inputs: { content: "content", theme: "theme" }, viewQueries: [{ propertyName: "popoverContent", first: true, predicate: ["popoverContent"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<span #popoverContent>\n <ng-content></ng-content>\n</span>\n", styles: [""] }); }
23571
23440
  }
23572
- `;
23573
- const missingMandatoryConfigFixture = () => `
23574
- [theme]
23575
- primary_color = "#093564"
23576
- secondary_color = "#c2e9dc"
23577
- background_color = "#fdfbff"
23578
- main_font = 'sans-serif'
23579
- `;
23580
- const wrongLanguageCodeConfigFixture = () => `
23581
- [global]
23582
- geonetwork4_api_url = "/geonetwork/srv/api"
23583
- proxy_path = "/proxy/?url="
23584
- metadata_language = "abc"
23585
-
23586
- [map]
23587
-
23588
- [theme]
23589
- primary_color = "#093564"
23590
- secondary_color = "#c2e9dc"
23591
- main_color = "#212029" # All-purpose text color
23592
- background_color = "#fdfbff"
23593
- `;
23594
- const unrecognizedKeysConfigFixture = () => `
23595
- [global]
23596
- geonetwork4_api_url = "/geonetwork/srv/api"
23597
- proxy_path = "/proxy/?url="
23598
- metadata_language = "fre"
23599
- another_path = '/whatever'
23600
-
23601
- [map]
23602
- max_zoom = 10
23603
- max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
23604
- do_not_use_default_basemap = false
23605
- external_viewer_url_template = 'https://example.com/myviewer?'
23606
- external_viewer_open_new_tab = true
23607
- another_zoom = 15
23608
- [[map_layer]]
23609
- type = "wms"
23610
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23611
- name = "masque_hdf_ign_carto_latin1"
23612
- [[map_layer]]
23613
- type = "wfs"
23614
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23615
- name = "masque_hdf_ign_carto_latin1"
23616
- another_layer = "wrong layer definition"
23617
-
23618
- [theme]
23619
- primary_color = "#093564"
23620
- secondary_color = "#c2e9dc"
23621
- main_color = "#212029" # All-purpose text color
23622
- background_color = "#fdfbff"
23623
- thumbnail_placeholder = 'assets/img/placeholder.svg'
23624
- header_background = 'teal'
23625
- header_foreground_color = "#872e2e"
23626
- main_font = 'sans-serif'
23627
- title_font = 'serif'
23628
- another_color = 'red'
23629
- `;
23441
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, decorators: [{
23442
+ type: Component,
23443
+ args: [{ selector: 'gn-ui-popover', standalone: true, imports: [], template: "<span #popoverContent>\n <ng-content></ng-content>\n</span>\n" }]
23444
+ }], propDecorators: { popoverContent: [{
23445
+ type: ViewChild,
23446
+ args: ['popoverContent', { static: false }]
23447
+ }], content: [{
23448
+ type: Input
23449
+ }], theme: [{
23450
+ type: Input
23451
+ }] } });
23630
23452
 
23631
- function getMapContextLayerFromConfig(config) {
23632
- switch (config.TYPE) {
23633
- case 'wms':
23634
- return {
23635
- type: 'wms',
23636
- url: config.URL,
23637
- name: config.NAME,
23638
- };
23639
- case 'wfs':
23640
- return {
23641
- type: 'wfs',
23642
- url: config.URL,
23643
- featureType: config.NAME,
23644
- };
23645
- case 'xyz':
23646
- return {
23647
- type: config.TYPE,
23648
- url: config.URL,
23649
- };
23650
- case 'geojson':
23651
- return {
23652
- type: config.TYPE,
23653
- ...(config.DATA ? { data: config.DATA } : { url: config.URL }),
23654
- };
23655
- case 'maplibre-style':
23656
- return {
23657
- type: config.TYPE,
23658
- styleUrl: config.STYLE_URL,
23659
- accessToken: config.ACCESS_TOKEN,
23660
- };
23661
- }
23453
+ class LoadingMaskComponent {
23454
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23455
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: LoadingMaskComponent, isStandalone: true, selector: "gn-ui-loading-mask", inputs: { message: "message" }, ngImport: i0, template: "<div class=\"h-full flex flex-col justify-center items-center relative backdrop\">\n <div class=\"absolute background bg-white inset-0\"></div>\n <mat-spinner [diameter]=\"28\" class=\"relative\"></mat-spinner>\n <span class=\"text-sm text-gray-700 mt-3 relative\">{{ message }}</span>\n</div>\n", styles: ["::ng-deep .mat-spinner circle{stroke:var(--color-gray-700);opacity:.5}.backdrop{background-color:#fff6}@supports (-webkit-backdrop-filter: blur()) or (backdrop-filter: blur()){.backdrop{background-color:transparent;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}}.background{opacity:.7}\n"], dependencies: [{ kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23662
23456
  }
23457
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, decorators: [{
23458
+ type: Component,
23459
+ args: [{ selector: 'gn-ui-loading-mask', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatProgressSpinnerModule], standalone: true, template: "<div class=\"h-full flex flex-col justify-center items-center relative backdrop\">\n <div class=\"absolute background bg-white inset-0\"></div>\n <mat-spinner [diameter]=\"28\" class=\"relative\"></mat-spinner>\n <span class=\"text-sm text-gray-700 mt-3 relative\">{{ message }}</span>\n</div>\n", styles: ["::ng-deep .mat-spinner circle{stroke:var(--color-gray-700);opacity:.5}.backdrop{background-color:#fff6}@supports (-webkit-backdrop-filter: blur()) or (backdrop-filter: blur()){.backdrop{background-color:transparent;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}}.background{opacity:.7}\n"] }]
23460
+ }], propDecorators: { message: [{
23461
+ type: Input
23462
+ }] } });
23663
23463
 
23664
- class MapStyleService {
23665
- constructor() {
23666
- this.styles = {
23667
- default: this.createStyleFunction(this.createGeometryStyles({
23668
- color: isConfigLoaded() ? getThemeConfig().PRIMARY_COLOR : 'blue',
23669
- })),
23670
- defaultHL: this.createStyleFunction(this.createGeometryStyles({
23671
- color: isConfigLoaded() ? getThemeConfig().SECONDARY_COLOR : 'red',
23672
- isFocused: true,
23673
- })),
23674
- };
23675
- }
23676
- createGeometryStyles(options) {
23677
- const { color, isFocused } = options;
23678
- const zIndex = isFocused ? 10 : undefined;
23679
- return {
23680
- polygon: new Style({
23681
- fill: new Fill({
23682
- color: this.computeTransparentFillColor(color),
23683
- }),
23684
- stroke: new Stroke({
23685
- color: 'white',
23686
- width: 2,
23687
- }),
23688
- zIndex,
23689
- }),
23690
- point: new Style({
23691
- image: new CircleStyle({
23692
- fill: new Fill({
23693
- color,
23694
- }),
23695
- stroke: new Stroke({
23696
- color: 'white',
23697
- width: isFocused ? 3 : 2,
23698
- }),
23699
- radius: isFocused ? 8 : 7,
23700
- }),
23701
- zIndex,
23702
- }),
23703
- line: [
23704
- new Style({
23705
- stroke: new Stroke({
23706
- color: 'white',
23707
- width: isFocused ? 8 : 6,
23708
- }),
23709
- zIndex,
23710
- }),
23711
- new Style({
23712
- stroke: new Stroke({
23713
- color,
23714
- width: isFocused ? 3 : 2,
23715
- }),
23716
- zIndex,
23717
- }),
23718
- ],
23719
- };
23720
- }
23721
- createStyleFunction(styleByGeometryType) {
23722
- return (feature) => {
23723
- const geometryType = feature?.getGeometry()?.getType();
23724
- switch (geometryType) {
23725
- case 'LinearRing':
23726
- case 'LineString':
23727
- case 'MultiLineString':
23728
- return styleByGeometryType.line;
23729
- case 'Point':
23730
- case 'MultiPoint':
23731
- return styleByGeometryType.point;
23732
- case 'Circle':
23733
- case 'Polygon':
23734
- case 'MultiPolygon':
23735
- return styleByGeometryType.polygon;
23736
- default:
23737
- return styleByGeometryType.point;
23738
- }
23739
- };
23740
- }
23741
- computeTransparentFillColor(color, alpha = 0.25) {
23742
- return chroma(color).alpha(alpha).css();
23743
- }
23744
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MapStyleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
23745
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MapStyleService, providedIn: 'root' }); }
23464
+ class ColorScaleComponent {
23465
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23466
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: ColorScaleComponent, isStandalone: true, selector: "gn-ui-color-scale", ngImport: i0, template: "<div class=\"flex flex-row items-center\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">primary</div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-black\"\n title=\"primary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darkest\"\n title=\"primary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darker\"\n title=\"primary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary border-2 border-primary-darkest\"\n title=\"primary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lighter\"\n title=\"primary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lightest\"\n title=\"primary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-white\"\n title=\"primary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">\n secondary\n </div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-black\"\n title=\"secondary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darkest\"\n title=\"secondary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darker\"\n title=\"secondary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary border-2 border-secondary-darkest\"\n title=\"secondary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lighter\"\n title=\"secondary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lightest\"\n title=\"secondary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-white\"\n title=\"secondary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">main</div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-main\" title=\"main\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-900\" title=\"gray-900\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-800\" title=\"gray-800\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-700\" title=\"gray-700\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-600\" title=\"gray-600\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-500\" title=\"gray-500\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-400\" title=\"gray-400\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-300\" title=\"gray-300\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-200\" title=\"gray-200\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-100\" title=\"gray-100\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-50\" title=\"gray-50\"></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-background\"\n title=\"background\"\n ></div>\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32\">background</div>\n</div>\n", styles: [""] }); }
23746
23467
  }
23747
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MapStyleService, decorators: [{
23748
- type: Injectable,
23749
- args: [{
23750
- providedIn: 'root',
23751
- }]
23468
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, decorators: [{
23469
+ type: Component,
23470
+ args: [{ selector: 'gn-ui-color-scale', standalone: true, template: "<div class=\"flex flex-row items-center\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">primary</div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-black\"\n title=\"primary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darkest\"\n title=\"primary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darker\"\n title=\"primary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary border-2 border-primary-darkest\"\n title=\"primary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lighter\"\n title=\"primary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lightest\"\n title=\"primary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-white\"\n title=\"primary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">\n secondary\n </div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-black\"\n title=\"secondary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darkest\"\n title=\"secondary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darker\"\n title=\"secondary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary border-2 border-secondary-darkest\"\n title=\"secondary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lighter\"\n title=\"secondary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lightest\"\n title=\"secondary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-white\"\n title=\"secondary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">main</div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-main\" title=\"main\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-900\" title=\"gray-900\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-800\" title=\"gray-800\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-700\" title=\"gray-700\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-600\" title=\"gray-600\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-500\" title=\"gray-500\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-400\" title=\"gray-400\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-300\" title=\"gray-300\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-200\" title=\"gray-200\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-100\" title=\"gray-100\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-50\" title=\"gray-50\"></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-background\"\n title=\"background\"\n ></div>\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32\">background</div>\n</div>\n" }]
23752
23471
  }] });
23753
23472
 
23754
- const colorPrimary = 'blue';
23755
- const colorSecondary = 'red';
23756
- const colorStroke = 'white';
23757
- const defaultMapStyleFixture = () => new Style({
23758
- image: new Circle({
23759
- fill: new Fill({
23760
- color: colorPrimary,
23761
- }),
23762
- stroke: new Stroke({
23763
- color: colorStroke,
23764
- width: 2,
23765
- }),
23766
- radius: 5,
23767
- }),
23768
- fill: new Fill({
23769
- color: 'rgba(0,0,255,0.25)',
23770
- }),
23771
- stroke: new Stroke({
23772
- color: colorStroke,
23773
- width: 2,
23774
- }),
23775
- });
23776
- const defaultMapStyleHlFixture = () => new Style({
23777
- image: new Circle({
23778
- fill: new Fill({
23779
- color: colorSecondary,
23780
- }),
23781
- stroke: new Stroke({
23782
- color: colorStroke,
23783
- width: 3,
23784
- }),
23785
- radius: 6,
23786
- }),
23787
- fill: new Fill({
23788
- color: 'rgba(255,0,0,0.25)',
23789
- }),
23790
- stroke: new Stroke({
23791
- color: colorSecondary,
23792
- width: 3,
23793
- }),
23794
- });
23795
-
23796
- class AnchorLinkDirective {
23473
+ class PopupAlertComponent {
23797
23474
  constructor() {
23798
23475
  this.changeDetector = inject(ChangeDetectorRef);
23799
- this.disabled = false;
23800
- this.observer = new MutationObserver(() => {
23801
- this.refreshDisabledState();
23802
- });
23803
- this.inView = false;
23804
- this.initialized = false;
23476
+ this.type = 'info';
23477
+ this.position = 'top';
23478
+ this.expanded = false;
23479
+ this.timeout = null;
23805
23480
  }
23806
- get elementClass() {
23807
- if (this.disabled) {
23808
- return this.disabledClass;
23809
- }
23810
- if (this.inView) {
23811
- return `${this.inViewClass} ${this.enabledClass}`;
23812
- }
23813
- else {
23814
- return `${this.outOfViewClass} ${this.enabledClass}`;
23815
- }
23481
+ get showDuration() {
23482
+ const chars = this.content.nativeElement.innerHTML.length;
23483
+ return Math.max(3000, chars * 20);
23816
23484
  }
23817
23485
  ngOnInit() {
23818
- this.observer.observe(document.body, {
23819
- childList: true,
23820
- subtree: true,
23821
- });
23822
- this.refreshDisabledState();
23823
- }
23824
- ngAfterViewChecked() {
23825
- if (!this.initialized && !this.disabled) {
23826
- const target = document.getElementById(this.targetId);
23827
- if (target) {
23828
- this.initializeIntersectionObserver(target);
23829
- this.initialized = true;
23830
- }
23831
- }
23832
- }
23833
- initializeIntersectionObserver(target) {
23834
- this.intersectionObserver = new IntersectionObserver((entries) => {
23835
- entries.forEach((entry) => {
23836
- this.inView = entry.isIntersecting;
23837
- this.changeDetector.detectChanges();
23838
- });
23839
- }, {
23840
- root: null,
23841
- rootMargin: '-30% 0% -60% 0%',
23842
- });
23843
- this.intersectionObserver.observe(target);
23844
- }
23845
- ngOnDestroy() {
23846
- this.observer.disconnect();
23847
- if (this.intersectionObserver) {
23848
- this.intersectionObserver.disconnect();
23849
- }
23850
- }
23851
- refreshDisabledState() {
23852
- const targetNotPresent = !document.getElementById(this.targetId);
23853
- if (targetNotPresent !== this.disabled) {
23854
- this.disabled = targetNotPresent;
23855
- this.changeDetector.detectChanges();
23856
- }
23857
- }
23858
- scrollToTarget() {
23859
- const target = document.getElementById(this.targetId);
23860
- if (!target)
23861
- return;
23862
- target.scrollIntoView({
23863
- behavior: 'smooth',
23864
- block: 'start',
23865
- });
23866
- }
23867
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
23868
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.19", type: AnchorLinkDirective, isStandalone: true, selector: "[gnUiAnchorLink]", inputs: { targetId: ["gnUiAnchorLink", "targetId"], disabledClass: ["gnUiAnchorLinkDisabledClass", "disabledClass"], enabledClass: ["gnUiAnchorLinkEnabledClass", "enabledClass"], inViewClass: ["gnUiAnchorLinkInViewClass", "inViewClass"], outOfViewClass: ["gnUiAnchorLinkOutOfViewClass", "outOfViewClass"] }, host: { listeners: { "click": "scrollToTarget()" }, properties: { "class": "this.elementClass" } }, ngImport: i0 }); }
23869
- }
23870
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, decorators: [{
23871
- type: Directive,
23872
- args: [{
23873
- selector: '[gnUiAnchorLink]',
23874
- standalone: true,
23875
- }]
23876
- }], propDecorators: { targetId: [{
23877
- type: Input,
23878
- args: ['gnUiAnchorLink']
23879
- }], disabledClass: [{
23880
- type: Input,
23881
- args: ['gnUiAnchorLinkDisabledClass']
23882
- }], enabledClass: [{
23883
- type: Input,
23884
- args: ['gnUiAnchorLinkEnabledClass']
23885
- }], inViewClass: [{
23886
- type: Input,
23887
- args: ['gnUiAnchorLinkInViewClass']
23888
- }], outOfViewClass: [{
23889
- type: Input,
23890
- args: ['gnUiAnchorLinkOutOfViewClass']
23891
- }], elementClass: [{
23892
- type: HostBinding,
23893
- args: ['class']
23894
- }], scrollToTarget: [{
23895
- type: HostListener,
23896
- args: ['click']
23897
- }] } });
23898
-
23899
- class PaginationDotsComponent {
23900
- constructor() {
23901
- this.containerClass = '';
23902
- }
23903
- // 1-based
23904
- get steps() {
23905
- return Array.from({ length: this.listComponent.pagesCount }, (_, i) => i + 1);
23906
- }
23907
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23908
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: PaginationDotsComponent, isStandalone: true, selector: "gn-ui-pagination-dots", inputs: { listComponent: "listComponent", containerClass: "containerClass" }, ngImport: i0, template: "@if (listComponent.pagesCount > 1) {\n <div\n class=\"overflow-hidden flex flex-row justify-center gap-[14px] p-1\"\n [ngClass]=\"containerClass\"\n >\n @for (step of steps; track step) {\n <button\n type=\"button\"\n class=\"pagination-dot\"\n (click)=\"listComponent.goToPage(step)\"\n [ngClass]=\"\n listComponent.currentPage === step ? 'bg-primary' : 'bg-gray-400'\n \"\n ></button>\n }\n </div>\n}\n", styles: [".pagination-dot{width:6px;height:6px;border-radius:6px;position:relative;flex-shrink:0}.pagination-dot:after{content:\"\";position:absolute;left:-7px;top:-7px;width:20px;height:20px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }], viewProviders: [
23909
- provideIcons({
23910
- iconoirNavArrowRight,
23911
- iconoirNavArrowLeft,
23912
- }),
23913
- ] }); }
23914
- }
23915
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, decorators: [{
23916
- type: Component,
23917
- args: [{ selector: 'gn-ui-pagination-dots', standalone: true, imports: [CommonModule], viewProviders: [
23918
- provideIcons({
23919
- iconoirNavArrowRight,
23920
- iconoirNavArrowLeft,
23921
- }),
23922
- ], template: "@if (listComponent.pagesCount > 1) {\n <div\n class=\"overflow-hidden flex flex-row justify-center gap-[14px] p-1\"\n [ngClass]=\"containerClass\"\n >\n @for (step of steps; track step) {\n <button\n type=\"button\"\n class=\"pagination-dot\"\n (click)=\"listComponent.goToPage(step)\"\n [ngClass]=\"\n listComponent.currentPage === step ? 'bg-primary' : 'bg-gray-400'\n \"\n ></button>\n }\n </div>\n}\n", styles: [".pagination-dot{width:6px;height:6px;border-radius:6px;position:relative;flex-shrink:0}.pagination-dot:after{content:\"\";position:absolute;left:-7px;top:-7px;width:20px;height:20px}\n"] }]
23923
- }], propDecorators: { listComponent: [{
23924
- type: Input
23925
- }], containerClass: [{
23926
- type: Input
23927
- }] } });
23928
-
23929
- class CarouselComponent {
23930
- constructor() {
23931
- this.changeDetector = inject(ChangeDetectorRef);
23932
- this.containerClass = '';
23933
- this.stepsContainerClass = 'w-full bottom-0 top-auto';
23934
- this.currentStepChange = new EventEmitter();
23935
- this.steps = [];
23936
- this.currentStep = 0;
23937
- this.refreshSteps = () => {
23938
- this.steps = this.emblaApi.scrollSnapList();
23939
- this.currentStep = this.emblaApi.selectedScrollSnap();
23940
- this.currentStepChange.emit(this.currentStep);
23941
- this.changeDetector.detectChanges();
23942
- };
23943
- }
23944
- // Paginable API
23945
- get isFirstPage() {
23946
- return this.currentStep === 0;
23947
- }
23948
- get isLastPage() {
23949
- return this.currentStep === this.steps.length - 1;
23950
- }
23951
- get currentPage() {
23952
- return this.currentStep + 1; // this is 1-based
23953
- }
23954
- get pagesCount() {
23955
- return this.steps.length;
23956
- }
23957
- goToPage(stepIndex) {
23958
- this.emblaApi.scrollTo(stepIndex - 1); // this is 0-based
23959
- }
23960
- goToPrevPage() {
23961
- if (this.isFirstPage)
23962
- return;
23963
- this.emblaApi.scrollPrev();
23964
- }
23965
- goToNextPage() {
23966
- if (this.isLastPage)
23967
- return;
23968
- this.emblaApi.scrollNext();
23969
- }
23970
- ngAfterViewInit() {
23971
- this.emblaApi = EmblaCarousel(this.carouselOverflowContainer.nativeElement, {
23972
- duration: 15,
23973
- });
23974
- this.emblaApi
23975
- .on('init', this.refreshSteps)
23976
- .on('reInit', this.refreshSteps)
23977
- .on('select', this.refreshSteps);
23978
- }
23979
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23980
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: CarouselComponent, isStandalone: true, selector: "gn-ui-carousel", inputs: { containerClass: "containerClass", stepsContainerClass: "stepsContainerClass" }, outputs: { currentStepChange: "currentStepChange" }, viewQueries: [{ propertyName: "carouselOverflowContainer", first: true, predicate: ["carouselOverflowContainer"], descendants: true }], ngImport: i0, template: "<div #carouselOverflowContainer class=\"w-full block\">\n <div class=\"carousel-container flex\" [ngClass]=\"containerClass\">\n <ng-content></ng-content>\n </div>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + stepsContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host{position:relative}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PaginationDotsComponent, selector: "gn-ui-pagination-dots", inputs: ["listComponent", "containerClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23981
- }
23982
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, decorators: [{
23983
- type: Component,
23984
- args: [{ selector: 'gn-ui-carousel', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, PaginationDotsComponent], template: "<div #carouselOverflowContainer class=\"w-full block\">\n <div class=\"carousel-container flex\" [ngClass]=\"containerClass\">\n <ng-content></ng-content>\n </div>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + stepsContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host{position:relative}\n"] }]
23985
- }], propDecorators: { carouselOverflowContainer: [{
23986
- type: ViewChild,
23987
- args: ['carouselOverflowContainer']
23988
- }], containerClass: [{
23989
- type: Input
23990
- }], stepsContainerClass: [{
23991
- type: Input
23992
- }], currentStepChange: [{
23993
- type: Output
23994
- }] } });
23995
-
23996
- class ProgressBarComponent {
23997
- constructor() {
23998
- this.value = 0;
23999
- this.type = 'default';
24000
- }
24001
- get progress() {
24002
- return this.value > 0 ? (this.value < 100 ? this.value : 100) : 0;
24003
- }
24004
- get color() {
24005
- switch (this.type) {
24006
- case 'default':
24007
- return {
24008
- outerBar: 'bg-gray-200',
24009
- innerBar: 'bg-gray-100',
24010
- text: 'text-gray-900',
24011
- };
24012
- case 'primary':
24013
- return {
24014
- outerBar: 'bg-primary',
24015
- innerBar: 'bg-primary-lighter',
24016
- text: 'text-white',
24017
- };
24018
- case 'secondary':
24019
- return {
24020
- outerBar: 'bg-secondary',
24021
- innerBar: 'bg-secondary-lighter',
24022
- text: 'text-white',
24023
- };
24024
- case 'light':
24025
- return {
24026
- outerBar: 'bg-primary-white',
24027
- innerBar: 'bg-primary',
24028
- text: 'text-main',
24029
- };
24030
- }
24031
- }
24032
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24033
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: ProgressBarComponent, isStandalone: true, selector: "gn-ui-progress-bar", inputs: { value: "value", type: "type" }, ngImport: i0, template: "@switch (type) {\n <!-- Light Theme -->\n @case ('light') {\n <div class=\"flex items-center relative\">\n <div\n class=\"flex-shrink-0 {{ color.text }} font-medium mr-2\n text-opacity-100 !text-slate-800\"\n data-cy=\"progressPercentage\"\n >\n {{ progress }}%\n </div>\n <div class=\"flex-grow h-[4px] w-[52px] {{ color.outerBar }} rounded-full\">\n <div\n [style.width.%]=\"progress\"\n class=\"{{ color.innerBar }} transition-width duration-500\n ease-in-out rounded-full shadow-sm w-[52px] h-[4px]\"\n ></div>\n </div>\n </div>\n }\n <!-- Default / Primary / Secondary Themes -->\n @default {\n <div class=\"flex h-full {{ color.outerBar }} rounded-t-lg rounded-b-lg\">\n <div\n [style.width.%]=\"progress\"\n class=\"flex {{ color.innerBar }} my-1 mx-1 transition-width\n duration-500 ease-in-out rounded-t-md rounded-b-md shadow-xl\"\n >\n <div\n class=\"flex items-center pl-2 py-1 {{ color.text }} font-bold text-4\"\n >\n {{ progress }}%\n </div>\n </div>\n </div>\n }\n}\n", styles: [".font-bold{font-weight:var(--progress-bar-font-weight, \"bold\")}\n"] }); }
24034
- }
24035
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, decorators: [{
24036
- type: Component,
24037
- args: [{ selector: 'gn-ui-progress-bar', standalone: true, imports: [], template: "@switch (type) {\n <!-- Light Theme -->\n @case ('light') {\n <div class=\"flex items-center relative\">\n <div\n class=\"flex-shrink-0 {{ color.text }} font-medium mr-2\n text-opacity-100 !text-slate-800\"\n data-cy=\"progressPercentage\"\n >\n {{ progress }}%\n </div>\n <div class=\"flex-grow h-[4px] w-[52px] {{ color.outerBar }} rounded-full\">\n <div\n [style.width.%]=\"progress\"\n class=\"{{ color.innerBar }} transition-width duration-500\n ease-in-out rounded-full shadow-sm w-[52px] h-[4px]\"\n ></div>\n </div>\n </div>\n }\n <!-- Default / Primary / Secondary Themes -->\n @default {\n <div class=\"flex h-full {{ color.outerBar }} rounded-t-lg rounded-b-lg\">\n <div\n [style.width.%]=\"progress\"\n class=\"flex {{ color.innerBar }} my-1 mx-1 transition-width\n duration-500 ease-in-out rounded-t-md rounded-b-md shadow-xl\"\n >\n <div\n class=\"flex items-center pl-2 py-1 {{ color.text }} font-bold text-4\"\n >\n {{ progress }}%\n </div>\n </div>\n </div>\n }\n}\n", styles: [".font-bold{font-weight:var(--progress-bar-font-weight, \"bold\")}\n"] }]
24038
- }], propDecorators: { value: [{
24039
- type: Input
24040
- }], type: [{
24041
- type: Input
24042
- }] } });
24043
-
24044
- class PopoverComponent {
24045
- constructor() {
24046
- this.viewContainerRef = inject(ViewContainerRef);
24047
- this.renderer = inject(Renderer2);
24048
- }
24049
- getContent() {
24050
- if (this.content instanceof TemplateRef) {
24051
- if (this.view) {
24052
- this.view.destroy();
24053
- }
24054
- this.view = this.viewContainerRef.createEmbeddedView(this.content);
24055
- this.view.detectChanges();
24056
- const wrapper = this.renderer.createElement('div'); // Create a wrapper div
24057
- this.view.rootNodes.forEach((node) => {
24058
- this.renderer.appendChild(wrapper, node); // Append each root node to the wrapper
24059
- });
24060
- return wrapper;
24061
- }
24062
- return this.content;
24063
- }
24064
- ngAfterViewInit() {
24065
- this.tippyInstance = tippy(this.popoverContent.nativeElement, {
24066
- content: this.getContent(),
24067
- allowHTML: true,
24068
- theme: this.theme,
24069
- });
24070
- }
24071
- ngOnChanges(changes) {
24072
- if (changes['theme']) {
24073
- this.theme = changes['theme'].currentValue;
24074
- if (this.tippyInstance) {
24075
- this.tippyInstance.setProps({ theme: this.theme });
24076
- }
24077
- }
24078
- if (changes['content']) {
24079
- this.content = changes['content'].currentValue;
24080
- if (this.tippyInstance) {
24081
- this.tippyInstance.setContent(this.getContent());
24082
- }
24083
- }
24084
- }
24085
- ngOnDestroy() {
24086
- if (this.tippyInstance) {
24087
- this.tippyInstance.destroy();
24088
- }
24089
- if (this.view) {
24090
- this.view.destroy();
24091
- }
24092
- }
24093
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24094
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: PopoverComponent, isStandalone: true, selector: "gn-ui-popover", inputs: { content: "content", theme: "theme" }, viewQueries: [{ propertyName: "popoverContent", first: true, predicate: ["popoverContent"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<span #popoverContent>\n <ng-content></ng-content>\n</span>\n", styles: [""] }); }
24095
- }
24096
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, decorators: [{
24097
- type: Component,
24098
- args: [{ selector: 'gn-ui-popover', standalone: true, imports: [], template: "<span #popoverContent>\n <ng-content></ng-content>\n</span>\n" }]
24099
- }], propDecorators: { popoverContent: [{
24100
- type: ViewChild,
24101
- args: ['popoverContent', { static: false }]
24102
- }], content: [{
24103
- type: Input
24104
- }], theme: [{
24105
- type: Input
24106
- }] } });
24107
-
24108
- class LoadingMaskComponent {
24109
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24110
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: LoadingMaskComponent, isStandalone: true, selector: "gn-ui-loading-mask", inputs: { message: "message" }, ngImport: i0, template: "<div class=\"h-full flex flex-col justify-center items-center relative backdrop\">\n <div class=\"absolute background bg-white inset-0\"></div>\n <mat-spinner [diameter]=\"28\" class=\"relative\"></mat-spinner>\n <span class=\"text-sm text-gray-700 mt-3 relative\">{{ message }}</span>\n</div>\n", styles: ["::ng-deep .mat-spinner circle{stroke:var(--color-gray-700);opacity:.5}.backdrop{background-color:#fff6}@supports (-webkit-backdrop-filter: blur()) or (backdrop-filter: blur()){.backdrop{background-color:transparent;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}}.background{opacity:.7}\n"], dependencies: [{ kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i2.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
24111
- }
24112
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, decorators: [{
24113
- type: Component,
24114
- args: [{ selector: 'gn-ui-loading-mask', changeDetection: ChangeDetectionStrategy.OnPush, imports: [MatProgressSpinnerModule], standalone: true, template: "<div class=\"h-full flex flex-col justify-center items-center relative backdrop\">\n <div class=\"absolute background bg-white inset-0\"></div>\n <mat-spinner [diameter]=\"28\" class=\"relative\"></mat-spinner>\n <span class=\"text-sm text-gray-700 mt-3 relative\">{{ message }}</span>\n</div>\n", styles: ["::ng-deep .mat-spinner circle{stroke:var(--color-gray-700);opacity:.5}.backdrop{background-color:#fff6}@supports (-webkit-backdrop-filter: blur()) or (backdrop-filter: blur()){.backdrop{background-color:transparent;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}}.background{opacity:.7}\n"] }]
24115
- }], propDecorators: { message: [{
24116
- type: Input
24117
- }] } });
24118
-
24119
- class ColorScaleComponent {
24120
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24121
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: ColorScaleComponent, isStandalone: true, selector: "gn-ui-color-scale", ngImport: i0, template: "<div class=\"flex flex-row items-center\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">primary</div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-black\"\n title=\"primary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darkest\"\n title=\"primary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darker\"\n title=\"primary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary border-2 border-primary-darkest\"\n title=\"primary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lighter\"\n title=\"primary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lightest\"\n title=\"primary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-white\"\n title=\"primary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">\n secondary\n </div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-black\"\n title=\"secondary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darkest\"\n title=\"secondary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darker\"\n title=\"secondary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary border-2 border-secondary-darkest\"\n title=\"secondary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lighter\"\n title=\"secondary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lightest\"\n title=\"secondary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-white\"\n title=\"secondary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">main</div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-main\" title=\"main\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-900\" title=\"gray-900\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-800\" title=\"gray-800\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-700\" title=\"gray-700\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-600\" title=\"gray-600\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-500\" title=\"gray-500\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-400\" title=\"gray-400\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-300\" title=\"gray-300\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-200\" title=\"gray-200\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-100\" title=\"gray-100\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-50\" title=\"gray-50\"></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-background\"\n title=\"background\"\n ></div>\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32\">background</div>\n</div>\n", styles: [""] }); }
24122
- }
24123
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, decorators: [{
24124
- type: Component,
24125
- args: [{ selector: 'gn-ui-color-scale', standalone: true, template: "<div class=\"flex flex-row items-center\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">primary</div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-black\"\n title=\"primary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darkest\"\n title=\"primary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-darker\"\n title=\"primary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary border-2 border-primary-darkest\"\n title=\"primary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lighter\"\n title=\"primary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-lightest\"\n title=\"primary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-primary-white\"\n title=\"primary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">\n secondary\n </div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-black\"\n title=\"secondary-black\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darkest\"\n title=\"secondary-darkest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-darker\"\n title=\"secondary-darker\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary border-2 border-secondary-darkest\"\n title=\"secondary\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lighter\"\n title=\"secondary-lighter\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-lightest\"\n title=\"secondary-lightest\"\n ></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-secondary-white\"\n title=\"secondary-white\"\n ></div>\n</div>\n<div class=\"flex flex-row\">\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32 text-right\">main</div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-main\" title=\"main\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-900\" title=\"gray-900\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-800\" title=\"gray-800\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-700\" title=\"gray-700\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-600\" title=\"gray-600\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-500\" title=\"gray-500\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-400\" title=\"gray-400\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-300\" title=\"gray-300\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-200\" title=\"gray-200\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-100\" title=\"gray-100\"></div>\n <div class=\"shadow-md rounded w-6 h-6 m-2 bg-gray-50\" title=\"gray-50\"></div>\n <div\n class=\"shadow-md rounded w-6 h-6 m-2 bg-background\"\n title=\"background\"\n ></div>\n <div class=\"text-xs text-gray-700 font-bold m-2 w-32\">background</div>\n</div>\n" }]
24126
- }] });
24127
-
24128
- class PopupAlertComponent {
24129
- constructor() {
24130
- this.changeDetector = inject(ChangeDetectorRef);
24131
- this.type = 'info';
24132
- this.position = 'top';
24133
- this.expanded = false;
24134
- this.timeout = null;
24135
- }
24136
- get showDuration() {
24137
- const chars = this.content.nativeElement.innerHTML.length;
24138
- return Math.max(3000, chars * 20);
24139
- }
24140
- ngOnInit() {
24141
- this.expandAndClose();
23486
+ this.expandAndClose();
24142
23487
  }
24143
23488
  expand() {
24144
23489
  this.expanded = true;
@@ -24309,15 +23654,15 @@ class AutocompleteComponent {
24309
23654
  getExtraClass() {
24310
23655
  if (this.allowSubmit) {
24311
23656
  if (this.enterButton) {
24312
- return 'border rounded-lg absolute w-8 h-8 right-[calc(var(--icon-width)+var(--icon-padding))] inset-y-[--icon-padding]';
23657
+ return 'border rounded-lg absolute w-8 h-8 right-[calc(var(--icon-width)+var(--icon-padding))] top-1/2 -translate-y-1/2';
24313
23658
  }
24314
23659
  else {
24315
- return 'border rounded-lg absolute w-8 h-8 right-[calc(var(--icon-width)+0.25*var(--icon-width))] inset-y-[calc(0.25*var(--icon-width))]';
23660
+ return 'border rounded-lg absolute w-8 h-8 right-[calc(var(--icon-width)+0.25*var(--icon-width))] top-1/2 -translate-y-1/2';
24316
23661
  }
24317
23662
  }
24318
23663
  else {
24319
23664
  if (!this.enterButton) {
24320
- return 'border rounded-lg absolute w-8 h-8 right-2 inset-y-2';
23665
+ return 'border rounded-lg absolute w-8 h-8 right-2 top-1/2 -translate-y-1/2';
24321
23666
  }
24322
23667
  }
24323
23668
  return 'border rounded-lg absolute w-8 h-8';
@@ -24453,7 +23798,7 @@ class AutocompleteComponent {
24453
23798
  this.enterBtnPosition = event.target['value'].length * 8 + 80;
24454
23799
  }
24455
23800
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24456
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AutocompleteComponent, isStandalone: true, selector: "gn-ui-autocomplete", inputs: { placeholder: "placeholder", enterButton: "enterButton", action: "action", value: "value", clearOnSelection: "clearOnSelection", preventCompleteOnSelection: "preventCompleteOnSelection", autoFocus: "autoFocus", minCharacterCount: "minCharacterCount", allowSubmit: "allowSubmit", forceTrackPosition: "forceTrackPosition", displayWithFn: "displayWithFn" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", inputCleared: "inputCleared", isSearchActive: "isSearchActive" }, providers: [
23801
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: AutocompleteComponent, isStandalone: true, selector: "gn-ui-autocomplete", inputs: { placeholder: "placeholder", enterButton: "enterButton", action: "action", value: "value", clearOnSelection: "clearOnSelection", preventCompleteOnSelection: "preventCompleteOnSelection", autoFocus: "autoFocus", minCharacterCount: "minCharacterCount", allowSubmit: "allowSubmit", forceTrackPosition: "forceTrackPosition", displayWithTemplate: "displayWithTemplate", displayWithFn: "displayWithFn" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", inputCleared: "inputCleared", isSearchActive: "isSearchActive" }, providers: [
24457
23802
  provideIcons({
24458
23803
  iconoirSearch,
24459
23804
  matClose,
@@ -24462,7 +23807,7 @@ class AutocompleteComponent {
24462
23807
  provideNgIconsConfig({
24463
23808
  size: '1.75rem',
24464
23809
  }),
24465
- ], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: MatAutocompleteTrigger, descendants: true }, { propertyName: "autocomplete", first: true, predicate: MatAutocomplete, descendants: true }, { propertyName: "inputRef", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<span class=\"w-full inline-block relative\">\n @if (!allowSubmit) {\n <div\n class=\"absolute inset-y-[--icon-padding] left-[--icon-padding] w-[--icon-width] pointer-events-none\"\n >\n <ng-icon name=\"iconoirSearch\" class=\"text-primary search\"></ng-icon>\n </div>\n }\n <div class=\"flex flex-row\">\n <input\n #searchInput\n type=\"text\"\n class=\"gn-ui-text-input\"\n (input)=\"handleInput($event)\"\n [placeholder]=\"placeholder\"\n [formControl]=\"control\"\n [matAutocomplete]=\"auto\"\n (keyup.enter)=\"handleSearch()\"\n [ngClass]=\"{\n 'text-primary': searchActive && enterButton,\n 'text-gray-900': !searchActive,\n 'px-[--icon-width]': !allowSubmit,\n }\"\n />\n @if (searchInput.value && displayEnterBtn) {\n <gn-ui-button\n type=\"gray\"\n extraClass=\"w-32 h-8 !opacity-100\"\n [ngStyle]=\"{ left: enterBtnPosition + 'px' }\"\n class=\"absolute\"\n disabled=\"true\"\n >\n <ng-icon\n name=\"iconoirLongArrowDownLeft\"\n class=\"!w-4 text-gray-900 font-bold\"\n ></ng-icon>\n <span translate class=\"text-bold text-gray-900 font-bold\">\n Enter to search\n </span>\n </gn-ui-button>\n }\n </div>\n @if (searchInput.value) {\n <gn-ui-button\n type=\"primary\"\n [extraClass]=\"getExtraClass()\"\n data-test=\"clear-btn\"\n aria-label=\"Clear\"\n (buttonClick)=\"clear()\"\n >\n <ng-icon class=\"text-white\" name=\"matClose\"></ng-icon>\n </gn-ui-button>\n }\n @if (allowSubmit) {\n <gn-ui-button\n type=\"light\"\n extraClass=\"border-0 border-l-[1px] border-gray-300 hover:border-gray-500 text-primary hover:text-primary-darkest focus:text-primary-darkest absolute inset-y-[--icon-padding] right-[--icon-padding]\"\n aria-label=\"Trigger search\"\n data-test=\"autocomplete-submit-btn\"\n (buttonClick)=\"handleSearch()\"\n >\n <ng-icon name=\"iconoirSearch\"></ng-icon>\n </gn-ui-button>\n }\n\n @if (error) {\n <gn-ui-popup-alert\n class=\"absolute mt-2 w-full top-[100%] left-0\"\n icon=\"matErrorOutlineOutline\"\n position=\"top\"\n type=\"warning\"\n >\n <span translate>search.autocomplete.error</span>\n {{ error }}\n </gn-ui-popup-alert>\n }\n</span>\n\n<mat-autocomplete\n #auto=\"matAutocomplete\"\n (optionSelected)=\"handleSelection($event)\"\n [displayWith]=\"displayWithFnInternal\"\n>\n @for (suggestion of suggestions$ | async; track suggestion) {\n <mat-option [value]=\"suggestion\" class=\"p-2 suggestion text-start\">\n {{ displayWithFnInternal(suggestion) }}\n </mat-option>\n }\n</mat-autocomplete>\n", styles: ["span{--icon-padding: var(--gn-ui-text-input-border-size, 2px);--icon-width: calc(var(--gn-ui-text-input-padding, .6em) * 2 + 1.25em)}span>*:not(gn-ui-popup-alert){font-size:var(--gn-ui-text-input-font-size, 1em)}input:placeholder-shown{text-overflow:ellipsis}gn-ui-button{--gn-ui-button-rounded: 0;--gn-ui-button-width: var(--icon-width);--gn-ui-button-padding: 0;font-size:1em}ng-icon.search{margin-top:.6rem;margin-left:.6rem}gn-ui-button:last-of-type{--gn-ui-button-rounded: 0 var(--gn-ui-text-input-rounded, .25em) var(--gn-ui-text-input-rounded, .25em) 0}.mat-mdc-option.suggestion.mat-mdc-option-active{background-color:var(--color-primary-lightest)}\n"], dependencies: [{ kind: "component", type: PopupAlertComponent, selector: "gn-ui-popup-alert", inputs: ["icon", "type", "position"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i1$2.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i1$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i1$2.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23810
+ ], viewQueries: [{ propertyName: "triggerRef", first: true, predicate: MatAutocompleteTrigger, descendants: true }, { propertyName: "autocomplete", first: true, predicate: MatAutocomplete, descendants: true }, { propertyName: "inputRef", first: true, predicate: ["searchInput"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<span class=\"w-full inline-block relative\">\n @if (!allowSubmit) {\n <div\n class=\"absolute inset-y-[--icon-padding] left-[--icon-padding] w-[--icon-width] pointer-events-none flex items-center justify-center\"\n >\n <ng-icon name=\"iconoirSearch\" class=\"text-primary\"></ng-icon>\n </div>\n }\n <div class=\"flex flex-row\">\n <input\n #searchInput\n type=\"text\"\n class=\"gn-ui-text-input\"\n (input)=\"handleInput($event)\"\n [placeholder]=\"placeholder\"\n [formControl]=\"control\"\n [matAutocomplete]=\"auto\"\n (keyup.enter)=\"handleSearch()\"\n [ngClass]=\"{\n 'text-primary': searchActive && enterButton,\n 'text-gray-900': !searchActive,\n 'px-[--icon-width]': !allowSubmit,\n }\"\n />\n @if (searchInput.value && displayEnterBtn) {\n <gn-ui-button\n type=\"gray\"\n extraClass=\"w-32 h-8 !opacity-100\"\n [ngStyle]=\"{ left: enterBtnPosition + 'px' }\"\n class=\"absolute\"\n disabled=\"true\"\n >\n <ng-icon\n name=\"iconoirLongArrowDownLeft\"\n class=\"!w-4 text-gray-900 font-bold\"\n ></ng-icon>\n <span translate class=\"text-bold text-gray-900 font-bold\">\n Enter to search\n </span>\n </gn-ui-button>\n }\n </div>\n @if (searchInput.value) {\n <gn-ui-button\n type=\"primary\"\n [extraClass]=\"getExtraClass()\"\n data-test=\"clear-btn\"\n aria-label=\"Clear\"\n (buttonClick)=\"clear()\"\n >\n <ng-icon class=\"text-white\" name=\"matClose\"></ng-icon>\n </gn-ui-button>\n }\n @if (allowSubmit) {\n <gn-ui-button\n type=\"light\"\n extraClass=\"border-0 border-l-[1px] border-gray-300 hover:border-gray-500 text-primary hover:text-primary-darkest focus:text-primary-darkest absolute inset-y-[--icon-padding] right-[--icon-padding]\"\n aria-label=\"Trigger search\"\n data-test=\"autocomplete-submit-btn\"\n (buttonClick)=\"handleSearch()\"\n >\n <ng-icon name=\"iconoirSearch\"></ng-icon>\n </gn-ui-button>\n }\n\n @if (error) {\n <gn-ui-popup-alert\n class=\"absolute mt-2 w-full top-[100%] left-0\"\n icon=\"matErrorOutlineOutline\"\n position=\"top\"\n type=\"warning\"\n >\n <span translate>search.autocomplete.error</span>\n {{ error }}\n </gn-ui-popup-alert>\n }\n</span>\n\n<mat-autocomplete\n #auto=\"matAutocomplete\"\n (optionSelected)=\"handleSelection($event)\"\n [displayWith]=\"displayWithFnInternal\"\n>\n @for (suggestion of suggestions$ | async; track suggestion) {\n <mat-option [value]=\"suggestion\" class=\"p-2 suggestion text-start\">\n @if (displayWithTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n displayWithTemplate;\n context: { $implicit: suggestion }\n \"\n ></ng-container>\n } @else {\n {{ displayWithFnInternal(suggestion) }}\n }\n </mat-option>\n }\n</mat-autocomplete>\n", styles: ["span{--icon-padding: var(--gn-ui-text-input-border-size, 2px);--icon-width: calc(var(--gn-ui-text-input-padding, .6em) * 2 + 1.25em)}span>*:not(gn-ui-popup-alert){font-size:var(--gn-ui-text-input-font-size, 1em)}input:placeholder-shown{text-overflow:ellipsis}gn-ui-button{--gn-ui-button-rounded: 0;--gn-ui-button-width: var(--icon-width);--gn-ui-button-padding: 0;font-size:1em}gn-ui-button:last-of-type{--gn-ui-button-rounded: 0 var(--gn-ui-text-input-rounded, .25em) var(--gn-ui-text-input-rounded, .25em) 0}.mat-mdc-option.suggestion.mat-mdc-option-active{background-color:var(--color-primary-lightest)}\n"], dependencies: [{ kind: "component", type: PopupAlertComponent, selector: "gn-ui-popup-alert", inputs: ["icon", "type", "position"] }, { kind: "ngmodule", type: MatAutocompleteModule }, { kind: "component", type: i1$2.MatAutocomplete, selector: "mat-autocomplete", inputs: ["aria-label", "aria-labelledby", "displayWith", "autoActiveFirstOption", "autoSelectActiveOption", "requireSelection", "panelWidth", "disableRipple", "class", "hideSingleSelectionIndicator"], outputs: ["optionSelected", "opened", "closed", "optionActivated"], exportAs: ["matAutocomplete"] }, { kind: "component", type: i1$2.MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: i1$2.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", inputs: ["matAutocomplete", "matAutocompletePosition", "matAutocompleteConnectedTo", "autocomplete", "matAutocompleteDisabled"], exportAs: ["matAutocompleteTrigger"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
24466
23811
  }
24467
23812
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, decorators: [{
24468
23813
  type: Component,
@@ -24483,7 +23828,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
24483
23828
  provideNgIconsConfig({
24484
23829
  size: '1.75rem',
24485
23830
  }),
24486
- ], template: "<span class=\"w-full inline-block relative\">\n @if (!allowSubmit) {\n <div\n class=\"absolute inset-y-[--icon-padding] left-[--icon-padding] w-[--icon-width] pointer-events-none\"\n >\n <ng-icon name=\"iconoirSearch\" class=\"text-primary search\"></ng-icon>\n </div>\n }\n <div class=\"flex flex-row\">\n <input\n #searchInput\n type=\"text\"\n class=\"gn-ui-text-input\"\n (input)=\"handleInput($event)\"\n [placeholder]=\"placeholder\"\n [formControl]=\"control\"\n [matAutocomplete]=\"auto\"\n (keyup.enter)=\"handleSearch()\"\n [ngClass]=\"{\n 'text-primary': searchActive && enterButton,\n 'text-gray-900': !searchActive,\n 'px-[--icon-width]': !allowSubmit,\n }\"\n />\n @if (searchInput.value && displayEnterBtn) {\n <gn-ui-button\n type=\"gray\"\n extraClass=\"w-32 h-8 !opacity-100\"\n [ngStyle]=\"{ left: enterBtnPosition + 'px' }\"\n class=\"absolute\"\n disabled=\"true\"\n >\n <ng-icon\n name=\"iconoirLongArrowDownLeft\"\n class=\"!w-4 text-gray-900 font-bold\"\n ></ng-icon>\n <span translate class=\"text-bold text-gray-900 font-bold\">\n Enter to search\n </span>\n </gn-ui-button>\n }\n </div>\n @if (searchInput.value) {\n <gn-ui-button\n type=\"primary\"\n [extraClass]=\"getExtraClass()\"\n data-test=\"clear-btn\"\n aria-label=\"Clear\"\n (buttonClick)=\"clear()\"\n >\n <ng-icon class=\"text-white\" name=\"matClose\"></ng-icon>\n </gn-ui-button>\n }\n @if (allowSubmit) {\n <gn-ui-button\n type=\"light\"\n extraClass=\"border-0 border-l-[1px] border-gray-300 hover:border-gray-500 text-primary hover:text-primary-darkest focus:text-primary-darkest absolute inset-y-[--icon-padding] right-[--icon-padding]\"\n aria-label=\"Trigger search\"\n data-test=\"autocomplete-submit-btn\"\n (buttonClick)=\"handleSearch()\"\n >\n <ng-icon name=\"iconoirSearch\"></ng-icon>\n </gn-ui-button>\n }\n\n @if (error) {\n <gn-ui-popup-alert\n class=\"absolute mt-2 w-full top-[100%] left-0\"\n icon=\"matErrorOutlineOutline\"\n position=\"top\"\n type=\"warning\"\n >\n <span translate>search.autocomplete.error</span>\n {{ error }}\n </gn-ui-popup-alert>\n }\n</span>\n\n<mat-autocomplete\n #auto=\"matAutocomplete\"\n (optionSelected)=\"handleSelection($event)\"\n [displayWith]=\"displayWithFnInternal\"\n>\n @for (suggestion of suggestions$ | async; track suggestion) {\n <mat-option [value]=\"suggestion\" class=\"p-2 suggestion text-start\">\n {{ displayWithFnInternal(suggestion) }}\n </mat-option>\n }\n</mat-autocomplete>\n", styles: ["span{--icon-padding: var(--gn-ui-text-input-border-size, 2px);--icon-width: calc(var(--gn-ui-text-input-padding, .6em) * 2 + 1.25em)}span>*:not(gn-ui-popup-alert){font-size:var(--gn-ui-text-input-font-size, 1em)}input:placeholder-shown{text-overflow:ellipsis}gn-ui-button{--gn-ui-button-rounded: 0;--gn-ui-button-width: var(--icon-width);--gn-ui-button-padding: 0;font-size:1em}ng-icon.search{margin-top:.6rem;margin-left:.6rem}gn-ui-button:last-of-type{--gn-ui-button-rounded: 0 var(--gn-ui-text-input-rounded, .25em) var(--gn-ui-text-input-rounded, .25em) 0}.mat-mdc-option.suggestion.mat-mdc-option-active{background-color:var(--color-primary-lightest)}\n"] }]
23831
+ ], template: "<span class=\"w-full inline-block relative\">\n @if (!allowSubmit) {\n <div\n class=\"absolute inset-y-[--icon-padding] left-[--icon-padding] w-[--icon-width] pointer-events-none flex items-center justify-center\"\n >\n <ng-icon name=\"iconoirSearch\" class=\"text-primary\"></ng-icon>\n </div>\n }\n <div class=\"flex flex-row\">\n <input\n #searchInput\n type=\"text\"\n class=\"gn-ui-text-input\"\n (input)=\"handleInput($event)\"\n [placeholder]=\"placeholder\"\n [formControl]=\"control\"\n [matAutocomplete]=\"auto\"\n (keyup.enter)=\"handleSearch()\"\n [ngClass]=\"{\n 'text-primary': searchActive && enterButton,\n 'text-gray-900': !searchActive,\n 'px-[--icon-width]': !allowSubmit,\n }\"\n />\n @if (searchInput.value && displayEnterBtn) {\n <gn-ui-button\n type=\"gray\"\n extraClass=\"w-32 h-8 !opacity-100\"\n [ngStyle]=\"{ left: enterBtnPosition + 'px' }\"\n class=\"absolute\"\n disabled=\"true\"\n >\n <ng-icon\n name=\"iconoirLongArrowDownLeft\"\n class=\"!w-4 text-gray-900 font-bold\"\n ></ng-icon>\n <span translate class=\"text-bold text-gray-900 font-bold\">\n Enter to search\n </span>\n </gn-ui-button>\n }\n </div>\n @if (searchInput.value) {\n <gn-ui-button\n type=\"primary\"\n [extraClass]=\"getExtraClass()\"\n data-test=\"clear-btn\"\n aria-label=\"Clear\"\n (buttonClick)=\"clear()\"\n >\n <ng-icon class=\"text-white\" name=\"matClose\"></ng-icon>\n </gn-ui-button>\n }\n @if (allowSubmit) {\n <gn-ui-button\n type=\"light\"\n extraClass=\"border-0 border-l-[1px] border-gray-300 hover:border-gray-500 text-primary hover:text-primary-darkest focus:text-primary-darkest absolute inset-y-[--icon-padding] right-[--icon-padding]\"\n aria-label=\"Trigger search\"\n data-test=\"autocomplete-submit-btn\"\n (buttonClick)=\"handleSearch()\"\n >\n <ng-icon name=\"iconoirSearch\"></ng-icon>\n </gn-ui-button>\n }\n\n @if (error) {\n <gn-ui-popup-alert\n class=\"absolute mt-2 w-full top-[100%] left-0\"\n icon=\"matErrorOutlineOutline\"\n position=\"top\"\n type=\"warning\"\n >\n <span translate>search.autocomplete.error</span>\n {{ error }}\n </gn-ui-popup-alert>\n }\n</span>\n\n<mat-autocomplete\n #auto=\"matAutocomplete\"\n (optionSelected)=\"handleSelection($event)\"\n [displayWith]=\"displayWithFnInternal\"\n>\n @for (suggestion of suggestions$ | async; track suggestion) {\n <mat-option [value]=\"suggestion\" class=\"p-2 suggestion text-start\">\n @if (displayWithTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n displayWithTemplate;\n context: { $implicit: suggestion }\n \"\n ></ng-container>\n } @else {\n {{ displayWithFnInternal(suggestion) }}\n }\n </mat-option>\n }\n</mat-autocomplete>\n", styles: ["span{--icon-padding: var(--gn-ui-text-input-border-size, 2px);--icon-width: calc(var(--gn-ui-text-input-padding, .6em) * 2 + 1.25em)}span>*:not(gn-ui-popup-alert){font-size:var(--gn-ui-text-input-font-size, 1em)}input:placeholder-shown{text-overflow:ellipsis}gn-ui-button{--gn-ui-button-rounded: 0;--gn-ui-button-width: var(--icon-width);--gn-ui-button-padding: 0;font-size:1em}gn-ui-button:last-of-type{--gn-ui-button-rounded: 0 var(--gn-ui-text-input-rounded, .25em) var(--gn-ui-text-input-rounded, .25em) 0}.mat-mdc-option.suggestion.mat-mdc-option-active{background-color:var(--color-primary-lightest)}\n"] }]
24487
23832
  }], propDecorators: { placeholder: [{
24488
23833
  type: Input
24489
23834
  }], enterButton: [{
@@ -24521,6 +23866,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
24521
23866
  }], inputRef: [{
24522
23867
  type: ViewChild,
24523
23868
  args: ['searchInput']
23869
+ }], displayWithTemplate: [{
23870
+ type: Input
24524
23871
  }], displayWithFn: [{
24525
23872
  type: Input
24526
23873
  }] } });
@@ -25005,7 +24352,7 @@ class DropdownMultiselectComponent {
25005
24352
  }
25006
24353
  setFocus() {
25007
24354
  setTimeout(() => {
25008
- this.searchFieldInput.nativeElement.focus();
24355
+ this.searchFieldInput?.nativeElement.focus();
25009
24356
  }, 0);
25010
24357
  }
25011
24358
  openOverlay() {
@@ -25111,7 +24458,10 @@ class DropdownMultiselectComponent {
25111
24458
  matExpandMore,
25112
24459
  matExpandLess,
25113
24460
  }),
25114
- ], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "overlayContainer", first: true, predicate: ["overlayContainer"], descendants: true, read: ElementRef }, { propertyName: "searchFieldInput", first: true, predicate: ["searchFieldInput"], descendants: true }, { propertyName: "checkboxes", predicate: ["checkBox"], descendants: true, read: ElementRef }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-test=\"dropdown-clear\">\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-[2px] flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity mb-1\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
24461
+ provideNgIconsConfig({
24462
+ size: '1.5rem',
24463
+ }),
24464
+ ], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "overlayContainer", first: true, predicate: ["overlayContainer"], descendants: true, read: ElementRef }, { propertyName: "searchFieldInput", first: true, predicate: ["searchFieldInput"], descendants: true }, { propertyName: "checkboxes", predicate: ["checkBox"], descendants: true, read: ElementRef }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button\n class=\"h-6 w-6 flex items-center justify-center\"\n data-test=\"dropdown-clear\"\n >\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-1 flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
25115
24465
  }
25116
24466
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: DropdownMultiselectComponent, decorators: [{
25117
24467
  type: Component,
@@ -25121,7 +24471,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
25121
24471
  matExpandMore,
25122
24472
  matExpandLess,
25123
24473
  }),
25124
- ], standalone: true, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button class=\"h-6 w-6\" data-test=\"dropdown-clear\">\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-[2px] flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity mb-1\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n" }]
24474
+ provideNgIconsConfig({
24475
+ size: '1.5rem',
24476
+ }),
24477
+ ], standalone: true, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n [attr.aria-owns]=\"id\"\n (buttonClick)=\"openOverlay()\"\n (keydown)=\"handleTriggerKeydown($event)\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelectedChoices) {\n <div\n class=\"gn-ui-multiselect-counter shrink-0 rounded-full font-bold text-[12px] w-5 h-5 flex items-center justify-center mr-1 selected-count\"\n >\n {{ selected.length }}\n </div>\n }\n </div>\n <button\n class=\"h-6 w-6 flex items-center justify-center\"\n data-test=\"dropdown-clear\"\n >\n @if (hasSelectedChoices && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"clearSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-300 rounded shadow-lg py-2 w-full overflow-x-hidden overflow-y-auto overlay-container\"\n [style.max-height]=\"overlayMaxHeight\"\n [style.min-width]=\"overlayMinWidth\"\n role=\"listbox\"\n tabindex=\"-1\"\n [attr.id]=\"id\"\n [attr.aria-multiselectable]=\"true\"\n [attr.aria-label]=\"title\"\n (keydown)=\"handleOverlayKeydown($event)\"\n #overlayContainer\n >\n <div\n class=\"border border-gray-300 rounded mb-2 mx-2 min-h-[44px] flex flex-row gap-1 flex-wrap p-2 focus-within:rounded focus-within:border-2 focus-within:border-primary\"\n >\n @for (selected of selectedChoices; track selected) {\n <button\n type=\"button\"\n [title]=\"selected.label\"\n class=\"max-w-full bg-main text-white rounded pr-[7px] flex gap-1 items-center opacity-70 hover:opacity-100 focus:opacity-100 transition-opacity\"\n (click)=\"select(selected, false)\"\n >\n <div class=\"text-sm truncate leading-[26px] px-2\">\n {{ selected.label }}\n </div>\n <div\n class=\"flex items-center justify-center rounded-full bg-white text-main h-[13px] w-[13px] pt-px -mt-px shrink-0\"\n >\n <ng-icon\n name=\"matClose\"\n class=\"!h-[12px] !w-[11px] text-[12px]\"\n ></ng-icon>\n </div>\n </button>\n }\n\n @if (allowSearch) {\n <div class=\"w-[50%] relative grow shrink\">\n <input\n #searchFieldInput\n class=\"w-full px-2 truncate text-[14px] h-full overlaySearchInput focus:outline-none\"\n [(ngModel)]=\"searchInputValue\"\n [placeholder]=\"'multiselect.filter.placeholder' | translate\"\n />\n @if (!!searchInputValue) {\n <button\n class=\"absolute top-1/2 -translate-y-1/2 right-0 px-[7px] leading-tight clear-search-input mr-2\"\n (click)=\"clearSearchInputValue($event)\"\n >\n <ng-icon class=\"!h-[10px] !w-[12px] text-[12px]\" name=\"matClose\">\n </ng-icon>\n </button>\n }\n </div>\n }\n </div>\n\n @for (choice of filteredChoicesByText; track choice) {\n <label\n [title]=\"choice.label\"\n class=\"flex px-5 py-1 w-full text-gray-900 cursor-pointer hover:text-primary-darkest hover:bg-gray-50 focus-within:text-primary-darkest focus-within:bg-gray-50 transition-colors\"\n >\n <input\n class=\"w-[18px] h-[18px] align-text-top shrink-0\"\n type=\"checkbox\"\n #checkBox\n [checked]=\"isSelected(choice)\"\n (change)=\"select(choice, checkBox.checked)\"\n />\n <span class=\"ml-[8px] text-[14px] truncate\">\n {{ choice.label }}\n </span>\n </label>\n }\n </div>\n</ng-template>\n" }]
25125
24478
  }], propDecorators: { title: [{
25126
24479
  type: Input
25127
24480
  }], choices: [{
@@ -25951,7 +25304,8 @@ class SearchFeatureCatalogComponent {
25951
25304
  const filtered = (this.featureCatalog?.featureTypes || []).filter((featureType) => {
25952
25305
  const fuzzyFilter = createFuzzyFilter(searchTerm);
25953
25306
  return (fuzzyFilter(featureType.name) ||
25954
- (featureType.definition && fuzzyFilter(featureType.definition)));
25307
+ (featureType.description &&
25308
+ fuzzyFilter(featureType.description)));
25955
25309
  });
25956
25310
  this.filteredFeatureCatalog = {
25957
25311
  ...this.featureCatalog,
@@ -26036,8 +25390,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
26036
25390
  marker('search.filters.spatialExtent.import');
26037
25391
  marker('search.filters.spatialExtent.helpText');
26038
25392
  marker('search.filters.spatialExtent.error.title');
25393
+ marker('search.filters.spatialExtent.error.outOfBounds');
26039
25394
  const LABEL_FROM_FILE = marker('search.filters.spatialExtent.bboxFromFile');
26040
25395
  const LABEL_FROM_FILE_DELETE = marker('search.filters.spatialExtent.bboxFromFileDelete');
25396
+ const LABEL_FROM_LOCATION = marker('search.filters.spatialExtent.bboxFromLocation');
25397
+ const LABEL_FROM_LOCATION_DELETE = marker('search.filters.spatialExtent.bboxFromLocationDelete');
26041
25398
  const LABEL_INITIAL = marker('search.filters.spatialExtent.bboxInitial');
26042
25399
  const LABEL_INITIAL_DELETE = marker('search.filters.spatialExtent.bboxInitialDelete');
26043
25400
  class SpatialExtentDropdownComponent {
@@ -26049,6 +25406,7 @@ class SpatialExtentDropdownComponent {
26049
25406
  this.errorChange = new EventEmitter();
26050
25407
  this.bbox = null;
26051
25408
  this.fileName = '';
25409
+ this.locationName = '';
26052
25410
  this.overlayPositions = [
26053
25411
  {
26054
25412
  originX: 'start',
@@ -26079,13 +25437,21 @@ class SpatialExtentDropdownComponent {
26079
25437
  return !!this.bbox;
26080
25438
  }
26081
25439
  get selectionLabelKey() {
26082
- return this.fileName ? LABEL_FROM_FILE : LABEL_INITIAL;
25440
+ if (this.fileName)
25441
+ return LABEL_FROM_FILE;
25442
+ if (this.locationName)
25443
+ return LABEL_FROM_LOCATION;
25444
+ return LABEL_INITIAL;
26083
25445
  }
26084
25446
  get selectionDeleteLabelKey() {
26085
- return this.fileName ? LABEL_FROM_FILE_DELETE : LABEL_INITIAL_DELETE;
25447
+ if (this.fileName)
25448
+ return LABEL_FROM_FILE_DELETE;
25449
+ if (this.locationName)
25450
+ return LABEL_FROM_LOCATION_DELETE;
25451
+ return LABEL_INITIAL_DELETE;
26086
25452
  }
26087
25453
  get selectionLabelParams() {
26088
- return { fileName: this.fileName };
25454
+ return { fileName: this.fileName, locationName: this.locationName };
26089
25455
  }
26090
25456
  openOverlay() {
26091
25457
  this.overlayMinWidth =
@@ -26116,8 +25482,13 @@ class SpatialExtentDropdownComponent {
26116
25482
  return;
26117
25483
  }
26118
25484
  const bbox = getGeometryBoundingBox(geometry);
25485
+ if (!isBoundingBoxWithinWorldExtent(bbox)) {
25486
+ this.setError(marker('search.filters.spatialExtent.error.outOfBounds'));
25487
+ return;
25488
+ }
26119
25489
  this.bbox = bbox;
26120
25490
  this.fileName = file.name;
25491
+ this.locationName = '';
26121
25492
  this.bboxChange.emit(bbox);
26122
25493
  this.cd.markForCheck();
26123
25494
  }
@@ -26126,6 +25497,15 @@ class SpatialExtentDropdownComponent {
26126
25497
  return;
26127
25498
  }
26128
25499
  }
25500
+ setLocationBbox(bbox, name) {
25501
+ this.errorKey = null;
25502
+ this.bbox = bbox;
25503
+ this.locationName = name;
25504
+ this.fileName = '';
25505
+ this.fileInput?.clear();
25506
+ this.bboxChange.emit(bbox);
25507
+ this.cd.markForCheck();
25508
+ }
26129
25509
  handleFileError(error) {
26130
25510
  if (error === 'file-too-large') {
26131
25511
  this.setError(marker('search.filters.spatialExtent.error.fileTooLarge'), {
@@ -26144,6 +25524,7 @@ class SpatialExtentDropdownComponent {
26144
25524
  removeSelection(event) {
26145
25525
  this.bbox = null;
26146
25526
  this.fileName = '';
25527
+ this.locationName = '';
26147
25528
  this.errorKey = null;
26148
25529
  this.fileInput?.clear();
26149
25530
  this.bboxChange.emit(null);
@@ -26153,14 +25534,14 @@ class SpatialExtentDropdownComponent {
26153
25534
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: SpatialExtentDropdownComponent, isStandalone: true, selector: "gn-ui-spatial-extent-dropdown", inputs: { title: "title", maxFileSizeMb: "maxFileSizeMb", initialBbox: "initialBbox" }, outputs: { bboxChange: "bboxChange", errorChange: "errorChange" }, providers: [
26154
25535
  provideIcons({
26155
25536
  iconoirCheckCircle,
26156
- iconoirImport,
26157
25537
  iconoirSquareDashed,
26158
25538
  iconoirTrash,
25539
+ iconoirUpload,
26159
25540
  matClose,
26160
25541
  matExpandLess,
26161
25542
  matExpandMore,
26162
25543
  }),
26163
- ], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "fileInput", first: true, predicate: DragAndDropFileInputComponent, descendants: true }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[8px]') + ' text-black'\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirImport\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"selectionDeleteLabelKey | translate: selectionLabelParams\"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ selectionLabelKey | translate: selectionLabelParams }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ selectionDeleteLabelKey | translate: selectionLabelParams }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: DragAndDropFileInputComponent, selector: "gn-ui-drag-and-drop-file-input", inputs: ["placeholder", "accept", "maxFileSizeMb", "icon", "dropzoneBackgroundColor", "textClass", "extraClass", "showFileName"], outputs: ["fileChange", "errorChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
25544
+ ], viewQueries: [{ propertyName: "overlayOrigin", first: true, predicate: ["overlayOrigin"], descendants: true }, { propertyName: "overlay", first: true, predicate: CdkConnectedOverlay, descendants: true }, { propertyName: "fileInput", first: true, predicate: DragAndDropFileInputComponent, descendants: true }], ngImport: i0, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[12px]') + ' text-black flex flex-col gap-[8px]'\n \"\n style=\"\n --gn-ui-text-input-rounded: 8px;\n --gn-ui-text-input-border-size: 1px;\n --gn-ui-text-input-padding: 6px;\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirUpload\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n <ng-content></ng-content>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"selectionDeleteLabelKey | translate: selectionLabelParams\"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ selectionLabelKey | translate: selectionLabelParams }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ selectionDeleteLabelKey | translate: selectionLabelParams }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n", styles: [""], dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1$7.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1$7.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: DragAndDropFileInputComponent, selector: "gn-ui-drag-and-drop-file-input", inputs: ["placeholder", "accept", "maxFileSizeMb", "icon", "dropzoneBackgroundColor", "textClass", "extraClass", "showFileName"], outputs: ["fileChange", "errorChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
26164
25545
  }
26165
25546
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, decorators: [{
26166
25547
  type: Component,
@@ -26173,14 +25554,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
26173
25554
  ], providers: [
26174
25555
  provideIcons({
26175
25556
  iconoirCheckCircle,
26176
- iconoirImport,
26177
25557
  iconoirSquareDashed,
26178
25558
  iconoirTrash,
25559
+ iconoirUpload,
26179
25560
  matClose,
26180
25561
  matExpandLess,
26181
25562
  matExpandMore,
26182
25563
  }),
26183
- ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[8px]') + ' text-black'\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirImport\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"selectionDeleteLabelKey | translate: selectionLabelParams\"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ selectionLabelKey | translate: selectionLabelParams }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ selectionDeleteLabelKey | translate: selectionLabelParams }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n" }]
25564
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<gn-ui-button\n type=\"outline\"\n extraClass=\"bg-background w-full !p-[8px] !pl-[16px]\"\n [title]=\"title\"\n (buttonClick)=\"toggleOverlay()\"\n cdkOverlayOrigin\n #overlayOrigin=\"cdkOverlayOrigin\"\n>\n <div class=\"grow flex items-center mr-2 gap-2 overflow-hidden\">\n <div class=\"text-left font-medium truncate py-1\">\n {{ title }}\n </div>\n @if (hasSelection) {\n <div\n class=\"bg-primary-lighter text-white shrink-0 rounded-full font-bold text-[12px] w-[22px] h-[22px] flex items-center justify-center\"\n >\n 1\n </div>\n }\n </div>\n <button class=\"h-6 w-6 flex items-center\" data-cy=\"clearSelection\">\n @if (hasSelection && !overlayOpen) {\n <ng-icon\n class=\"shrink-0 opacity-40 mr-1.5 hover:opacity-80 transition-colors clear-btn\"\n (click)=\"removeSelection($event)\"\n name=\"matClose\"\n ></ng-icon>\n }\n </button>\n <ng-icon\n [name]=\"overlayOpen ? 'matExpandLess' : 'matExpandMore'\"\n class=\"shrink-0 opacity-40\"\n >\n </ng-icon>\n</gn-ui-button>\n\n<ng-template\n cdkConnectedOverlay\n cdkConnectedOverlayHasBackdrop\n cdkConnectedOverlayBackdropClass=\"cdk-overlay-transparent-backdrop\"\n [cdkConnectedOverlayOrigin]=\"overlayOrigin\"\n [cdkConnectedOverlayOpen]=\"overlayOpen\"\n [cdkConnectedOverlayPositions]=\"overlayPositions\"\n [cdkConnectedOverlayScrollStrategy]=\"scrollStrategy\"\n [cdkConnectedOverlayFlexibleDimensions]=\"true\"\n (overlayOutsideClick)=\"closeOverlay()\"\n (detach)=\"closeOverlay()\"\n>\n <div\n class=\"bg-white border border-gray-400 rounded shadow-lg pt-[12px] px-[16px] overlay-container w-[280px] flex flex-col gap-2\"\n [style.min-width]=\"overlayMinWidth\"\n >\n <div class=\"text-xs text-black\">\n {{ 'search.filters.spatialExtent.helpText' | translate }}\n </div>\n\n <div\n [class]=\"\n (hasSelection\n ? 'border-b-[1px] border-gray-400 pb-[20px]'\n : 'pb-[12px]') + ' text-black flex flex-col gap-[8px]'\n \"\n style=\"\n --gn-ui-text-input-rounded: 8px;\n --gn-ui-text-input-border-size: 1px;\n --gn-ui-text-input-padding: 6px;\n \"\n >\n <gn-ui-drag-and-drop-file-input\n accept=\".json,.geojson\"\n [placeholder]=\"'search.filters.spatialExtent.import' | translate\"\n [maxFileSizeMb]=\"maxFileSizeMb\"\n [showFileName]=\"false\"\n textClass=\"text-black truncate\"\n dropzoneBackgroundColor=\"transparent\"\n icon=\"iconoirUpload\"\n extraClass=\"gn-ui-gray-outline-input w-full !h-[32px] px-[8px] py-[4px] justify-between\"\n (fileChange)=\"handleFileSelected($event)\"\n (errorChange)=\"handleFileError($event)\"\n data-cy=\"importGeojson\"\n ></gn-ui-drag-and-drop-file-input>\n <ng-content></ng-content>\n </div>\n\n @if (hasSelection) {\n <gn-ui-button\n [type]=\"'primary-light'\"\n [title]=\"selectionDeleteLabelKey | translate: selectionLabelParams\"\n (buttonClick)=\"removeSelection($event)\"\n extraClass=\"group gap-x-2 w-full h-[28px] px-[8px] py-[4px] mb-[12px] bg-primary-lighter text-white\"\n data-test=\"spatial-extent-selected-item\"\n >\n <ng-icon\n name=\"iconoirSquareDashed\"\n class=\"shrink-0\"\n size=\"15px\"\n ></ng-icon>\n <span class=\"group-hover:hidden truncate text-sm m-auto\">\n {{ selectionLabelKey | translate: selectionLabelParams }}\n </span>\n <span class=\"hidden group-hover:block truncate text-sm m-auto\">\n {{ selectionDeleteLabelKey | translate: selectionLabelParams }}\n </span>\n <ng-icon\n name=\"iconoirCheckCircle\"\n class=\"group-hover:hidden shrink-0\"\n size=\"14px\"\n ></ng-icon>\n <ng-icon\n name=\"iconoirTrash\"\n class=\"!hidden group-hover:!block shrink-0\"\n size=\"15px\"\n ></ng-icon>\n </gn-ui-button>\n }\n </div>\n</ng-template>\n" }]
26184
25565
  }], propDecorators: { title: [{
26185
25566
  type: Input
26186
25567
  }], maxFileSizeMb: [{
@@ -26706,11 +26087,11 @@ class BlockListComponent {
26706
26087
  this.goToPage(this.currentPage + 1);
26707
26088
  }
26708
26089
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: BlockListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
26709
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: BlockListComponent, isStandalone: true, selector: "gn-ui-block-list", inputs: { containerClass: "containerClass", paginationContainerClass: "paginationContainerClass" }, outputs: { listChanges: "listChanges" }, host: { listeners: { "window:resize": "onResize()" } }, queries: [{ propertyName: "blocks", predicate: ["block"], read: ElementRef }], viewQueries: [{ propertyName: "blockContainer", first: true, predicate: ["blockContainer"], descendants: true }], ngImport: i0, template: "<div\n class=\"grid gap-4 w-full sm:grid-cols-2\"\n #blockContainer\n [ngClass]=\"[containerClass, 'size-' + subComponentSize]\"\n>\n <ng-content></ng-content>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + paginationContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host .block-list-container ::ng-deep>*{flex-shrink:0}:host{position:relative}@media screen and (min-width: 769px){.size-L{grid-template-columns:repeat(1,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-M{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-S{grid-template-columns:repeat(3,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-XS{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PaginationDotsComponent, selector: "gn-ui-pagination-dots", inputs: ["listComponent", "containerClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
26090
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: BlockListComponent, isStandalone: true, selector: "gn-ui-block-list", inputs: { containerClass: "containerClass", paginationContainerClass: "paginationContainerClass" }, outputs: { listChanges: "listChanges" }, host: { listeners: { "window:resize": "onResize()" } }, queries: [{ propertyName: "blocks", predicate: ["block"], read: ElementRef }], viewQueries: [{ propertyName: "blockContainer", first: true, predicate: ["blockContainer"], descendants: true }], ngImport: i0, template: "<div\n class=\"grid gap-4 w-full sm:grid-cols-2\"\n #blockContainer\n [ngClass]=\"[containerClass, 'size-' + subComponentSize]\"\n>\n <ng-content></ng-content>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + paginationContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host .block-list-container ::ng-deep>*{flex-shrink:0}:host{display:block;position:relative}@media screen and (min-width: 769px){.size-L{grid-template-columns:repeat(1,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-M{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-S{grid-template-columns:repeat(3,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-XS{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: PaginationDotsComponent, selector: "gn-ui-pagination-dots", inputs: ["listComponent", "containerClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
26710
26091
  }
26711
26092
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: BlockListComponent, decorators: [{
26712
26093
  type: Component,
26713
- args: [{ selector: 'gn-ui-block-list', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, PaginationDotsComponent], template: "<div\n class=\"grid gap-4 w-full sm:grid-cols-2\"\n #blockContainer\n [ngClass]=\"[containerClass, 'size-' + subComponentSize]\"\n>\n <ng-content></ng-content>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + paginationContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host .block-list-container ::ng-deep>*{flex-shrink:0}:host{position:relative}@media screen and (min-width: 769px){.size-L{grid-template-columns:repeat(1,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-M{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-S{grid-template-columns:repeat(3,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-XS{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}}\n"] }]
26094
+ args: [{ selector: 'gn-ui-block-list', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, PaginationDotsComponent], template: "<div\n class=\"grid gap-4 w-full sm:grid-cols-2\"\n #blockContainer\n [ngClass]=\"[containerClass, 'size-' + subComponentSize]\"\n>\n <ng-content></ng-content>\n</div>\n<gn-ui-pagination-dots\n [containerClass]=\"'absolute ' + paginationContainerClass\"\n [listComponent]=\"this\"\n></gn-ui-pagination-dots>\n", styles: [":host .block-list-container ::ng-deep>*{flex-shrink:0}:host{display:block;position:relative}@media screen and (min-width: 769px){.size-L{grid-template-columns:repeat(1,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-M{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-S{grid-template-columns:repeat(3,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}.size-XS{grid-template-columns:repeat(2,minmax(0,1fr));grid-auto-rows:minmax(0,min-content)}}\n"] }]
26714
26095
  }], propDecorators: { containerClass: [{
26715
26096
  type: Input
26716
26097
  }], paginationContainerClass: [{
@@ -27449,9 +26830,7 @@ const initSearch = () => {
27449
26830
  },
27450
26831
  params: {
27451
26832
  filters: {},
27452
- pageSize: getOptionalSearchConfig()?.LIMIT
27453
- ? getOptionalSearchConfig().LIMIT
27454
- : DEFAULT_PAGE_SIZE,
26833
+ pageSize: DEFAULT_PAGE_SIZE,
27455
26834
  currentPage: 0,
27456
26835
  favoritesOnly: false,
27457
26836
  useSpatialFilter: true,
@@ -27900,6 +27279,146 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
27900
27279
  }]
27901
27280
  }] });
27902
27281
 
27282
+ const DEFAULT_GEOCODING_PROVIDER = [
27283
+ 'geonames',
27284
+ { maxRows: 5 },
27285
+ ];
27286
+ const GEOCODING_PROVIDER = new InjectionToken('geocoding-provider', {
27287
+ providedIn: 'root',
27288
+ factory: () => DEFAULT_GEOCODING_PROVIDER,
27289
+ });
27290
+ // these options are arrays in the providers, but they can be configured
27291
+ // with a single value for simplicity
27292
+ const GEOCODING_PROVIDER_ARRAY_OPTIONS = {
27293
+ geoadmin: ['origins', 'features'],
27294
+ geoplateforme: [
27295
+ 'index',
27296
+ 'category',
27297
+ 'type',
27298
+ 'postCode',
27299
+ 'cityCode',
27300
+ 'depCode',
27301
+ ],
27302
+ };
27303
+ function wrapArrayOptions(options, keys) {
27304
+ const wrapped = { ...options };
27305
+ for (const key of keys) {
27306
+ if (typeof wrapped[key] === 'string') {
27307
+ wrapped[key] = [wrapped[key]];
27308
+ }
27309
+ }
27310
+ return wrapped;
27311
+ }
27312
+ class GeocodingService {
27313
+ constructor() {
27314
+ this.provider = inject(GEOCODING_PROVIDER);
27315
+ }
27316
+ query(text) {
27317
+ let queryObservable;
27318
+ switch (this.provider[0]) {
27319
+ case 'geoadmin':
27320
+ queryObservable = from(queryGeoadmin(text, wrapArrayOptions(this.provider[1], GEOCODING_PROVIDER_ARRAY_OPTIONS.geoadmin)));
27321
+ break;
27322
+ case 'geonames':
27323
+ queryObservable = from(queryGeonames(text, this.provider[1]));
27324
+ break;
27325
+ case 'geoplateforme':
27326
+ queryObservable = from(queryGeoplateforme(text, {
27327
+ ...wrapArrayOptions(this.provider[1], GEOCODING_PROVIDER_ARRAY_OPTIONS.geoplateforme),
27328
+ returnTrueGeometry: true,
27329
+ }));
27330
+ break;
27331
+ default:
27332
+ return throwError(() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`));
27333
+ }
27334
+ return queryObservable.pipe(catchError((error) => throwError(error)));
27335
+ }
27336
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
27337
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, providedIn: 'root' }); }
27338
+ }
27339
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingService, decorators: [{
27340
+ type: Injectable,
27341
+ args: [{
27342
+ providedIn: 'root',
27343
+ }]
27344
+ }] });
27345
+
27346
+ const GEOCODING_PROVIDER_LABELS = new InjectionToken('geocodingProviderLabels', {
27347
+ factory: () => ({}),
27348
+ });
27349
+ class LocationSearchComponent {
27350
+ constructor() {
27351
+ this.geocodingService = inject(GeocodingService);
27352
+ this.labels = inject(GEOCODING_PROVIDER_LABELS);
27353
+ this.placeholder = '';
27354
+ this.resultSelected = new EventEmitter();
27355
+ this.bboxSelected = new EventEmitter();
27356
+ this.displayWithFn = (item) => item.label;
27357
+ this.searchAction = (text) => this.geocodingService.query(text);
27358
+ }
27359
+ getSecondaryLabel(result) {
27360
+ return this.resolveLabel(result, this.labels.secondary);
27361
+ }
27362
+ getMainLabel(result) {
27363
+ return this.resolveLabel(result, this.labels.main) ?? result.label;
27364
+ }
27365
+ getTertiaryLabel(result) {
27366
+ return this.resolveLabel(result, this.labels.tertiary);
27367
+ }
27368
+ getDisplayLabel(result) {
27369
+ const tertiary = this.getTertiaryLabel(result);
27370
+ return this.getMainLabel(result) + (tertiary ? ', ' + tertiary : '');
27371
+ }
27372
+ resolveLabel(result, path) {
27373
+ if (!path)
27374
+ return undefined;
27375
+ let value;
27376
+ try {
27377
+ value = pointer.get(result, path);
27378
+ }
27379
+ catch {
27380
+ return undefined;
27381
+ }
27382
+ const values = Array.isArray(value) ? value : [value];
27383
+ const label = values
27384
+ .filter((v) => typeof v === 'string' || typeof v === 'number')
27385
+ .join(', ');
27386
+ return label || undefined;
27387
+ }
27388
+ // geoplateforme keeps a simplified geometry in geom and puts the real one,
27389
+ // as a JSON string, in properties.truegeometry when returnTrueGeometry is set
27390
+ getGeometry(result) {
27391
+ const trueGeometry = result.properties?.['truegeometry'];
27392
+ if (typeof trueGeometry === 'string') {
27393
+ return JSON.parse(trueGeometry);
27394
+ }
27395
+ return trueGeometry ?? result.geom;
27396
+ }
27397
+ handleItemSelected(item) {
27398
+ const result = item;
27399
+ this.resultSelected.emit(result);
27400
+ const geometry = this.getGeometry(result);
27401
+ if (geometry) {
27402
+ this.bboxSelected.emit({
27403
+ bbox: getGeometryBoundingBox(geometry),
27404
+ label: this.getDisplayLabel(result),
27405
+ });
27406
+ }
27407
+ }
27408
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
27409
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: LocationSearchComponent, isStandalone: true, selector: "gn-ui-location-search", inputs: { placeholder: "placeholder" }, outputs: { resultSelected: "resultSelected", bboxSelected: "bboxSelected" }, ngImport: i0, template: "<gn-ui-autocomplete\n [action]=\"searchAction\"\n [displayWithFn]=\"displayWithFn\"\n [placeholder]=\"placeholder\"\n [displayWithTemplate]=\"defaultItemTpl\"\n [clearOnSelection]=\"true\"\n (itemSelected)=\"handleItemSelected($event)\"\n>\n</gn-ui-autocomplete>\n\n<ng-template #defaultItemTpl let-result>\n <div class=\"py-2\">\n @if (getSecondaryLabel(result)) {\n <div class=\"gn-ui-card-detail\">{{ getSecondaryLabel(result) }}</div>\n }\n <div class=\"gn-ui-card-title\">{{ getDisplayLabel(result) }}</div>\n </div>\n</ng-template>\n", dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
27410
+ }
27411
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, decorators: [{
27412
+ type: Component,
27413
+ args: [{ selector: 'gn-ui-location-search', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [AutocompleteComponent], template: "<gn-ui-autocomplete\n [action]=\"searchAction\"\n [displayWithFn]=\"displayWithFn\"\n [placeholder]=\"placeholder\"\n [displayWithTemplate]=\"defaultItemTpl\"\n [clearOnSelection]=\"true\"\n (itemSelected)=\"handleItemSelected($event)\"\n>\n</gn-ui-autocomplete>\n\n<ng-template #defaultItemTpl let-result>\n <div class=\"py-2\">\n @if (getSecondaryLabel(result)) {\n <div class=\"gn-ui-card-detail\">{{ getSecondaryLabel(result) }}</div>\n }\n <div class=\"gn-ui-card-title\">{{ getDisplayLabel(result) }}</div>\n </div>\n</ng-template>\n" }]
27414
+ }], propDecorators: { placeholder: [{
27415
+ type: Input
27416
+ }], resultSelected: [{
27417
+ type: Output
27418
+ }], bboxSelected: [{
27419
+ type: Output
27420
+ }] } });
27421
+
27903
27422
  // expects the replacement key ${uuid}
27904
27423
  const RECORD_DATASET_URL_TOKEN = new InjectionToken('record-dataset-url-token');
27905
27424
  const RECORD_SERVICE_URL_TOKEN = new InjectionToken('record-service-url-token');
@@ -28058,6 +27577,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
28058
27577
  class AbstractSearchField {
28059
27578
  }
28060
27579
  class SimpleSearchField {
27580
+ get fieldIdentifier() {
27581
+ return this.customIdentifier ?? this.esFieldName;
27582
+ }
28061
27583
  constructor(esFieldName, injector, order = 'asc', orderType = 'key') {
28062
27584
  this.esFieldName = esFieldName;
28063
27585
  this.injector = injector;
@@ -28066,14 +27588,26 @@ class SimpleSearchField {
28066
27588
  this.repository = this.injector.get(RecordsRepositoryInterface);
28067
27589
  // FIXME: this is required to register runtime fields; abstract this as well
28068
27590
  this.esService = this.injector.get(ElasticsearchService);
27591
+ this.includeValues = [];
27592
+ this.excludeValues = [];
27593
+ }
27594
+ setFieldIdentifier(fieldIdentifier) {
27595
+ this.customIdentifier = fieldIdentifier;
27596
+ this.esService.registerFieldAlias(fieldIdentifier, this.esFieldName);
28069
27597
  }
28070
27598
  getAggregations() {
28071
27599
  return {
28072
- [this.esFieldName]: {
27600
+ [this.fieldIdentifier]: {
28073
27601
  type: 'terms',
28074
27602
  field: this.esFieldName,
28075
27603
  limit: 1000,
28076
27604
  sort: [this.order, this.orderType],
27605
+ ...(this.includeValues?.length && {
27606
+ includeValues: this.includeValues,
27607
+ }),
27608
+ ...(this.excludeValues?.length && {
27609
+ excludeValues: this.excludeValues,
27610
+ }),
28077
27611
  },
28078
27612
  };
28079
27613
  }
@@ -28081,7 +27615,7 @@ class SimpleSearchField {
28081
27615
  return bucket.term.toString();
28082
27616
  }
28083
27617
  getAvailableValues() {
28084
- return this.repository.aggregate(this.getAggregations()).pipe(map$1((response) => response[this.esFieldName].buckets || []), switchMap((buckets) => {
27618
+ return this.repository.aggregate(this.getAggregations()).pipe(map$1((response) => response[this.fieldIdentifier].buckets || []), switchMap((buckets) => {
28085
27619
  const bucketPromises = buckets.map(async (bucket) => ({
28086
27620
  label: `${await this.getBucketLabel(bucket)} (${bucket.count})`,
28087
27621
  value: bucket.term.toString(),
@@ -28094,7 +27628,7 @@ class SimpleSearchField {
28094
27628
  // FieldValue[]
28095
27629
  if (this.getType() === 'values') {
28096
27630
  return of({
28097
- [this.esFieldName]: values.reduce((acc, val) => {
27631
+ [this.fieldIdentifier]: values.reduce((acc, val) => {
28098
27632
  const value = val.toString();
28099
27633
  if (value !== '') {
28100
27634
  return { ...acc, [value]: true };
@@ -28105,11 +27639,11 @@ class SimpleSearchField {
28105
27639
  }
28106
27640
  // DateRange
28107
27641
  return of({
28108
- [this.esFieldName]: values[0] !== '' ? values[0] : {},
27642
+ [this.fieldIdentifier]: values[0] !== '' ? values[0] : {},
28109
27643
  });
28110
27644
  }
28111
27645
  getValuesForFilter(filters) {
28112
- const filter = filters[this.esFieldName];
27646
+ const filter = filters[this.fieldIdentifier];
28113
27647
  if (!filter)
28114
27648
  return of([]);
28115
27649
  // filter by expression
@@ -28127,6 +27661,9 @@ class SimpleSearchField {
28127
27661
  getType() {
28128
27662
  return 'values';
28129
27663
  }
27664
+ clone() {
27665
+ return Object.create(this);
27666
+ }
28130
27667
  }
28131
27668
  class TranslatedSearchField extends SimpleSearchField {
28132
27669
  constructor(esFieldName, injector, order = 'asc', orderType = 'key') {
@@ -28368,15 +27905,26 @@ class DateRangeSearchField extends SimpleSearchField {
28368
27905
  return 'dateRange';
28369
27906
  }
28370
27907
  }
27908
+ // treats a resource's creation/revision dates as an interval (its min and max), so a record matches
27909
+ // when that interval intersects the filter range, not just when a single date falls inside it
28371
27910
  class ResourceCreationRevisionDateSearchField extends DateRangeSearchField {
28372
27911
  constructor(injector, order = 'desc') {
28373
27912
  super('resourceCreationRevisionDate', injector, order);
28374
- this.esService.registerRuntimeField('resourceCreationRevisionDate', `if (doc.containsKey('creationDateForResource') && doc['creationDateForResource'].size() > 0) {
28375
- for (def date : doc['creationDateForResource']) { emit(date.millis); }
28376
- }
28377
- if (doc.containsKey('revisionDateForResource') && doc['revisionDateForResource'].size() > 0) {
28378
- for (def date : doc['revisionDateForResource']) { emit(date.millis); }
28379
- }`, 'date');
27913
+ const dateSourceFields = [
27914
+ 'creationDateForResource',
27915
+ 'revisionDateForResource',
27916
+ ];
27917
+ const collectSortedDates = dateSourceFields
27918
+ .map((field) => `if (doc.containsKey('${field}')) {
27919
+ for (def date : doc['${field}']) { dates.add(date.millis); }
27920
+ }`)
27921
+ .join('\n');
27922
+ this.esService.registerRuntimeField('resourceCreationRevisionDateMin', `def dates = [];
27923
+ ${collectSortedDates}
27924
+ if (dates.length > 0) { dates.sort(null); emit(dates[0]); }`, 'date');
27925
+ this.esService.registerRuntimeField('resourceCreationRevisionDateMax', `def dates = [];
27926
+ ${collectSortedDates}
27927
+ if (dates.length > 0) { dates.sort(null); emit(dates[dates.length - 1]); }`, 'date');
28380
27928
  }
28381
27929
  }
28382
27930
  class BoundingBoxSearchField extends SimpleSearchField {
@@ -28385,11 +27933,11 @@ class BoundingBoxSearchField extends SimpleSearchField {
28385
27933
  }
28386
27934
  getFiltersForValues(values) {
28387
27935
  return of({
28388
- [this.esFieldName]: values.map(Number),
27936
+ [this.fieldIdentifier]: values.map(Number),
28389
27937
  });
28390
27938
  }
28391
27939
  getValuesForFilter(filters) {
28392
- const filter = filters[this.esFieldName];
27940
+ const filter = filters[this.fieldIdentifier];
28393
27941
  return of(isBoundingBox(filter) ? filter : []);
28394
27942
  }
28395
27943
  getType() {
@@ -28488,7 +28036,7 @@ class RecordKindField extends SimpleSearchField {
28488
28036
  }
28489
28037
  getFiltersForValues(values) {
28490
28038
  const filters = {
28491
- [this.esFieldName]: values.reduce((acc, value) => {
28039
+ [this.fieldIdentifier]: values.reduce((acc, value) => {
28492
28040
  if (value === '')
28493
28041
  return { ...acc, [value]: true };
28494
28042
  const keysToAdd = this.TYPE_MAPPING[value] || [value];
@@ -28511,7 +28059,7 @@ class RecordKindField extends SimpleSearchField {
28511
28059
  return of(filters);
28512
28060
  }
28513
28061
  getValuesForFilter(filters) {
28514
- const filter = filters[this.esFieldName];
28062
+ const filter = filters[this.fieldIdentifier];
28515
28063
  if (!filter)
28516
28064
  return of([]);
28517
28065
  const activeValues = Object.keys(filter).filter((v) => filter[v]);
@@ -28541,11 +28089,15 @@ marker('search.filters.publisherOrg');
28541
28089
  marker('search.filters.user');
28542
28090
  marker('search.filters.changeDate');
28543
28091
  marker('search.filters.resourceCreationRevisionDate');
28092
+ marker('search.filters.temporalExtent');
28544
28093
  marker('search.filters.spatialExtent');
28094
+ marker('search.filters.documentStandard');
28095
+ const CUSTOM_FIELDS = new InjectionToken('custom-fields');
28545
28096
  class FieldsService {
28546
28097
  constructor() {
28547
28098
  this.injector = inject(Injector);
28548
- this.fields = {
28099
+ this.customFields = inject(CUSTOM_FIELDS, { optional: true }) ?? [];
28100
+ this.baseFields = {
28549
28101
  organization: new OrganizationSearchField(this.injector),
28550
28102
  format: new SimpleSearchField('format', this.injector, 'asc'),
28551
28103
  resourceType: new ResourceTypeLegacyField(this.injector), // Deprecated, use `recordKind` instead
@@ -28565,9 +28117,31 @@ class FieldsService {
28565
28117
  user: new UserSearchField(this.injector),
28566
28118
  changeDate: new DateRangeSearchField('changeDate', this.injector, 'desc'),
28567
28119
  resourceCreationRevisionDate: new ResourceCreationRevisionDateSearchField(this.injector, 'desc'),
28120
+ temporalExtent: new DateRangeSearchField('resourceTemporalExtentDateRange', this.injector, 'desc'),
28568
28121
  availableServices: new AvailableServicesField(this.injector),
28569
28122
  spatialExtent: new BoundingBoxSearchField('spatialExtent', this.injector),
28570
28123
  };
28124
+ this.fields = { ...this.baseFields };
28125
+ for (const customField of this.customFields) {
28126
+ const baseField = this.baseFields[customField.baseFilter];
28127
+ if (!(baseField instanceof SimpleSearchField)) {
28128
+ console.warn(`The custom field '${customField.name}' relies on a base field '${customField.baseFilter}' that is not supported. This field will be ignored.`);
28129
+ continue;
28130
+ }
28131
+ if (!customField.name.includes(':')) {
28132
+ console.warn(`The custom field '${customField.name}' is not scoped with a prefix. Custom fields must have their names prefixed, for instance "myOrg:myKeywords". This field will be ignored.`);
28133
+ continue;
28134
+ }
28135
+ const newField = baseField.clone();
28136
+ newField.setFieldIdentifier(customField.name);
28137
+ if (customField.includeValues) {
28138
+ newField.includeValues = customField.includeValues;
28139
+ }
28140
+ if (customField.excludeValues) {
28141
+ newField.excludeValues = customField.excludeValues;
28142
+ }
28143
+ this.fields[customField.name] = newField;
28144
+ }
28571
28145
  }
28572
28146
  get supportedFields() {
28573
28147
  return Object.keys(this.fields);
@@ -28615,7 +28189,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
28615
28189
  args: [{
28616
28190
  providedIn: 'root',
28617
28191
  }]
28618
- }] });
28192
+ }], ctorParameters: () => [] });
28619
28193
 
28620
28194
  class ApiCardComponent {
28621
28195
  constructor() {
@@ -30641,14 +30215,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
30641
30215
  marker('feature.catalog.attribute.type');
30642
30216
  marker('feature.catalog.attribute.name');
30643
30217
  marker('feature.catalog.attribute.code');
30644
- marker('feature.catalog.attribute.definition');
30218
+ marker('feature.catalog.attribute.description');
30645
30219
  marker('feature.catalog.attribute.values');
30646
30220
  class FeatureCatalogListComponent {
30647
30221
  constructor() {
30648
30222
  this.COLUMNS_DEFAULT = [
30649
30223
  { key: 'type', width: '25%' },
30650
30224
  { key: 'name', width: '40%' },
30651
- { key: 'definition', width: 'minmax(0px, 1fr)' },
30225
+ { key: 'description', width: 'minmax(0px, 1fr)' },
30652
30226
  ];
30653
30227
  this.COLUMN_VALUES = {
30654
30228
  key: 'values',
@@ -30669,7 +30243,7 @@ class FeatureCatalogListComponent {
30669
30243
  return col.key;
30670
30244
  }
30671
30245
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureCatalogListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
30672
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FeatureCatalogListComponent, isStandalone: true, selector: "gn-ui-feature-catalog-list", inputs: { filteredFeatureCatalog: "filteredFeatureCatalog" }, providers: [provideIcons({ iconoirList })], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }, { propertyName: "scrollable", first: true, predicate: CdkScrollable, descendants: true, static: true }, { propertyName: "panelComponent", first: true, predicate: ["expanel"], descendants: true, read: ExpandablePanelComponent, static: true }], ngImport: i0, template: "<div\n cdkScrollable\n class=\"h-[562px] relative overflow-y-auto overflow-hidden\"\n data-cy=\"feat-catalog-scrollable\"\n>\n <div #scrollContainer class=\"flex flex-col gap-2 py-5 px-5\">\n @for (\n featureType of filteredFeatureCatalog?.featureTypes;\n track featureType\n ) {\n <div class=\"rounded shadow bg-white\">\n <gn-ui-expandable-panel\n #expanel\n [collapsed]=\"filteredFeatureCatalog?.featureTypes?.length !== 1\"\n iconColor=\"black\"\n >\n <ng-template #titleTemplate>\n <div class=\"px-2\">\n <div class=\"text-lg font-bold\">{{ featureType.name }}</div>\n @if (featureType.definition) {\n <div class=\"text-sm\">\n {{ featureType.definition }}\n </div>\n }\n </div>\n </ng-template>\n @if (expanel && !expanel.collapsed) {\n <div\n class=\"grid gap-0\"\n [style.grid-template-columns]=\"\n getGridTemplateColumns(featureType.attributes)\n \"\n data-cy=\"feature-type-content\"\n >\n @for (\n col of getColumnsDefinition(featureType.attributes);\n track trackByColumn(i, col);\n let i = $index\n ) {\n <div\n class=\"py-1 px-2 text-sm font-bold text-left border-t break-all\"\n [class.border-l]=\"i > 0\"\n [class.border-gray-300]=\"i > 0\"\n [ngClass]=\"col.class || ''\"\n data-test=\"column-label\"\n >\n {{ 'feature.catalog.attribute.' + col.key | translate }}\n </div>\n }\n @if (expanel && !expanel.collapsed) {\n @for (row of featureType.attributes; track row) {\n @for (\n col of getColumnsDefinition(featureType.attributes);\n track trackByColumn(i, col);\n let i = $index\n ) {\n <div\n class=\"bg-white text-sm font-normal text-left border-t\"\n [class.border-l]=\"i > 0\"\n [class.border-gray-300]=\"i > 0\"\n data-test=\"cell-content\"\n >\n @if (col.key === 'values') {\n @if (row.values?.length > 0) {\n <gn-ui-cell-popin\n #popinRef\n [scrollContainer]=\"scrollContainer\"\n [cdkScrollContainer]=\"scrollable\"\n >\n <div\n cellContent\n data-cy=\"values-cell-popin-trigger\"\n >\n <gn-ui-button\n type=\"light\"\n extraClass=\"bg-transparent border-none\"\n (buttonClick)=\"popinRef.openOverlay()\"\n >\n <ng-icon name=\"iconoirList\" size=\"24\"></ng-icon>\n </gn-ui-button>\n </div>\n <div\n popinContent\n class=\"max-h-60 overflow-y-auto min-w-64 py-4 px-6\"\n style=\"scrollbar-width: thin\"\n >\n <ul class=\"list-disc list-inside mr-4\">\n @for (v of row.values; track v) {\n <li>\n {{ v.label || v.code }}\n </li>\n }\n </ul>\n </div>\n </gn-ui-cell-popin>\n }\n } @else {\n <gn-ui-truncated-text\n [scrollContainer]=\"scrollContainer\"\n [cdkScrollContainer]=\"scrollable\"\n [text]=\"row[col.key]\"\n ></gn-ui-truncated-text>\n }\n </div>\n }\n }\n }\n </div>\n }\n </gn-ui-expandable-panel>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: CellPopinComponent, selector: "gn-ui-cell-popin", inputs: ["extraClass", "cdkScrollContainer", "scrollContainer", "activePopin"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ExpandablePanelComponent, selector: "gn-ui-expandable-panel", inputs: ["title", "iconColor", "collapsed"] }, { kind: "component", type: TruncatedTextComponent, selector: "gn-ui-truncated-text", inputs: ["text", "extraClass", "scrollContainer", "cdkScrollContainer"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2$3.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
30246
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FeatureCatalogListComponent, isStandalone: true, selector: "gn-ui-feature-catalog-list", inputs: { filteredFeatureCatalog: "filteredFeatureCatalog" }, providers: [provideIcons({ iconoirList })], viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true }, { propertyName: "scrollable", first: true, predicate: CdkScrollable, descendants: true, static: true }, { propertyName: "panelComponent", first: true, predicate: ["expanel"], descendants: true, read: ExpandablePanelComponent, static: true }], ngImport: i0, template: "<div\n cdkScrollable\n class=\"h-[562px] relative overflow-y-auto overflow-hidden\"\n data-cy=\"feat-catalog-scrollable\"\n>\n <div #scrollContainer class=\"flex flex-col gap-2 py-5 px-5\">\n @for (\n featureType of filteredFeatureCatalog?.featureTypes;\n track featureType\n ) {\n <div class=\"rounded shadow bg-white\">\n <gn-ui-expandable-panel\n #expanel\n [collapsed]=\"filteredFeatureCatalog?.featureTypes?.length !== 1\"\n iconColor=\"black\"\n >\n <ng-template #titleTemplate>\n <div class=\"px-2\">\n <div class=\"text-lg font-bold\">{{ featureType.name }}</div>\n @if (featureType.description) {\n <div class=\"text-sm\">\n {{ featureType.description }}\n </div>\n }\n </div>\n </ng-template>\n @if (expanel && !expanel.collapsed) {\n <div\n class=\"grid gap-0\"\n [style.grid-template-columns]=\"\n getGridTemplateColumns(featureType.attributes)\n \"\n data-cy=\"feature-type-content\"\n >\n @for (\n col of getColumnsDefinition(featureType.attributes);\n track trackByColumn(i, col);\n let i = $index\n ) {\n <div\n class=\"py-1 px-2 text-sm font-bold text-left border-t break-all\"\n [class.border-l]=\"i > 0\"\n [class.border-gray-300]=\"i > 0\"\n [ngClass]=\"col.class || ''\"\n data-test=\"column-label\"\n >\n {{ 'feature.catalog.attribute.' + col.key | translate }}\n </div>\n }\n @if (expanel && !expanel.collapsed) {\n @for (row of featureType.attributes; track row) {\n @for (\n col of getColumnsDefinition(featureType.attributes);\n track trackByColumn(i, col);\n let i = $index\n ) {\n <div\n class=\"bg-white text-sm font-normal text-left border-t\"\n [class.border-l]=\"i > 0\"\n [class.border-gray-300]=\"i > 0\"\n data-test=\"cell-content\"\n >\n @if (col.key === 'values') {\n @if (row.values?.length > 0) {\n <gn-ui-cell-popin\n #popinRef\n [scrollContainer]=\"scrollContainer\"\n [cdkScrollContainer]=\"scrollable\"\n >\n <div\n cellContent\n data-cy=\"values-cell-popin-trigger\"\n >\n <gn-ui-button\n type=\"light\"\n extraClass=\"bg-transparent border-none\"\n (buttonClick)=\"popinRef.openOverlay()\"\n >\n <ng-icon name=\"iconoirList\" size=\"24\"></ng-icon>\n </gn-ui-button>\n </div>\n <div\n popinContent\n class=\"max-h-60 overflow-y-auto min-w-64 py-4 px-6\"\n style=\"scrollbar-width: thin\"\n >\n <ul class=\"list-disc list-inside mr-4\">\n @for (v of row.values; track v) {\n <li>\n {{ v.label || v.code }}\n </li>\n }\n </ul>\n </div>\n </gn-ui-cell-popin>\n }\n } @else {\n <gn-ui-truncated-text\n [scrollContainer]=\"scrollContainer\"\n [cdkScrollContainer]=\"scrollable\"\n [text]=\"row[col.key]\"\n ></gn-ui-truncated-text>\n }\n </div>\n }\n }\n }\n </div>\n }\n </gn-ui-expandable-panel>\n </div>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "component", type: CellPopinComponent, selector: "gn-ui-cell-popin", inputs: ["extraClass", "cdkScrollContainer", "scrollContainer", "activePopin"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: ExpandablePanelComponent, selector: "gn-ui-expandable-panel", inputs: ["title", "iconColor", "collapsed"] }, { kind: "component", type: TruncatedTextComponent, selector: "gn-ui-truncated-text", inputs: ["text", "extraClass", "scrollContainer", "cdkScrollContainer"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i2$3.CdkScrollable, selector: "[cdk-scrollable], [cdkScrollable]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
30673
30247
  }
30674
30248
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureCatalogListComponent, decorators: [{
30675
30249
  type: Component,
@@ -30682,7 +30256,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
30682
30256
  TruncatedTextComponent,
30683
30257
  NgIconComponent,
30684
30258
  ScrollingModule,
30685
- ], providers: [provideIcons({ iconoirList })], template: "<div\n cdkScrollable\n class=\"h-[562px] relative overflow-y-auto overflow-hidden\"\n data-cy=\"feat-catalog-scrollable\"\n>\n <div #scrollContainer class=\"flex flex-col gap-2 py-5 px-5\">\n @for (\n featureType of filteredFeatureCatalog?.featureTypes;\n track featureType\n ) {\n <div class=\"rounded shadow bg-white\">\n <gn-ui-expandable-panel\n #expanel\n [collapsed]=\"filteredFeatureCatalog?.featureTypes?.length !== 1\"\n iconColor=\"black\"\n >\n <ng-template #titleTemplate>\n <div class=\"px-2\">\n <div class=\"text-lg font-bold\">{{ featureType.name }}</div>\n @if (featureType.definition) {\n <div class=\"text-sm\">\n {{ featureType.definition }}\n </div>\n }\n </div>\n </ng-template>\n @if (expanel && !expanel.collapsed) {\n <div\n class=\"grid gap-0\"\n [style.grid-template-columns]=\"\n getGridTemplateColumns(featureType.attributes)\n \"\n data-cy=\"feature-type-content\"\n >\n @for (\n col of getColumnsDefinition(featureType.attributes);\n track trackByColumn(i, col);\n let i = $index\n ) {\n <div\n class=\"py-1 px-2 text-sm font-bold text-left border-t break-all\"\n [class.border-l]=\"i > 0\"\n [class.border-gray-300]=\"i > 0\"\n [ngClass]=\"col.class || ''\"\n data-test=\"column-label\"\n >\n {{ 'feature.catalog.attribute.' + col.key | translate }}\n </div>\n }\n @if (expanel && !expanel.collapsed) {\n @for (row of featureType.attributes; track row) {\n @for (\n col of getColumnsDefinition(featureType.attributes);\n track trackByColumn(i, col);\n let i = $index\n ) {\n <div\n class=\"bg-white text-sm font-normal text-left border-t\"\n [class.border-l]=\"i > 0\"\n [class.border-gray-300]=\"i > 0\"\n data-test=\"cell-content\"\n >\n @if (col.key === 'values') {\n @if (row.values?.length > 0) {\n <gn-ui-cell-popin\n #popinRef\n [scrollContainer]=\"scrollContainer\"\n [cdkScrollContainer]=\"scrollable\"\n >\n <div\n cellContent\n data-cy=\"values-cell-popin-trigger\"\n >\n <gn-ui-button\n type=\"light\"\n extraClass=\"bg-transparent border-none\"\n (buttonClick)=\"popinRef.openOverlay()\"\n >\n <ng-icon name=\"iconoirList\" size=\"24\"></ng-icon>\n </gn-ui-button>\n </div>\n <div\n popinContent\n class=\"max-h-60 overflow-y-auto min-w-64 py-4 px-6\"\n style=\"scrollbar-width: thin\"\n >\n <ul class=\"list-disc list-inside mr-4\">\n @for (v of row.values; track v) {\n <li>\n {{ v.label || v.code }}\n </li>\n }\n </ul>\n </div>\n </gn-ui-cell-popin>\n }\n } @else {\n <gn-ui-truncated-text\n [scrollContainer]=\"scrollContainer\"\n [cdkScrollContainer]=\"scrollable\"\n [text]=\"row[col.key]\"\n ></gn-ui-truncated-text>\n }\n </div>\n }\n }\n }\n </div>\n }\n </gn-ui-expandable-panel>\n </div>\n }\n </div>\n</div>\n" }]
30259
+ ], providers: [provideIcons({ iconoirList })], template: "<div\n cdkScrollable\n class=\"h-[562px] relative overflow-y-auto overflow-hidden\"\n data-cy=\"feat-catalog-scrollable\"\n>\n <div #scrollContainer class=\"flex flex-col gap-2 py-5 px-5\">\n @for (\n featureType of filteredFeatureCatalog?.featureTypes;\n track featureType\n ) {\n <div class=\"rounded shadow bg-white\">\n <gn-ui-expandable-panel\n #expanel\n [collapsed]=\"filteredFeatureCatalog?.featureTypes?.length !== 1\"\n iconColor=\"black\"\n >\n <ng-template #titleTemplate>\n <div class=\"px-2\">\n <div class=\"text-lg font-bold\">{{ featureType.name }}</div>\n @if (featureType.description) {\n <div class=\"text-sm\">\n {{ featureType.description }}\n </div>\n }\n </div>\n </ng-template>\n @if (expanel && !expanel.collapsed) {\n <div\n class=\"grid gap-0\"\n [style.grid-template-columns]=\"\n getGridTemplateColumns(featureType.attributes)\n \"\n data-cy=\"feature-type-content\"\n >\n @for (\n col of getColumnsDefinition(featureType.attributes);\n track trackByColumn(i, col);\n let i = $index\n ) {\n <div\n class=\"py-1 px-2 text-sm font-bold text-left border-t break-all\"\n [class.border-l]=\"i > 0\"\n [class.border-gray-300]=\"i > 0\"\n [ngClass]=\"col.class || ''\"\n data-test=\"column-label\"\n >\n {{ 'feature.catalog.attribute.' + col.key | translate }}\n </div>\n }\n @if (expanel && !expanel.collapsed) {\n @for (row of featureType.attributes; track row) {\n @for (\n col of getColumnsDefinition(featureType.attributes);\n track trackByColumn(i, col);\n let i = $index\n ) {\n <div\n class=\"bg-white text-sm font-normal text-left border-t\"\n [class.border-l]=\"i > 0\"\n [class.border-gray-300]=\"i > 0\"\n data-test=\"cell-content\"\n >\n @if (col.key === 'values') {\n @if (row.values?.length > 0) {\n <gn-ui-cell-popin\n #popinRef\n [scrollContainer]=\"scrollContainer\"\n [cdkScrollContainer]=\"scrollable\"\n >\n <div\n cellContent\n data-cy=\"values-cell-popin-trigger\"\n >\n <gn-ui-button\n type=\"light\"\n extraClass=\"bg-transparent border-none\"\n (buttonClick)=\"popinRef.openOverlay()\"\n >\n <ng-icon name=\"iconoirList\" size=\"24\"></ng-icon>\n </gn-ui-button>\n </div>\n <div\n popinContent\n class=\"max-h-60 overflow-y-auto min-w-64 py-4 px-6\"\n style=\"scrollbar-width: thin\"\n >\n <ul class=\"list-disc list-inside mr-4\">\n @for (v of row.values; track v) {\n <li>\n {{ v.label || v.code }}\n </li>\n }\n </ul>\n </div>\n </gn-ui-cell-popin>\n }\n } @else {\n <gn-ui-truncated-text\n [scrollContainer]=\"scrollContainer\"\n [cdkScrollContainer]=\"scrollable\"\n [text]=\"row[col.key]\"\n ></gn-ui-truncated-text>\n }\n </div>\n }\n }\n }\n </div>\n }\n </gn-ui-expandable-panel>\n </div>\n }\n </div>\n</div>\n" }]
30686
30260
  }], propDecorators: { filteredFeatureCatalog: [{
30687
30261
  type: Input
30688
30262
  }], scrollContainer: [{
@@ -31820,6 +31394,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
31820
31394
  ], template: "<div class=\"flex flex-col gap-6 p-6 items-start pointer-events-none\">\n @for (\n notification of notificationsService.notifications$ | async;\n track trackById($index, notification)\n ) {\n <gn-ui-notification\n class=\"max-w-full pointer-events-auto\"\n [text]=\"notification.text\"\n [type]=\"notification.type\"\n [title]=\"notification.title\"\n [closeMessage]=\"notification.closeMessage\"\n (notificationClose)=\"\n notificationsService.removeNotificationById(notification.id)\n \"\n [@enterExit]\n ></gn-ui-notification>\n }\n</div>\n" }]
31821
31395
  }] });
31822
31396
 
31397
+ marker('search.filters.spatialExtent.searchLocation');
31398
+ // in MB, null means no limit
31399
+ const SPATIAL_EXTENT_MAX_FILE_SIZE = new InjectionToken('spatialExtentMaxFileSize', { factory: () => null });
31823
31400
  class FilterDropdownComponent {
31824
31401
  constructor() {
31825
31402
  this.searchFacade = inject(SearchFacade);
@@ -31827,7 +31404,7 @@ class FilterDropdownComponent {
31827
31404
  this.fieldsService = inject(FieldsService);
31828
31405
  this.notificationsService = inject(NotificationsService);
31829
31406
  this.translateService = inject(TranslateService);
31830
- this.spatialExtentMaxFileSize = getOptionalSearchConfig()?.SPATIAL_EXTENT_MAX_FILE_SIZE;
31407
+ this.spatialExtentMaxFileSize = inject(SPATIAL_EXTENT_MAX_FILE_SIZE);
31831
31408
  this.selected$ = this.searchFacade.searchFilters$.pipe(switchMap((filters) => this.fieldsService.readFieldValuesFromFilters(filters)), map$1((fieldValues) => fieldValues[this.fieldName]), filter$1((selected) => !!selected), startWith$1([]), catchError(() => of([])));
31832
31409
  this.selectedDateRange$ = this.selected$.pipe(map$1((selected) => (Array.isArray(selected) ? {} : selected)));
31833
31410
  this.selectedBoundingBox$ = this.selected$.pipe(map$1((selected) => Array.isArray(selected) && selected.length > 0
@@ -31848,6 +31425,9 @@ class FilterDropdownComponent {
31848
31425
  .subscribe((filters) => this.searchService.updateFilters(filters));
31849
31426
  this.clearSpatialExtentErrorNotification();
31850
31427
  }
31428
+ onLocationSelected({ bbox, label }) {
31429
+ this.spatialExtentDropdown.setLocationBbox(bbox, label);
31430
+ }
31851
31431
  onSpatialExtentError(error) {
31852
31432
  this.clearSpatialExtentErrorNotification();
31853
31433
  this.spatialExtentErrorNotificationId =
@@ -31878,7 +31458,7 @@ class FilterDropdownComponent {
31878
31458
  .subscribe((filters) => this.searchService.updateFilters(filters));
31879
31459
  }
31880
31460
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
31881
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FilterDropdownComponent, isStandalone: true, selector: "gn-ui-filter-dropdown", inputs: { fieldName: "fieldName", title: "title" }, ngImport: i0, template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n [attr.data-cy-field]=\"fieldName\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [initialBbox]=\"(selectedBoundingBox$ | async) ?? null\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\n [attr.data-cy-field]=\"fieldName\"\n ></gn-ui-spatial-extent-dropdown>\n} @else {\n <gn-ui-dropdown-multiselect\n class=\"w-full\"\n [title]=\"title\"\n [maxRows]=\"6\"\n [choices]=\"(choices$ | async) || []\"\n [selected]=\"selected$ | async\"\n [allowSearch]=\"true\"\n (selectValues)=\"onSelectedValues($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n </gn-ui-dropdown-multiselect>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DateRangeDropdownComponent, selector: "gn-ui-date-range-dropdown", inputs: ["title", "dateRange"], outputs: ["dateRangeChange"] }, { kind: "component", type: DropdownMultiselectComponent, selector: "gn-ui-dropdown-multiselect", inputs: ["title", "choices", "selected", "allowSearch", "maxRows", "searchInputValue"], outputs: ["selectValues"] }, { kind: "component", type: SpatialExtentDropdownComponent, selector: "gn-ui-spatial-extent-dropdown", inputs: ["title", "maxFileSizeMb", "initialBbox"], outputs: ["bboxChange", "errorChange"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
31461
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FilterDropdownComponent, isStandalone: true, selector: "gn-ui-filter-dropdown", inputs: { fieldName: "fieldName", title: "title" }, viewQueries: [{ propertyName: "spatialExtentDropdown", first: true, predicate: SpatialExtentDropdownComponent, descendants: true }], ngImport: i0, template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n [attr.data-cy-field]=\"fieldName\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [initialBbox]=\"(selectedBoundingBox$ | async) ?? null\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n <gn-ui-location-search\n [placeholder]=\"'search.filters.spatialExtent.searchLocation' | translate\"\n (bboxSelected)=\"onLocationSelected($event)\"\n data-cy=\"locationSearch\"\n ></gn-ui-location-search>\n </gn-ui-spatial-extent-dropdown>\n} @else {\n <gn-ui-dropdown-multiselect\n class=\"w-full\"\n [title]=\"title\"\n [maxRows]=\"6\"\n [choices]=\"(choices$ | async) || []\"\n [selected]=\"selected$ | async\"\n [allowSearch]=\"true\"\n (selectValues)=\"onSelectedValues($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n </gn-ui-dropdown-multiselect>\n}\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: DateRangeDropdownComponent, selector: "gn-ui-date-range-dropdown", inputs: ["title", "dateRange"], outputs: ["dateRangeChange"] }, { kind: "component", type: DropdownMultiselectComponent, selector: "gn-ui-dropdown-multiselect", inputs: ["title", "choices", "selected", "allowSearch", "maxRows", "searchInputValue"], outputs: ["selectValues"] }, { kind: "component", type: SpatialExtentDropdownComponent, selector: "gn-ui-spatial-extent-dropdown", inputs: ["title", "maxFileSizeMb", "initialBbox"], outputs: ["bboxChange", "errorChange"] }, { kind: "component", type: LocationSearchComponent, selector: "gn-ui-location-search", inputs: ["placeholder"], outputs: ["resultSelected", "bboxSelected"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
31882
31462
  }
31883
31463
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, decorators: [{
31884
31464
  type: Component,
@@ -31887,11 +31467,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
31887
31467
  DateRangeDropdownComponent,
31888
31468
  DropdownMultiselectComponent,
31889
31469
  SpatialExtentDropdownComponent,
31890
- ], template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n [attr.data-cy-field]=\"fieldName\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [initialBbox]=\"(selectedBoundingBox$ | async) ?? null\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\n [attr.data-cy-field]=\"fieldName\"\n ></gn-ui-spatial-extent-dropdown>\n} @else {\n <gn-ui-dropdown-multiselect\n class=\"w-full\"\n [title]=\"title\"\n [maxRows]=\"6\"\n [choices]=\"(choices$ | async) || []\"\n [selected]=\"selected$ | async\"\n [allowSearch]=\"true\"\n (selectValues)=\"onSelectedValues($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n </gn-ui-dropdown-multiselect>\n}\n" }]
31470
+ LocationSearchComponent,
31471
+ TranslatePipe,
31472
+ ], template: "@if (fieldType === 'dateRange') {\n <gn-ui-date-range-dropdown\n [title]=\"title\"\n [dateRange]=\"(selectedDateRange$ | async) ?? {}\"\n (dateRangeChange)=\"onDateRangeChange($event)\"\n [attr.data-cy-field]=\"fieldName\"\n ></gn-ui-date-range-dropdown>\n} @else if (fieldType === 'spatialExtent') {\n <gn-ui-spatial-extent-dropdown\n [title]=\"title\"\n [initialBbox]=\"(selectedBoundingBox$ | async) ?? null\"\n [maxFileSizeMb]=\"spatialExtentMaxFileSize\"\n (bboxChange)=\"onBboxChange($event)\"\n (errorChange)=\"onSpatialExtentError($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n <gn-ui-location-search\n [placeholder]=\"'search.filters.spatialExtent.searchLocation' | translate\"\n (bboxSelected)=\"onLocationSelected($event)\"\n data-cy=\"locationSearch\"\n ></gn-ui-location-search>\n </gn-ui-spatial-extent-dropdown>\n} @else {\n <gn-ui-dropdown-multiselect\n class=\"w-full\"\n [title]=\"title\"\n [maxRows]=\"6\"\n [choices]=\"(choices$ | async) || []\"\n [selected]=\"selected$ | async\"\n [allowSearch]=\"true\"\n (selectValues)=\"onSelectedValues($event)\"\n [attr.data-cy-field]=\"fieldName\"\n >\n </gn-ui-dropdown-multiselect>\n}\n" }]
31891
31473
  }], propDecorators: { fieldName: [{
31892
31474
  type: Input
31893
31475
  }], title: [{
31894
31476
  type: Input
31477
+ }], spatialExtentDropdown: [{
31478
+ type: ViewChild,
31479
+ args: [SpatialExtentDropdownComponent]
31895
31480
  }] } });
31896
31481
 
31897
31482
  class FuzzySearchComponent {
@@ -31948,7 +31533,7 @@ class FuzzySearchComponent {
31948
31533
  this.isSearchActive.emit(event);
31949
31534
  }
31950
31535
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FuzzySearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
31951
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: FuzzySearchComponent, isStandalone: true, selector: "gn-ui-fuzzy-search", inputs: { autoFocus: "autoFocus", forceTrackPosition: "forceTrackPosition", enterButton: "enterButton", placeholder: "placeholder" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", isSearchActive: "isSearchActive" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: AutocompleteComponent, descendants: true }], ngImport: i0, template: "<gn-ui-autocomplete\n [placeholder]=\"placeholder ?? ('search.field.any.placeholder' | translate)\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n (inputSubmitted)=\"handleInputSubmission($event)\"\n (inputCleared)=\"handleInputCleared()\"\n (isSearchActive)=\"handleSearchActive($event)\"\n [value]=\"searchInputValue$ | async\"\n [preventCompleteOnSelection]=\"true\"\n [autoFocus]=\"autoFocus\"\n [allowSubmit]=\"true\"\n [forceTrackPosition]=\"forceTrackPosition\"\n [enterButton]=\"enterButton\"\n></gn-ui-autocomplete>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
31536
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: FuzzySearchComponent, isStandalone: true, selector: "gn-ui-fuzzy-search", inputs: { autoFocus: "autoFocus", forceTrackPosition: "forceTrackPosition", enterButton: "enterButton", placeholder: "placeholder" }, outputs: { itemSelected: "itemSelected", inputSubmitted: "inputSubmitted", isSearchActive: "isSearchActive" }, viewQueries: [{ propertyName: "autocomplete", first: true, predicate: AutocompleteComponent, descendants: true }], ngImport: i0, template: "<gn-ui-autocomplete\n [placeholder]=\"placeholder ?? ('search.field.any.placeholder' | translate)\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n (inputSubmitted)=\"handleInputSubmission($event)\"\n (inputCleared)=\"handleInputCleared()\"\n (isSearchActive)=\"handleSearchActive($event)\"\n [value]=\"searchInputValue$ | async\"\n [preventCompleteOnSelection]=\"true\"\n [autoFocus]=\"autoFocus\"\n [allowSubmit]=\"true\"\n [forceTrackPosition]=\"forceTrackPosition\"\n [enterButton]=\"enterButton\"\n></gn-ui-autocomplete>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
31952
31537
  }
31953
31538
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FuzzySearchComponent, decorators: [{
31954
31539
  type: Component,
@@ -32508,6 +32093,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
32508
32093
  marker('search.filters.summaryLabel.user');
32509
32094
  marker('search.filters.summaryLabel.changeDate');
32510
32095
  marker('search.filters.summaryLabel.resourceCreationRevisionDate');
32096
+ marker('search.filters.summaryLabel.temporalExtent');
32511
32097
  const OPEN_BOUND = '…';
32512
32098
  class SearchFiltersSummaryItemComponent {
32513
32099
  constructor() {
@@ -32889,95 +32475,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
32889
32475
  ], template: "<div\n class=\"bg-white rounded shadow shadow-lg relative h-full w-[400px] overflow-hidden\"\n>\n <div class=\"p-3 border-b border-gray-300 flex items-center\">\n <ng-icon class=\"mr-2\" name=\"matLayersOutline\"></ng-icon>\n <span translate>map.layers.list</span>\n </div>\n <div class=\"flex flex-col px-4 divide-y divide-y-gray-50\">\n @for (layer of layers$ | async; track layer; let index = $index) {\n <div class=\"flex flex-row py-3\">\n <ng-icon class=\"-ml-2 mr-2 shrink-0\" name=\"matChevronRight\"></ng-icon>\n <span class=\"mr-2 grow\">{{ layer.label }}</span>\n <a\n href\n class=\"underline text-sm text-red-700 hover:text-red-900\"\n (click)=\"deleteLayer(index); $event.preventDefault()\"\n >\n delete\n </a>\n </div>\n }\n </div>\n <gn-ui-expandable-panel-button [titleTemplate]=\"addLayerTitle\">\n <mat-tab-group animationDuration=\"200ms\" class=\"h-full\">\n <mat-tab [label]=\"'map.add.layer.catalog' | translate\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-catalog></gn-ui-add-layer-from-catalog>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.wms' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-wms></gn-ui-add-layer-from-wms>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.wfs' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-wfs></gn-ui-add-layer-from-wfs>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.ogc.api' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-ogc-api\n [ogcUrl]=\"ogcUrl\"\n (layerAdded)=\"addLayer($event)\"\n ></gn-ui-add-layer-from-ogc-api>\n </div>\n </mat-tab>\n <mat-tab [label]=\"'map.add.layer.file' | translate\" bodyClass=\"h-full\">\n <div class=\"p-3\">\n <gn-ui-add-layer-from-file></gn-ui-add-layer-from-file>\n </div>\n </mat-tab>\n </mat-tab-group>\n </gn-ui-expandable-panel-button>\n</div>\n\n<ng-template #addLayerTitle>\n <ng-icon class=\"mr-4\" name=\"matAddCircleOutlineOutline\"> </ng-icon>\n <span translate>map.add.layer</span>\n</ng-template>\n" }]
32890
32476
  }] });
32891
32477
 
32892
- class GeocodingComponent {
32893
- constructor() {
32894
- this.mapFacade = inject(MapFacade);
32895
- this.geocodingService = inject(GeocodingService);
32896
- this.searchText = '';
32897
- this.results = [];
32898
- this.searchTextChanged = new Subject();
32899
- this.destroy$ = new Subject();
32900
- this.errorMessage = null;
32901
- this.searchTextChanged
32902
- .pipe(debounceTime(300), switchMap$1((searchText) => {
32903
- return from(this.geocodingService.query(searchText)).pipe(catchError$1((error) => {
32904
- this.errorMessage =
32905
- 'An error occurred while searching. Please try again.';
32906
- console.error(error);
32907
- return [];
32908
- }));
32909
- }), takeUntil(this.destroy$))
32910
- .subscribe((results) => {
32911
- this.results = results;
32912
- });
32913
- }
32914
- ngOnDestroy() {
32915
- this.destroy$.next();
32916
- this.destroy$.complete();
32917
- }
32918
- onSearchChange(searchText) {
32919
- if (!searchText) {
32920
- this.clearSearch();
32921
- return;
32922
- }
32923
- else {
32924
- this.searchTextChanged.next(searchText);
32925
- }
32926
- }
32927
- clearSearch() {
32928
- this.searchText = '';
32929
- this.results = [];
32930
- this.errorMessage = null;
32931
- }
32932
- async zoomToLocation(result) {
32933
- const geometry = result.geom;
32934
- if (geometry.type === 'Point') {
32935
- await this.zoomToPoint(geometry.coordinates);
32936
- }
32937
- else if (geometry.type === 'Polygon') {
32938
- await this.zoomToPolygon(geometry.coordinates);
32939
- }
32940
- else {
32941
- console.error(`Unsupported geometry type: ${geometry.type}`);
32942
- }
32943
- }
32944
- async zoomToPoint(pointCoords) {
32945
- const context = await firstValueFrom(this.mapFacade.context$);
32946
- const view = {
32947
- center: pointCoords,
32948
- zoom: 10,
32949
- };
32950
- this.mapFacade.applyContext({
32951
- ...context,
32952
- view,
32953
- });
32954
- }
32955
- async zoomToPolygon(polygonCoords) {
32956
- const context = await firstValueFrom(this.mapFacade.context$);
32957
- const view = {
32958
- geometry: {
32959
- type: 'Polygon',
32960
- coordinates: polygonCoords,
32961
- },
32962
- };
32963
- this.mapFacade.applyContext({
32964
- ...context,
32965
- view,
32966
- });
32967
- }
32968
- onEnterPress() {
32969
- if (this.results && this.results.length > 0) {
32970
- this.zoomToLocation(this.results[0]);
32971
- }
32972
- }
32973
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
32974
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GeocodingComponent, isStandalone: true, selector: "gn-ui-geocoding", ngImport: i0, template: "<gn-ui-search-input\n [(value)]=\"searchText\"\n (valueChange)=\"onSearchChange($event)\"\n (keyup.enter)=\"onEnterPress()\"\n [placeholder]=\"'map.geocoding.placeholder' | translate\"\n>\n</gn-ui-search-input>\n@if (results && results.length) {\n <ul\n class=\"bg-gray-50 border border-gray-200 w-full mt-2 shadow-sm rounded-lg\"\n >\n @for (result of results; track result) {\n <li\n (click)=\"zoomToLocation(result)\"\n class=\"flex items-center pl-8 pr-4 py-2 border-b border-gray-200 relative cursor-pointer hover:bg-blue-100 hover:text-gray-800 transition duration-300 ease-in-out\"\n >\n <svg\n class=\"stroke-current text-blue-500 absolute w-5 h-5 left-3 top-3\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\"\n />\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n <span class=\"font-sans font-semibold ml-4\">{{ result.label }}</span>\n </li>\n }\n </ul>\n}\n", styles: [""], dependencies: [{ kind: "component", type: SearchInputComponent, selector: "gn-ui-search-input", inputs: ["value", "placeholder"], outputs: ["valueChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }] }); }
32975
- }
32976
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GeocodingComponent, decorators: [{
32977
- type: Component,
32978
- args: [{ selector: 'gn-ui-geocoding', standalone: true, imports: [SearchInputComponent, TranslatePipe], template: "<gn-ui-search-input\n [(value)]=\"searchText\"\n (valueChange)=\"onSearchChange($event)\"\n (keyup.enter)=\"onEnterPress()\"\n [placeholder]=\"'map.geocoding.placeholder' | translate\"\n>\n</gn-ui-search-input>\n@if (results && results.length) {\n <ul\n class=\"bg-gray-50 border border-gray-200 w-full mt-2 shadow-sm rounded-lg\"\n >\n @for (result of results; track result) {\n <li\n (click)=\"zoomToLocation(result)\"\n class=\"flex items-center pl-8 pr-4 py-2 border-b border-gray-200 relative cursor-pointer hover:bg-blue-100 hover:text-gray-800 transition duration-300 ease-in-out\"\n >\n <svg\n class=\"stroke-current text-blue-500 absolute w-5 h-5 left-3 top-3\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z\"\n />\n <path\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n stroke-width=\"2\"\n d=\"M15 11a3 3 0 11-6 0 3 3 0 016 0z\"\n />\n </svg>\n <span class=\"font-sans font-semibold ml-4\">{{ result.label }}</span>\n </li>\n }\n </ul>\n}\n" }]
32979
- }], ctorParameters: () => [] });
32980
-
32981
32478
  /*
32982
32479
  Metadata actions
32983
32480
  */
@@ -34160,7 +33657,7 @@ class DataService {
34160
33657
  }));
34161
33658
  }
34162
33659
  async getDownloadLinksFromOgcApiFeatures(ogcApiLink) {
34163
- const collectionInfo = await this.getDownloadUrlsFromOgcApi(ogcApiLink.url.href);
33660
+ const collectionInfo = await this.getDownloadUrlsFromOgcApi(ogcApiLink.url.href, ogcApiLink.name);
34164
33661
  return Object.keys(collectionInfo.bulkDownloadLinks).map((mimeType) => {
34165
33662
  const urlWithoutLimit = new URL(collectionInfo.bulkDownloadLinks[mimeType]);
34166
33663
  urlWithoutLimit.searchParams.delete('limit');
@@ -34173,27 +33670,31 @@ class DataService {
34173
33670
  };
34174
33671
  });
34175
33672
  }
34176
- async getDownloadUrlsFromOgcApi(url) {
33673
+ async getTargetCollectionId(endpoint, collectionId) {
33674
+ const collections = await endpoint.featureCollections;
33675
+ return collections.length === 1 && !collectionId
33676
+ ? collections[0]
33677
+ : collectionId;
33678
+ }
33679
+ async getDownloadUrlsFromOgcApi(url, collectionId) {
34177
33680
  const endpoint = new OgcApiEndpoint(url);
34178
- return await endpoint.featureCollections
34179
- .then((collections) => {
34180
- return endpoint.getCollectionInfo(collections[0]);
34181
- })
34182
- .catch((error) => {
34183
- throw new Error(`ogc.unreachable.unknown`);
34184
- });
33681
+ try {
33682
+ const id = await this.getTargetCollectionId(endpoint, collectionId);
33683
+ return await endpoint.getCollectionInfo(id);
33684
+ }
33685
+ catch {
33686
+ throw new Error('ogc.unreachable.unknown');
33687
+ }
34185
33688
  }
34186
- async getItemsFromOgcApi(url, limit) {
33689
+ async getItemsFromOgcApi(url, collectionId, limit) {
34187
33690
  const endpoint = new OgcApiEndpoint(url);
34188
- return await endpoint.featureCollections
34189
- .then((collections) => {
34190
- return collections.length
34191
- ? endpoint.getCollectionItems(collections[0], limit)
34192
- : null;
34193
- })
34194
- .catch(() => {
34195
- throw new Error(`ogc.unreachable.unknown`);
34196
- });
33691
+ try {
33692
+ const id = await this.getTargetCollectionId(endpoint, collectionId);
33693
+ return await endpoint.getCollectionItems(id, limit);
33694
+ }
33695
+ catch {
33696
+ throw new Error('ogc.unreachable.unknown');
33697
+ }
34197
33698
  }
34198
33699
  async getItemsFromStacApi(url, options) {
34199
33700
  return await StacEndpoint.getItemsFromUrl(url, options)
@@ -34281,7 +33782,7 @@ class DataService {
34281
33782
  }
34282
33783
  else if (link.type === 'service' &&
34283
33784
  link.accessServiceProtocol === 'ogcFeatures') {
34284
- return from(this.getDownloadUrlsFromOgcApi(link.url.href)).pipe(switchMap$1((collectionInfo) => {
33785
+ return from(this.getDownloadUrlsFromOgcApi(link.url.href, link.name)).pipe(switchMap$1((collectionInfo) => {
34285
33786
  const isMimeTypeJson = (mimeType) => {
34286
33787
  return mimeType.toLowerCase().indexOf('json') > -1;
34287
33788
  };
@@ -35225,7 +34726,7 @@ class MdViewFacade {
35225
34726
  if (this.linkClassifier.hasUsage(link, LinkUsage.GEODATA)) {
35226
34727
  if (link.type === 'service' &&
35227
34728
  link.accessServiceProtocol === 'ogcFeatures') {
35228
- return from(this.dataService.getItemsFromOgcApi(link.url.href, 1)).pipe(map$1((collectionRecords) => {
34729
+ return from(this.dataService.getItemsFromOgcApi(link.url.href, link.name, 1)).pipe(map$1((collectionRecords) => {
35229
34730
  return collectionRecords &&
35230
34731
  collectionRecords[0] &&
35231
34732
  collectionRecords[0].geometry
@@ -35308,7 +34809,7 @@ class MdViewEffects {
35308
34809
  }
35309
34810
  return loadFullMetadataSuccess({ full: record });
35310
34811
  }), catchError((error) => of(loadFullMetadataFailure({ otherError: error.message })))));
35311
- this.loadFeatureCatalog$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), filter$1(({ full }) => full !== undefined), switchMap$1(({ full }) => this.recordsRepository.getFeatureCatalog(full)), map$1((featureCatalog) => loadFeatureCatalogSuccess({
34812
+ this.loadFeatureCatalog$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), filter$1(({ full }) => full !== undefined), switchMap$1(({ full }) => this.recordsRepository.queryLinkedFeatureCatalog(full)), map$1((featureCatalog) => loadFeatureCatalogSuccess({
35312
34813
  datasetCatalog: featureCatalog,
35313
34814
  })), catchError((error) => of(loadFeatureCatalogFailure({
35314
34815
  error: error.message,
@@ -38022,7 +37523,7 @@ class GenericKeywordsComponent {
38022
37523
  this.deletedKeyword.emit(keyword);
38023
37524
  }
38024
37525
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GenericKeywordsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
38025
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GenericKeywordsComponent, isStandalone: true, selector: "gn-ui-generic-keywords", inputs: { keywords: "keywords", keywordTypes: "keywordTypes", placeholder: "placeholder", allowSubmit: "allowSubmit" }, outputs: { changedKeywords: "changedKeywords", addedKeyword: "addedKeyword", deletedKeyword: "deletedKeyword" }, ngImport: i0, template: "<div class=\"flex flex-col gap-4\">\n <gn-ui-autocomplete\n [placeholder]=\"placeholder\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n [preventCompleteOnSelection]=\"false\"\n [minCharacterCount]=\"1\"\n [allowSubmit]=\"false\"\n [clearOnSelection]=\"true\"\n ></gn-ui-autocomplete>\n <div class=\"flex gap-2 flex-wrap\">\n @for (keyword of keywords; track keyword) {\n <gn-ui-keyword-badge\n [keyword]=\"keyword\"\n [editable]=\"true\"\n (keywordRemove)=\"removeKeyword($event)\"\n ></gn-ui-keyword-badge>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: KeywordBadgeComponent, selector: "gn-ui-keyword-badge", inputs: ["keyword", "editable"], outputs: ["keywordClick", "keywordRemove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
37526
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: GenericKeywordsComponent, isStandalone: true, selector: "gn-ui-generic-keywords", inputs: { keywords: "keywords", keywordTypes: "keywordTypes", placeholder: "placeholder", allowSubmit: "allowSubmit" }, outputs: { changedKeywords: "changedKeywords", addedKeyword: "addedKeyword", deletedKeyword: "deletedKeyword" }, ngImport: i0, template: "<div class=\"flex flex-col gap-4\">\n <gn-ui-autocomplete\n [placeholder]=\"placeholder\"\n [displayWithFn]=\"displayWithFn\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleItemSelection($event)\"\n [preventCompleteOnSelection]=\"false\"\n [minCharacterCount]=\"1\"\n [allowSubmit]=\"false\"\n [clearOnSelection]=\"true\"\n ></gn-ui-autocomplete>\n <div class=\"flex gap-2 flex-wrap\">\n @for (keyword of keywords; track keyword) {\n <gn-ui-keyword-badge\n [keyword]=\"keyword\"\n [editable]=\"true\"\n (keywordRemove)=\"removeKeyword($event)\"\n ></gn-ui-keyword-badge>\n }\n </div>\n</div>\n", dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: KeywordBadgeComponent, selector: "gn-ui-keyword-badge", inputs: ["keyword", "editable"], outputs: ["keywordClick", "keywordRemove"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38026
37527
  }
38027
37528
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: GenericKeywordsComponent, decorators: [{
38028
37529
  type: Component,
@@ -38614,7 +38115,7 @@ class FormFieldContactsForResourceComponent {
38614
38115
  provideNgIconsConfig({
38615
38116
  size: '1.5rem',
38616
38117
  }),
38617
- ], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <div class=\"flex flex-row flex-wrap gap-2\" data-test=\"rolesToPick\">\n @for (role of rolesToPick; track role) {\n <gn-ui-button type=\"gray\" (buttonClick)=\"addRoleToDisplay(role)\">\n <ng-icon name=\"iconoirPlus\" class=\"text-primary\"></ng-icon>\n &nbsp;\n <span translate>{{ roleToLabel(role) }}</span>\n </gn-ui-button>\n }\n </div>\n @if (value.length === 0) {\n <div\n class=\"p-4 border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contactsForResource.noContact\n </div>\n }\n @if (roleSectionsToDisplay && roleSectionsToDisplay.length > 0) {\n <div class=\"mt-8\" data-test=\"displayedRoles\">\n @for (\n role of roleSectionsToDisplay;\n track role;\n let index = $index;\n let isLast = $last\n ) {\n <div class=\"flex flex-col gap-4\">\n <div class=\"flex flex-row justify-between\">\n <span class=\"font-bold text-base\" translate>{{\n roleToLabel(role)\n }}</span>\n </div>\n @if (role !== 'unspecified' && role !== 'other') {\n <gn-ui-autocomplete\n [placeholder]=\"\n 'editor.record.form.field.contactsForResource.placeholder'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event, role)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n [allowSubmit]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (contactsForRessourceByRole.get(role); as contacts) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event, role)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact>\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n </ng-template>\n }\n @if (!isLast) {\n <hr class=\"border-t-[#D6D3D1] mt-4 mb-6\" />\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{--gn-ui-button-padding: 8px 8px;--gn-ui-button-rounded: 8px}\n"], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38118
+ ], usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <div class=\"flex flex-row flex-wrap gap-2\" data-test=\"rolesToPick\">\n @for (role of rolesToPick; track role) {\n <gn-ui-button type=\"gray\" (buttonClick)=\"addRoleToDisplay(role)\">\n <ng-icon name=\"iconoirPlus\" class=\"text-primary\"></ng-icon>\n &nbsp;\n <span translate>{{ roleToLabel(role) }}</span>\n </gn-ui-button>\n }\n </div>\n @if (value.length === 0) {\n <div\n class=\"p-4 border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contactsForResource.noContact\n </div>\n }\n @if (roleSectionsToDisplay && roleSectionsToDisplay.length > 0) {\n <div class=\"mt-8\" data-test=\"displayedRoles\">\n @for (\n role of roleSectionsToDisplay;\n track role;\n let index = $index;\n let isLast = $last\n ) {\n <div class=\"flex flex-col gap-4\">\n <div class=\"flex flex-row justify-between\">\n <span class=\"font-bold text-base\" translate>{{\n roleToLabel(role)\n }}</span>\n </div>\n @if (role !== 'unspecified' && role !== 'other') {\n <gn-ui-autocomplete\n [placeholder]=\"\n 'editor.record.form.field.contactsForResource.placeholder'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event, role)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n [allowSubmit]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (contactsForRessourceByRole.get(role); as contacts) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event, role)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact>\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n </ng-template>\n }\n @if (!isLast) {\n <hr class=\"border-t-[#D6D3D1] mt-4 mb-6\" />\n }\n </div>\n }\n </div>\n }\n</div>\n", styles: [":host{--gn-ui-button-padding: 8px 8px;--gn-ui-button-rounded: 8px}\n"], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38618
38119
  }
38619
38120
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsForResourceComponent, decorators: [{
38620
38121
  type: Component,
@@ -38714,7 +38215,7 @@ class FormFieldContactsComponent {
38714
38215
  this.subscription.unsubscribe();
38715
38216
  }
38716
38217
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
38717
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FormFieldContactsComponent, isStandalone: true, selector: "gn-ui-form-field-contacts", inputs: { value: "value", modelSpecifier: "modelSpecifier" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <gn-ui-autocomplete\n [placeholder]=\"'editor.record.form.field.contacts.placeholder' | translate\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n >\n </gn-ui-autocomplete>\n\n @if (contacts.length > 0) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact let-index=\"index\">\n @if (modelSpecifier === 'contact:editableDetails') {\n <gn-ui-contact-details-form\n [contact]=\"contact\"\n (contactChange)=\"handleContactChanged($event, index)\"\n ></gn-ui-contact-details-form>\n } @else {\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n }\n </ng-template>\n } @else {\n <div\n class=\"p-4 text-sm border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contacts.noContact\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: ContactDetailsFormComponent, selector: "gn-ui-contact-details-form", inputs: ["contact"], outputs: ["contactChange"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38218
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FormFieldContactsComponent, isStandalone: true, selector: "gn-ui-form-field-contacts", inputs: { value: "value", modelSpecifier: "modelSpecifier" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"flex flex-col gap-3\">\n <gn-ui-autocomplete\n [placeholder]=\"'editor.record.form.field.contacts.placeholder' | translate\"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"addContact($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"1\"\n [clearOnSelection]=\"true\"\n >\n </gn-ui-autocomplete>\n\n @if (contacts.length > 0) {\n <gn-ui-sortable-list\n [items]=\"contacts\"\n (itemsOrderChange)=\"handleContactsChanged($event)\"\n [elementTemplate]=\"contactTemplate\"\n ></gn-ui-sortable-list>\n <ng-template #contactTemplate let-contact let-index=\"index\">\n @if (modelSpecifier === 'contact:editableDetails') {\n <gn-ui-contact-details-form\n [contact]=\"contact\"\n (contactChange)=\"handleContactChanged($event, index)\"\n ></gn-ui-contact-details-form>\n } @else {\n <gn-ui-contact-card [contact]=\"contact\"></gn-ui-contact-card>\n }\n </ng-template>\n } @else {\n <div\n class=\"p-4 text-sm border border-primary bg-primary-lightest rounded-lg\"\n translate\n >\n editor.record.form.field.contacts.noContact\n </div>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: ContactCardComponent, selector: "gn-ui-contact-card", inputs: ["contact"] }, { kind: "component", type: ContactDetailsFormComponent, selector: "gn-ui-contact-details-form", inputs: ["contact"], outputs: ["contactChange"] }, { kind: "component", type: SortableListComponent, selector: "gn-ui-sortable-list", inputs: ["elementTemplate", "items"], outputs: ["itemsOrderChange"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38718
38219
  }
38719
38220
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldContactsComponent, decorators: [{
38720
38221
  type: Component,
@@ -39067,7 +38568,7 @@ class OnlineServiceResourceInputComponent {
39067
38568
  provideNgIconsConfig({
39068
38569
  size: '1.5em',
39069
38570
  }),
39070
- ], ngImport: i0, template: "<div class=\"flex flex-row justify-between\">\n <h3 class=\"text-[16px] font-bold text-main mb-[12px]\" translate>\n editor.record.form.field.onlineResource.edit.protocol\n </h3>\n @if (protocolHint) {\n <ng-icon\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"protocolHint\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n }\n</div>\n<div class=\"flex flex-row items-center gap-4 h-[48px]\">\n <mat-radio-group\n aria-labelledby=\"example-radio-group-label\"\n class=\"flex flex-row gap-[8px]\"\n [(ngModel)]=\"_service.accessServiceProtocol\"\n [disabled]=\"disabled\"\n (change)=\"resetAllFormFields()\"\n >\n @for (protocolOption of availableProtocolOptions; track protocolOption) {\n <mat-radio-button [value]=\"protocolOption.value\">\n {{ protocolOption.label | translate }}\n </mat-radio-button>\n }\n </mat-radio-group>\n</div>\n\n<div class=\"flex flex-col gap-4\">\n <gn-ui-url-input\n class=\"w-full\"\n (uploadClick)=\"handleUploadClick($event)\"\n (valueChange)=\"handleUrlValueChange($event)\"\n [disabled]=\"disabled\"\n [value]=\"_service.url?.toString()\"\n [showValidateButton]=\"activeLayerSuggestion\"\n [resetUrlOnChange]=\"resetUrlOnChange\"\n >\n @if (activeLayerSuggestion) {\n <ng-content>\n <ng-icon name=\"iconoirRefresh\"></ng-icon>\n </ng-content>\n }\n </gn-ui-url-input>\n\n @if (loading) {\n <div class=\"flex justify-center w-full py-4\">\n <gn-ui-spinning-loader></gn-ui-spinning-loader>\n </div>\n }\n @if (errorMessage) {\n <p class=\"text-sm text-red-500 pl-4\" translate>\n editor.record.form.field.onlineResource.edit.identifier.error\n </p>\n }\n\n @if (\n !activeLayerSuggestion ||\n (_service.url && errorMessage) ||\n (modifyMode && (layers$ | async).length === 0)\n ) {\n <gn-ui-text-input\n class=\"grow border-b border-gray-300 pb-4\"\n [(value)]=\"_service.identifierInService\"\n [placeholder]=\"getIdentifierPlaceholder() | translate\"\n data-cy=\"identifier-in-service\"\n [disabled]=\"disabled\"\n ></gn-ui-text-input>\n }\n @if (activeLayerSuggestion && (layers$ | async)?.length > 0) {\n <gn-ui-autocomplete\n class=\"border-b border-gray-300 pb-4\"\n [placeholder]=\"\n 'editor.record.form.field.onlineResource.edit.identifier.select.label'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleSelectValue($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"0\"\n [clearOnSelection]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (\n !modifyMode &&\n ((activeLayerSuggestion && (layers$ | async)) ||\n !activeLayerSuggestion ||\n (_service.url && errorMessage))\n ) {\n <gn-ui-button\n (buttonClick)=\"submit()\"\n [disabled]=\"disabled || !_service.identifierInService\"\n type=\"primary\"\n >\n <span class=\"text-white font-bold\" translate>\n editor.record.form.field.onlineResource.edit.identifier.submit</span\n >\n </gn-ui-button>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i3$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i3$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: SpinningLoaderComponent, selector: "gn-ui-spinning-loader" }, { kind: "component", type: TextInputComponent, selector: "gn-ui-text-input", inputs: ["value", "extraClass", "placeholder", "required", "disabled", "type"], outputs: ["valueChange"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: UrlInputComponent, selector: "gn-ui-url-input", inputs: ["value", "extraClass", "placeholder", "disabled", "showValidateButton", "resetUrlOnChange"], outputs: ["valueChange", "uploadClick"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
38571
+ ], ngImport: i0, template: "<div class=\"flex flex-row justify-between\">\n <h3 class=\"text-[16px] font-bold text-main mb-[12px]\" translate>\n editor.record.form.field.onlineResource.edit.protocol\n </h3>\n @if (protocolHint) {\n <ng-icon\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"protocolHint\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n }\n</div>\n<div class=\"flex flex-row items-center gap-4 h-[48px]\">\n <mat-radio-group\n aria-labelledby=\"example-radio-group-label\"\n class=\"flex flex-row gap-[8px]\"\n [(ngModel)]=\"_service.accessServiceProtocol\"\n [disabled]=\"disabled\"\n (change)=\"resetAllFormFields()\"\n >\n @for (protocolOption of availableProtocolOptions; track protocolOption) {\n <mat-radio-button [value]=\"protocolOption.value\">\n {{ protocolOption.label | translate }}\n </mat-radio-button>\n }\n </mat-radio-group>\n</div>\n\n<div class=\"flex flex-col gap-4\">\n <gn-ui-url-input\n class=\"w-full\"\n (uploadClick)=\"handleUploadClick($event)\"\n (valueChange)=\"handleUrlValueChange($event)\"\n [disabled]=\"disabled\"\n [value]=\"_service.url?.toString()\"\n [showValidateButton]=\"activeLayerSuggestion\"\n [resetUrlOnChange]=\"resetUrlOnChange\"\n >\n @if (activeLayerSuggestion) {\n <ng-content>\n <ng-icon name=\"iconoirRefresh\"></ng-icon>\n </ng-content>\n }\n </gn-ui-url-input>\n\n @if (loading) {\n <div class=\"flex justify-center w-full py-4\">\n <gn-ui-spinning-loader></gn-ui-spinning-loader>\n </div>\n }\n @if (errorMessage) {\n <p class=\"text-sm text-red-500 pl-4\" translate>\n editor.record.form.field.onlineResource.edit.identifier.error\n </p>\n }\n\n @if (\n !activeLayerSuggestion ||\n (_service.url && errorMessage) ||\n (modifyMode && (layers$ | async).length === 0)\n ) {\n <gn-ui-text-input\n class=\"grow border-b border-gray-300 pb-4\"\n [(value)]=\"_service.identifierInService\"\n [placeholder]=\"getIdentifierPlaceholder() | translate\"\n data-cy=\"identifier-in-service\"\n [disabled]=\"disabled\"\n ></gn-ui-text-input>\n }\n @if (activeLayerSuggestion && (layers$ | async)?.length > 0) {\n <gn-ui-autocomplete\n class=\"border-b border-gray-300 pb-4\"\n [placeholder]=\"\n 'editor.record.form.field.onlineResource.edit.identifier.select.label'\n | translate\n \"\n [action]=\"autoCompleteAction\"\n (itemSelected)=\"handleSelectValue($event)\"\n [displayWithFn]=\"displayWithFn\"\n [minCharacterCount]=\"0\"\n [clearOnSelection]=\"false\"\n >\n </gn-ui-autocomplete>\n }\n @if (\n !modifyMode &&\n ((activeLayerSuggestion && (layers$ | async)) ||\n !activeLayerSuggestion ||\n (_service.url && errorMessage))\n ) {\n <gn-ui-button\n (buttonClick)=\"submit()\"\n [disabled]=\"disabled || !_service.identifierInService\"\n type=\"primary\"\n >\n <span class=\"text-white font-bold\" translate>\n editor.record.form.field.onlineResource.edit.identifier.submit</span\n >\n </gn-ui-button>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: AutocompleteComponent, selector: "gn-ui-autocomplete", inputs: ["placeholder", "enterButton", "action", "value", "clearOnSelection", "preventCompleteOnSelection", "autoFocus", "minCharacterCount", "allowSubmit", "forceTrackPosition", "displayWithTemplate", "displayWithFn"], outputs: ["itemSelected", "inputSubmitted", "inputCleared", "isSearchActive"] }, { kind: "component", type: ButtonComponent, selector: "gn-ui-button", inputs: ["type", "disabled", "extraClass"], outputs: ["buttonClick"] }, { kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "ngmodule", type: MatRadioModule }, { kind: "directive", type: i3$1.MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: i3$1.MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: SpinningLoaderComponent, selector: "gn-ui-spinning-loader" }, { kind: "component", type: TextInputComponent, selector: "gn-ui-text-input", inputs: ["value", "extraClass", "placeholder", "required", "disabled", "type"], outputs: ["valueChange"] }, { kind: "directive", type: TranslateDirective, selector: "[translate],[ngx-translate]", inputs: ["translate", "translateParams"] }, { kind: "component", type: UrlInputComponent, selector: "gn-ui-url-input", inputs: ["value", "extraClass", "placeholder", "disabled", "showValidateButton", "resetUrlOnChange"], outputs: ["valueChange", "uploadClick"] }, { kind: "pipe", type: i1$1.AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
39071
38572
  }
39072
38573
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: OnlineServiceResourceInputComponent, decorators: [{
39073
38574
  type: Component,
@@ -40942,6 +40443,638 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
40942
40443
  args: ['gnUiSearchRouterContainer']
40943
40444
  }] } });
40944
40445
 
40446
+ const flatten = (base, obj, keepLevel = false) => Object.keys(obj).reduce((prev, curr) => {
40447
+ const path = base ? `${base}.${curr}` : curr;
40448
+ const val = obj[curr];
40449
+ if (keepLevel) {
40450
+ return { ...prev, [path]: flatten('', val) };
40451
+ }
40452
+ else if (typeof val === 'object' && !Array.isArray(val)) {
40453
+ return {
40454
+ ...prev,
40455
+ ...flatten(path, val),
40456
+ };
40457
+ }
40458
+ else {
40459
+ return { ...prev, [path]: val };
40460
+ }
40461
+ }, {});
40462
+ const checkKeys = (input, mandatory, optional) => {
40463
+ const keys = Object.keys(input);
40464
+ const missing = mandatory.filter((key) => keys.indexOf(key) === -1);
40465
+ const unrecognized = keys.filter((key) => mandatory.indexOf(key) === -1 && optional.indexOf(key) === -1);
40466
+ return {
40467
+ missing,
40468
+ unrecognized,
40469
+ };
40470
+ };
40471
+ /**
40472
+ * Only keeps recognized keys, flatten nested values (to allow having "." in keys),
40473
+ * pushes warnings and errors to the given arrays; returns null in case of error
40474
+ */
40475
+ function parseConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
40476
+ if (typeof fullConfigObj[sectionName] !== 'object') {
40477
+ if (mandatoryKeys.length === 0)
40478
+ return null;
40479
+ outErrors.push(`The [${sectionName}] mandatory section is missing.`);
40480
+ return null;
40481
+ }
40482
+ const sectionConf = fullConfigObj[sectionName];
40483
+ const keysCheck = checkKeys(sectionConf, mandatoryKeys, optionalKeys);
40484
+ if (keysCheck.missing.length) {
40485
+ // note: this is not thrown to allow merging several Errors down the line
40486
+ outErrors.push(`In the [${sectionName}] section: ${keysCheck.missing.join(', ')}`);
40487
+ return null;
40488
+ }
40489
+ else if (keysCheck.unrecognized.length) {
40490
+ outWarnings.push(`In the [${sectionName}] section: ${keysCheck.unrecognized.join(', ')}`);
40491
+ keysCheck.unrecognized.forEach((key) => delete sectionConf[key]);
40492
+ }
40493
+ return sectionConf;
40494
+ }
40495
+ /**
40496
+ * Same as parseConfigSection but keeps all keys, recognized or not
40497
+ * Also the first level is the language code (e.g. 'en')
40498
+ * This is optional
40499
+ */
40500
+ function parseTranslationsConfigSection(fullConfigObj, sectionName) {
40501
+ if (typeof fullConfigObj[sectionName] !== 'object') {
40502
+ return {};
40503
+ }
40504
+ return flatten('', fullConfigObj[sectionName], true);
40505
+ }
40506
+ /**
40507
+ * Same as parseConfigSection but handles an array of configs; this is
40508
+ * considered optional; returns null in case of error in at least one of
40509
+ * the sections
40510
+ */
40511
+ function parseMultiConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
40512
+ const sections = fullConfigObj[sectionName];
40513
+ if (!sections) {
40514
+ return [];
40515
+ }
40516
+ if (!Array.isArray(sections)) {
40517
+ outErrors.push(`Expected [[${sectionName}]] to be an array of sections.`);
40518
+ return null;
40519
+ }
40520
+ const result = sections.map((section) => parseConfigSection({ [sectionName]: section }, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors));
40521
+ if (result.some((r) => r === null)) {
40522
+ return null;
40523
+ }
40524
+ return result;
40525
+ }
40526
+ function checkMetadataLanguage(parsedConfigSection, outWarnings) {
40527
+ const lang2 = toLang2(parsedConfigSection.metadata_language.toLowerCase());
40528
+ if (lang2?.length !== 2) {
40529
+ outWarnings.push(`In the [global] section: metadata_language = "${parsedConfigSection.metadata_language}" is not a recognized ISO 639 language code`);
40530
+ }
40531
+ return parsedConfigSection;
40532
+ }
40533
+ function checkNewRecordDefaultLanguage(parsedConfigSection, outWarnings) {
40534
+ const lang2 = toLang2(parsedConfigSection.new_record_default_language.toLowerCase());
40535
+ if (!(lang2 in LANG_2_TO_3_MAPPER)) {
40536
+ outWarnings.push(`In the [editing] section: new_record_default_language = "${parsedConfigSection.new_record_default_language}" is not a recognized ISO 639 language code`);
40537
+ return {
40538
+ ...parsedConfigSection,
40539
+ new_record_default_language: undefined,
40540
+ };
40541
+ }
40542
+ return {
40543
+ ...parsedConfigSection,
40544
+ new_record_default_language: lang2,
40545
+ };
40546
+ }
40547
+ function checkNewRecordStandard(parsedConfigSection, outWarnings) {
40548
+ const standard = parsedConfigSection.new_record_standard;
40549
+ const normalizedStandard = typeof standard === 'string' ? standard.trim().toLowerCase() : null;
40550
+ if (normalizedStandard === 'iso19139' ||
40551
+ normalizedStandard === 'iso19115-3') {
40552
+ return {
40553
+ ...parsedConfigSection,
40554
+ new_record_standard: normalizedStandard,
40555
+ };
40556
+ }
40557
+ outWarnings.push(`In the [editing] section: new_record_standard = "${standard}" is not a supported metadata standard`);
40558
+ return {
40559
+ ...parsedConfigSection,
40560
+ new_record_standard: undefined,
40561
+ };
40562
+ }
40563
+
40564
+ /**
40565
+ * This loader extends the default one based on JSON files but also loads custom translations
40566
+ * defined in the app configuration
40567
+ * Implements a fallback on default lang if translated labels are empty
40568
+ */
40569
+ class FileWithOverridesTranslateLoader extends FileTranslateLoader {
40570
+ getTranslation(lang) {
40571
+ const baseLang = lang.substring(0, 2); // removing the right part of e.g. en_EN
40572
+ return super.getTranslation(baseLang).pipe(map$1((translations) => ({
40573
+ ...translations,
40574
+ ...getCustomTranslations(baseLang),
40575
+ })));
40576
+ }
40577
+ }
40578
+
40579
+ const MISSING_CONFIG_ERROR = `Application configuration was not initialized correctly.
40580
+ This error might show up in case of an invalid/malformed configuration file.
40581
+
40582
+ Note: make sure that you have called \`loadAppConfig\` from '../../../../../libs/util/app-config/src' before starting the Angular application.`;
40583
+ let globalConfig = null;
40584
+ function getGlobalConfig() {
40585
+ if (globalConfig === null)
40586
+ throw new Error(MISSING_CONFIG_ERROR);
40587
+ return globalConfig;
40588
+ }
40589
+ let themeConfig = null;
40590
+ function getThemeConfig() {
40591
+ if (themeConfig === null)
40592
+ throw new Error(MISSING_CONFIG_ERROR);
40593
+ return themeConfig;
40594
+ }
40595
+ let mapConfig = null;
40596
+ function getOptionalMapConfig() {
40597
+ return mapConfig;
40598
+ }
40599
+ let searchConfig = null;
40600
+ function getOptionalSearchConfig() {
40601
+ return searchConfig;
40602
+ }
40603
+ let editorConfig = null;
40604
+ function getOptionalEditorConfig() {
40605
+ return editorConfig;
40606
+ }
40607
+ let metadataQualityConfig = null;
40608
+ function getMetadataQualityConfig() {
40609
+ return (metadataQualityConfig ||
40610
+ {
40611
+ ENABLED: false,
40612
+ });
40613
+ }
40614
+ let customTranslations = null;
40615
+ function getCustomTranslations(langCode) {
40616
+ if (customTranslations === null)
40617
+ throw new Error(MISSING_CONFIG_ERROR);
40618
+ return langCode in customTranslations ? customTranslations[langCode] : {};
40619
+ }
40620
+ let appConfigLoaded = false;
40621
+ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
40622
+ console.log(`[geonetwork-ui] Loading application configuration from ${configUrl}`);
40623
+ return fetch(configUrl)
40624
+ .then((resp) => {
40625
+ if (!resp.ok)
40626
+ throw new Error('Configuration file could not be loaded');
40627
+ return resp.text();
40628
+ })
40629
+ .then((conf) => {
40630
+ let parsed;
40631
+ try {
40632
+ parsed = TOML.parse(conf, { joiner: '\n', bigint: false });
40633
+ }
40634
+ catch (e) {
40635
+ throw new Error(`An error occurred when parsing the configuration file: ${e.message}`);
40636
+ }
40637
+ const errors = [];
40638
+ const warnings = [];
40639
+ let parsedGlobalSection = parseConfigSection(parsed, 'global', ['geonetwork4_api_url'], [
40640
+ 'datahub_url',
40641
+ 'edit_url_template',
40642
+ 'proxy_path',
40643
+ 'metadata_language',
40644
+ 'login_url',
40645
+ 'logout_url',
40646
+ 'settings_url',
40647
+ 'web_component_embedder_url',
40648
+ 'languages',
40649
+ 'contact_email',
40650
+ 'reuse_form_url',
40651
+ ], warnings, errors);
40652
+ if (parsedGlobalSection?.metadata_language) {
40653
+ parsedGlobalSection = checkMetadataLanguage(parsedGlobalSection, warnings);
40654
+ }
40655
+ globalConfig =
40656
+ parsedGlobalSection === null
40657
+ ? null
40658
+ : {
40659
+ GN4_API_URL: parsedGlobalSection.geonetwork4_api_url,
40660
+ DATAHUB_URL: parsedGlobalSection.datahub_url,
40661
+ EDIT_URL_TEMPLATE: parsedGlobalSection.edit_url_template,
40662
+ PROXY_PATH: parsedGlobalSection.proxy_path,
40663
+ METADATA_LANGUAGE: parsedGlobalSection.metadata_language
40664
+ ? parsedGlobalSection.metadata_language.toLowerCase()
40665
+ : undefined,
40666
+ LOGIN_URL: parsedGlobalSection.login_url,
40667
+ LOGOUT_URL: parsedGlobalSection.logout_url,
40668
+ SETTINGS_URL: parsedGlobalSection.settings_url,
40669
+ WEB_COMPONENT_EMBEDDER_URL: parsedGlobalSection.web_component_embedder_url,
40670
+ LANGUAGES: parsedGlobalSection.languages,
40671
+ CONTACT_EMAIL: parsedGlobalSection.contact_email,
40672
+ REUSE_FORM_URL: parsedGlobalSection.reuse_form_url,
40673
+ };
40674
+ const parsedLayersSections = parseMultiConfigSection(parsed, 'map_layer', ['type'], ['name', 'url', 'data', 'styleUrl', 'accessToken'], warnings, errors);
40675
+ const parsedMapSection = parseConfigSection(parsed, 'map', [], [
40676
+ 'max_zoom',
40677
+ 'do_not_tile_wms',
40678
+ 'max_extent',
40679
+ 'max_feature_count',
40680
+ 'baselayer',
40681
+ 'do_not_use_default_basemap',
40682
+ 'external_viewer_url_template',
40683
+ 'external_viewer_open_new_tab',
40684
+ ], warnings, errors);
40685
+ mapConfig =
40686
+ parsedMapSection === null || parsedLayersSections === null
40687
+ ? null
40688
+ : {
40689
+ MAX_ZOOM: parsedMapSection.max_zoom,
40690
+ DO_NOT_TILE_WMS: parsedMapSection.do_not_tile_wms,
40691
+ MAX_EXTENT: parsedMapSection.max_extent,
40692
+ MAX_FEATURE_COUNT: parsedMapSection.max_feature_count,
40693
+ EXTERNAL_VIEWER_URL_TEMPLATE: parsedMapSection.external_viewer_url_template,
40694
+ EXTERNAL_VIEWER_OPEN_NEW_TAB: parsedMapSection.external_viewer_open_new_tab,
40695
+ DO_NOT_USE_DEFAULT_BASEMAP: !!parsedMapSection.do_not_use_default_basemap,
40696
+ MAP_LAYERS: parsedLayersSections.map((map_layer) => ({
40697
+ TYPE: map_layer.type,
40698
+ URL: map_layer.url,
40699
+ NAME: map_layer.name,
40700
+ DATA: map_layer.data,
40701
+ STYLE_URL: map_layer.styleUrl,
40702
+ ACCESS_TOKEN: map_layer.accessToken,
40703
+ })),
40704
+ };
40705
+ const parsedThemeSection = parseConfigSection(parsed, 'theme', ['primary_color', 'secondary_color', 'main_color', 'background_color'], [
40706
+ 'header_foreground_color',
40707
+ 'main_font',
40708
+ 'title_font',
40709
+ 'fonts_stylesheet_url',
40710
+ 'thumbnail_placeholder',
40711
+ 'header_background',
40712
+ 'favicon',
40713
+ ], warnings, errors);
40714
+ themeConfig =
40715
+ parsedThemeSection === null
40716
+ ? null
40717
+ : {
40718
+ PRIMARY_COLOR: parsedThemeSection.primary_color,
40719
+ SECONDARY_COLOR: parsedThemeSection.secondary_color,
40720
+ MAIN_COLOR: parsedThemeSection.main_color,
40721
+ BACKGROUND_COLOR: parsedThemeSection.background_color,
40722
+ HEADER_FOREGROUND_COLOR: parsedThemeSection.header_foreground_color,
40723
+ THUMBNAIL_PLACEHOLDER: parsedThemeSection.thumbnail_placeholder,
40724
+ HEADER_BACKGROUND: parsedThemeSection.header_background,
40725
+ TITLE_FONT: parsedThemeSection.title_font,
40726
+ MAIN_FONT: parsedThemeSection.main_font,
40727
+ FONTS_STYLESHEET_URL: parsedThemeSection.fonts_stylesheet_url,
40728
+ FAVICON: parsedThemeSection.favicon,
40729
+ };
40730
+ const parsedSearchSection = parseConfigSection(parsed, 'search', [], [
40731
+ 'record_kind_quick_filter',
40732
+ 'filter_geometry_data',
40733
+ 'filter_geometry_url',
40734
+ 'do_not_use_default_search_preset',
40735
+ 'search_preset',
40736
+ 'advanced_filters',
40737
+ 'limit',
40738
+ 'spatial_extent_max_file_size',
40739
+ 'geocoding_provider',
40740
+ 'geocoding_provider_options',
40741
+ 'geocoding_provider_labels',
40742
+ ], warnings, errors);
40743
+ const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
40744
+ const parsedCustomFilters = parseMultiConfigSection(parsed, 'custom_filter', ['name', 'base_filter'], ['exclude_values', 'include_values', 'label_key'], warnings, errors);
40745
+ const parsedGeocodingProviderLabels = parsedSearchSection?.geocoding_provider_labels;
40746
+ searchConfig =
40747
+ parsedSearchSection === null
40748
+ ? null
40749
+ : {
40750
+ RECORD_KIND_QUICK_FILTER: parsedSearchSection.record_kind_quick_filter,
40751
+ FILTER_GEOMETRY_DATA: parsedSearchSection.filter_geometry_data,
40752
+ FILTER_GEOMETRY_URL: parsedSearchSection.filter_geometry_url,
40753
+ DO_NOT_USE_DEFAULT_SEARCH_PRESET: !!parsedSearchSection.do_not_use_default_search_preset,
40754
+ SEARCH_PRESET: parsedSearchParams.map((param) => ({
40755
+ sort: param.sort,
40756
+ name: param.name,
40757
+ filters: param.filters,
40758
+ })),
40759
+ ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
40760
+ CUSTOM_FILTERS: (parsedCustomFilters ?? []).map((customFilter) => ({
40761
+ name: customFilter.name,
40762
+ baseFilter: customFilter.base_filter,
40763
+ excludeValues: customFilter.exclude_values,
40764
+ includeValues: customFilter.include_values,
40765
+ labelKey: customFilter.label_key,
40766
+ })),
40767
+ LIMIT: parsedSearchSection.limit,
40768
+ SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
40769
+ GEOCODING_PROVIDER: parsedSearchSection.geocoding_provider,
40770
+ GEOCODING_PROVIDER_OPTIONS: parsedSearchSection.geocoding_provider_options,
40771
+ GEOCODING_PROVIDER_LABELS: parsedGeocodingProviderLabels
40772
+ ? {
40773
+ MAIN: parsedGeocodingProviderLabels.main,
40774
+ SECONDARY: parsedGeocodingProviderLabels.secondary,
40775
+ TERTIARY: parsedGeocodingProviderLabels.tertiary,
40776
+ }
40777
+ : undefined,
40778
+ };
40779
+ const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
40780
+ metadataQualityConfig =
40781
+ parsedMetadataQualitySection === null
40782
+ ? null
40783
+ : {
40784
+ ENABLED: parsedMetadataQualitySection.enabled,
40785
+ SORTABLE: parsedMetadataQualitySection.sortable,
40786
+ };
40787
+ let parsedEditingSection = parseConfigSection(parsed, 'editing', [], ['new_record_default_language', 'new_record_standard'], warnings, errors);
40788
+ if (parsedEditingSection !== null &&
40789
+ parsedEditingSection.new_record_default_language !== undefined) {
40790
+ parsedEditingSection = checkNewRecordDefaultLanguage(parsedEditingSection, warnings);
40791
+ }
40792
+ if (parsedEditingSection !== null &&
40793
+ parsedEditingSection.new_record_standard !== undefined) {
40794
+ parsedEditingSection = checkNewRecordStandard(parsedEditingSection, warnings);
40795
+ }
40796
+ editorConfig =
40797
+ parsedEditingSection === null
40798
+ ? null
40799
+ : {
40800
+ NEW_RECORD_DEFAULT_LANGUAGE: parsedEditingSection.new_record_default_language,
40801
+ NEW_RECORD_STANDARD: parsedEditingSection.new_record_standard,
40802
+ };
40803
+ customTranslations = parseTranslationsConfigSection(parsed, 'translations');
40804
+ if (errors.length) {
40805
+ throw new Error(`One or more mandatory settings were missing from the configuration file.
40806
+ ${errors.join('\n')}`);
40807
+ }
40808
+ else if (warnings.length) {
40809
+ console.warn(`One or more unexpected settings were encountered in the configuration file.
40810
+ ${warnings.join('\n')}`);
40811
+ }
40812
+ appConfigLoaded = true;
40813
+ });
40814
+ }
40815
+ function isConfigLoaded() {
40816
+ return appConfigLoaded;
40817
+ }
40818
+ function _reset() {
40819
+ globalConfig = null;
40820
+ themeConfig = null;
40821
+ editorConfig = null;
40822
+ customTranslations = null;
40823
+ }
40824
+ const TRANSLATE_WITH_OVERRIDES_CONFIG = {
40825
+ compiler: {
40826
+ provide: TranslateCompiler,
40827
+ useClass: TranslateMessageFormatCompiler,
40828
+ },
40829
+ loader: [
40830
+ {
40831
+ provide: TRANSLATE_HTTP_LOADER_CONFIG,
40832
+ useValue: {
40833
+ prefix: './assets/i18n/',
40834
+ suffix: '.json',
40835
+ },
40836
+ },
40837
+ {
40838
+ provide: TranslateLoader,
40839
+ useClass: FileWithOverridesTranslateLoader,
40840
+ deps: [HttpClient, TRANSLATE_HTTP_LOADER_CONFIG],
40841
+ },
40842
+ ],
40843
+ };
40844
+
40845
+ const okAppConfigFixture = () => `
40846
+ [global]
40847
+ geonetwork4_api_url = "/geonetwork/srv/api"
40848
+ proxy_path = "/proxy/?url="
40849
+ metadata_language = "fre"
40850
+ login_url = "/cas/login?service="
40851
+ logout_url = "/geonetwork/signout"
40852
+ settings_url = "/geonetwork/settings"
40853
+ web_component_embedder_url = "/datahub/wc-embedder.html"
40854
+
40855
+ [map]
40856
+ max_zoom = 10
40857
+ max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
40858
+ do_not_use_default_basemap = false
40859
+ external_viewer_url_template = 'https://example.com/myviewer?'
40860
+ external_viewer_open_new_tab = true
40861
+ [[map_layer]]
40862
+ type = "wms"
40863
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
40864
+ name = "masque_hdf_ign_carto_latin1"
40865
+ [[map_layer]]
40866
+ type = "wfs"
40867
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
40868
+ name = "masque_hdf_ign_carto_latin1"
40869
+
40870
+ [theme]
40871
+ primary_color = "#093564"
40872
+ secondary_color = "#c2e9dc"
40873
+ main_color = "#212029" # All-purpose text color
40874
+ background_color = "#fdfbff"
40875
+ thumbnail_placeholder = 'assets/img/placeholder.svg'
40876
+ header_background = 'teal'
40877
+ header_foreground_color = "#872e2e"
40878
+ main_font = 'sans-serif'
40879
+ title_font = 'serif'
40880
+ fonts_stylesheet_url = "https://fonts.googleapis.com/css2?family=Open+Sans"
40881
+
40882
+ [search]
40883
+ record_kind_quick_filter = false
40884
+ filter_geometry_url = 'https://my.domain.org/geom.json'
40885
+ do_not_use_default_search_preset = false
40886
+ geocoding_provider = "geoplateforme"
40887
+ geocoding_provider_options.index = "poi"
40888
+ geocoding_provider_options.category = "administratif"
40889
+ geocoding_provider_options.limit = 5
40890
+ geocoding_provider_labels.main = '/properties/name/0'
40891
+ geocoding_provider_labels.secondary = '/properties/citycode/0'
40892
+ geocoding_provider_labels.tertiary = '/properties/category/1'
40893
+ advanced_filters = ['publicationYear', 'documentStandard', 'inspireKeyword', 'topic', 'license', 'myOrg:firstCustomFilter', 'myOrg:secondCustomFilter']
40894
+
40895
+ [[custom_filter]]
40896
+ name = 'myOrg:firstCustomFilter'
40897
+ base_filter = 'keyword'
40898
+ exclude_values = ['my keyword 1', 'my keyword 2']
40899
+ label_key = 'myOrg.firstCustomFilter'
40900
+
40901
+ [[custom_filter]]
40902
+ name = 'myOrg:secondCustomFilter'
40903
+ base_filter = 'keyword'
40904
+ include_values = ['my keyword 3', 'my keyword 4']
40905
+ label_key = 'myOrg.secondCustomFilter'
40906
+
40907
+ [[search_preset]]
40908
+ sort = "-createDate"
40909
+ name = 'filterByOrgs'
40910
+ filters.q = 'Carto'
40911
+ filters.organisation = ['Org1', 'Org2']
40912
+ filters.format = ['ESRI Shapefile']
40913
+ filters.topic = ['boundaries']
40914
+ filters.publicationYear = ['2023', '2022']
40915
+ filters.spatial = ['yes']
40916
+
40917
+ [translations.en]
40918
+ "my.first.key" = 'First label.'
40919
+ "my.second.key" = """
40920
+ Second label,
40921
+ on two lines."""
40922
+
40923
+ [translations.de]
40924
+ my.first.key = 'Erste Etikett.'
40925
+
40926
+ [translations.fr]
40927
+ my.sample.text = "Un bon exemple de texte."
40928
+ "my.quoted.text" = 'du texte entre guillements.'
40929
+ `;
40930
+ const appConfigWithTranslationFixture = () => okAppConfigFixture();
40931
+ const minimalAppConfigFixture = () => `
40932
+ [global]
40933
+ geonetwork4_api_url = "/geonetwork/srv/api"
40934
+ proxy_path = "/proxy/?url="
40935
+
40936
+ [theme]
40937
+ primary_color = "#093564"
40938
+ secondary_color = "#c2e9dc"
40939
+ main_color = "#212029" # All-purpose text color
40940
+ background_color = "#fdfbff"
40941
+ `;
40942
+ const customFilterMissingMandatoryConfigFixture = () => `
40943
+ [global]
40944
+ geonetwork4_api_url = "/geonetwork/srv/api"
40945
+
40946
+ [theme]
40947
+ primary_color = "#093564"
40948
+ secondary_color = "#c2e9dc"
40949
+ main_color = "#212029" # All-purpose text color
40950
+ background_color = "#fdfbff"
40951
+
40952
+ [search]
40953
+ advanced_filters = ['myOrg:firstCustomFilter']
40954
+
40955
+ [[custom_filter]]
40956
+ name = 'myOrg:firstCustomFilter'
40957
+ `;
40958
+ const mapConfigFixture = () => ({
40959
+ MAX_ZOOM: 10,
40960
+ MAX_EXTENT: [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855],
40961
+ DO_NOT_USE_DEFAULT_BASEMAP: false,
40962
+ DO_NOT_TILE_WMS: false,
40963
+ EXTERNAL_VIEWER_URL_TEMPLATE: 'https://example.com/myviewer/#/?actions=[{"type":"CATALOG:ADD_LAYERS_FROM_CATALOGS","layers":["${layer_name}"],"sources":[{"url":"${service_url}","type":"${service_type}"}]}]',
40964
+ EXTERNAL_VIEWER_OPEN_NEW_TAB: true,
40965
+ MAP_LAYERS: [
40966
+ {
40967
+ TYPE: 'xyz',
40968
+ URL: 'https://some-basemap-server',
40969
+ },
40970
+ {
40971
+ TYPE: 'wms',
40972
+ URL: 'https://some-wms-server',
40973
+ NAME: 'some_layername',
40974
+ },
40975
+ {
40976
+ TYPE: 'wfs',
40977
+ URL: 'https://some-wfs-server',
40978
+ NAME: 'some_layername',
40979
+ },
40980
+ ],
40981
+ });
40982
+ const malformedConfigFixture = () => `
40983
+ {
40984
+ "I thought": "we were still doing json"
40985
+ }
40986
+ `;
40987
+ const missingMandatoryConfigFixture = () => `
40988
+ [theme]
40989
+ primary_color = "#093564"
40990
+ secondary_color = "#c2e9dc"
40991
+ background_color = "#fdfbff"
40992
+ main_font = 'sans-serif'
40993
+ `;
40994
+ const wrongLanguageCodeConfigFixture = () => `
40995
+ [global]
40996
+ geonetwork4_api_url = "/geonetwork/srv/api"
40997
+ proxy_path = "/proxy/?url="
40998
+ metadata_language = "abc"
40999
+
41000
+ [map]
41001
+
41002
+ [theme]
41003
+ primary_color = "#093564"
41004
+ secondary_color = "#c2e9dc"
41005
+ main_color = "#212029" # All-purpose text color
41006
+ background_color = "#fdfbff"
41007
+ `;
41008
+ const unrecognizedKeysConfigFixture = () => `
41009
+ [global]
41010
+ geonetwork4_api_url = "/geonetwork/srv/api"
41011
+ proxy_path = "/proxy/?url="
41012
+ metadata_language = "fre"
41013
+ another_path = '/whatever'
41014
+
41015
+ [map]
41016
+ max_zoom = 10
41017
+ max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
41018
+ do_not_use_default_basemap = false
41019
+ external_viewer_url_template = 'https://example.com/myviewer?'
41020
+ external_viewer_open_new_tab = true
41021
+ another_zoom = 15
41022
+ [[map_layer]]
41023
+ type = "wms"
41024
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
41025
+ name = "masque_hdf_ign_carto_latin1"
41026
+ [[map_layer]]
41027
+ type = "wfs"
41028
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
41029
+ name = "masque_hdf_ign_carto_latin1"
41030
+ another_layer = "wrong layer definition"
41031
+
41032
+ [theme]
41033
+ primary_color = "#093564"
41034
+ secondary_color = "#c2e9dc"
41035
+ main_color = "#212029" # All-purpose text color
41036
+ background_color = "#fdfbff"
41037
+ thumbnail_placeholder = 'assets/img/placeholder.svg'
41038
+ header_background = 'teal'
41039
+ header_foreground_color = "#872e2e"
41040
+ main_font = 'sans-serif'
41041
+ title_font = 'serif'
41042
+ another_color = 'red'
41043
+ `;
41044
+
41045
+ function getMapContextLayerFromConfig(config) {
41046
+ switch (config.TYPE) {
41047
+ case 'wms':
41048
+ return {
41049
+ type: 'wms',
41050
+ url: config.URL,
41051
+ name: config.NAME,
41052
+ };
41053
+ case 'wfs':
41054
+ return {
41055
+ type: 'wfs',
41056
+ url: config.URL,
41057
+ featureType: config.NAME,
41058
+ };
41059
+ case 'xyz':
41060
+ return {
41061
+ type: config.TYPE,
41062
+ url: config.URL,
41063
+ };
41064
+ case 'geojson':
41065
+ return {
41066
+ type: config.TYPE,
41067
+ ...(config.DATA ? { data: config.DATA } : { url: config.URL }),
41068
+ };
41069
+ case 'maplibre-style':
41070
+ return {
41071
+ type: config.TYPE,
41072
+ styleUrl: config.STYLE_URL,
41073
+ accessToken: config.ACCESS_TOKEN,
41074
+ };
41075
+ }
41076
+ }
41077
+
40945
41078
  const CHART_TYPE_VALUES = [
40946
41079
  'bar',
40947
41080
  'bar-horizontal',
@@ -40957,5 +41090,5 @@ const CHART_TYPE_VALUES = [
40957
41090
  * Generated bundle index. Do not edit.
40958
41091
  */
40959
41092
 
40960
- export { ADD_RESULTS, ADD_SEARCH, AVAILABLE_LICENSES, AbstractAction, AbstractSearchField, ActionMenuComponent, AddLayerFromCatalogComponent, AddLayerRecordPreviewComponent, AddResults, AddSearch, AnchorLinkDirective, ApiCardComponent, ApplicationBannerComponent, AuthService, AutocompleteComponent, AutofocusDirective, AvailableServicesField, AvatarComponent, AvatarServiceInterface, BASEMAP_LAYERS, BadgeComponent, BaseConverter, BaseFileReader, BaseReader, BlockListComponent, BoundingBoxSearchField, ButtonComponent, CHART_TYPE_VALUES, CLEAR_ERROR, CLEAR_RESULTS, CarouselComponent, CatalogTitleComponent, CellPopinComponent, ChartComponent, ChartViewComponent, CheckToggleComponent, CheckboxComponent, ClearError, ClearResults, ColorScaleComponent, ConfirmationDialogComponent, ContactDetailsComponent, ContactDetailsFormComponent, ContactPillComponent, ContentGhostComponent, CopyTextButtonComponent, DEFAULT_BASEMAP_LAYER, DEFAULT_CONFIGURATION, DEFAULT_GN4_LOGIN_URL, DEFAULT_GN4_LOGOUT_URL, DEFAULT_GN4_SETTINGS_URL, DEFAULT_LANG, DEFAULT_PAGE_SIZE, DEFAULT_RECORD_CONVERTER, DEFAULT_RESULTS_LAYOUT_CONFIG, DEFAULT_SEARCH_KEY, DEFAULT_SPATIAL_EXTENT_STYLE, DISABLE_AUTH, DISABLE_DRAFT, DO_NOT_USE_DEFAULT_BASEMAP, DataService, DataTableComponent, DataViewComponent, DataViewPermalinkComponent, DataViewShareComponent, DataViewWebComponentComponent, DatePickerComponent, DateRangeDropdownComponent, DateRangeInputsComponent, DateRangePickerComponent, DateRangeSearchField, DateService, DcatApConverter, DefaultRouterModule, DownloadItemComponent, DownloadsListComponent, DragAndDropFileInputComponent, DropdownMultiselectComponent, DropdownSelectorComponent, EDITOR_FEATURE_KEY, ES_QUERY_FIELDS_PRIORITY, ES_RESOURCES_VALUES, ES_SOURCE_SUMMARY, EXTERNAL_VIEWER_OPEN_NEW_TAB, EXTERNAL_VIEWER_URL_TEMPLATE, EditableLabelDirective, EditorFacade, EditorService, ElasticsearchService, ErrorComponent, ErrorType, ExpandablePanelButtonComponent, ExpandablePanelComponent, ExternalLinkCardComponent, ExternalViewerButtonComponent, FIELDS_BRIEF, FIELDS_SUMMARY, FILTER_GEOMETRY, FILTER_SUMMARY_IGNORE_LIST, FORMATS, FacetBlockComponent, FacetItemComponent, FacetListComponent, FacetsContainerComponent, FavoriteStarComponent, FavoritesService, FeatureCatalogListComponent, FeatureDetailComponent, FeatureEditorModule, FeatureMapModule, FeatureRecordModule, FeatureSearchModule, FetchError, FieldFocusDirective, FieldsService, FigureComponent, FigureContainerComponent, FileInputComponent, FileTranslateLoader, FilesDropDirective, FilterDropdownComponent, FormFieldArrayComponent, FormFieldComponent, FormFieldDateComponent, FormFieldFileComponent, FormFieldKeywordsComponent, FormFieldLicenseComponent, FormFieldObjectComponent, FormFieldRichComponent, FormFieldSimpleComponent, FormFieldSpatialExtentComponent, FormFieldTemporalExtentsComponent, FormFieldTopicsComponent, FormFieldWrapperComponent, FullTextSearchField, FuzzySearchComponent, GEONETWORK_UI_TAG_NAME, GEONETWORK_UI_VERSION, GeoDataBadgeComponent, GeoTableViewComponent, GeocodingComponent, GeojsonReader, Gn4Converter, Gn4PlatformMapper, Gn4PlatformService, Gn4Repository, Gn4SettingsService, GnUiHumanizeDateDirective, GpfApiDlComponent, GravatarService, I18nInterceptor, ISO_TOPICS, ImageFallbackDirective, ImageInputComponent, ImageOverlayPreviewComponent, ImportRecordComponent, InlineFilterComponent, InteractiveTableColumnComponent, InteractiveTableComponent, InternalLinkCardComponent, IsSpatialSearchField, Iso191153Converter, Iso19139Converter, KeywordBadgeComponent, KindBadgeComponent, LANGUAGES_LIST, LANGUAGE_NAMES, LANGUAGE_STORAGE_KEY, LANG_2_TO_3_MAPPER, LOGIN_URL, LOGOUT_URL, LONLAT_CRS_CODES, LanguageSwitcherComponent, LayersPanelComponent, LicenseSearchField, LinkClassifierService, LinkUsage, LoadingMaskComponent, LogService, MAP_FEATURE_KEY, MAP_VIEW_CONSTRAINTS, MAX_UPLOAD_SIZE_MB, METADATA_LANGUAGE, MapContainerComponent, MapFacade, MapLegendComponent, MapStateContainerComponent, MapStyleService, MapUtilsService, MapViewComponent, MarkdownEditorComponent, MarkdownParserComponent, MaxLinesComponent, mdview_actions as MdViewActions, MdViewFacade, MetadataCatalogComponent, MetadataContactComponent, MetadataDoiComponent, MetadataInfoComponent, MetadataLinkType, MetadataMapperContext, MetadataQualityComponent, MetadataQualityItemComponent, MetadataQualityPanelComponent, ModalDialogComponent, MultilingualPanelComponent, MultilingualSearchField, MyOrgService, NAMESPACES, NOT_APPLICABLE_CONSTRAINT, NOT_KNOWN_CONSTRAINT, NotificationComponent, NotificationsContainerComponent, NotificationsService, OPEN_DATA_LICENSE, ORGANIZATIONS_STRATEGY, ORGANIZATION_PAGE_URL_TOKEN, ORGANIZATION_URL_TOKEN, OnlineResourceCardComponent, OnlineServiceResourceInputComponent, OrganisationPreviewComponent, OrganisationsComponent, OrganisationsFilterComponent, OrganisationsResultComponent, OrganizationSearchField, OrganizationsFromGroupsService, OrganizationsFromMetadataService, OrganizationsServiceInterface, OwnerSearchField, PAGINATE, PARSE_DELIMITER, PATCH_RESULTS_AGGREGATIONS, PROXY_PATH, Paginate, PaginationButtonsComponent, PaginationComponent, PaginationDotsComponent, PatchResultsAggregations, PlatformServiceInterface, PopoverComponent, PopupAlertComponent, PossibleResourceTypes, PossibleResourceTypesDefinition, PreviousNextButtonsComponent, ProgressBarComponent, ProxyService, QUERY_FIELDS, RECORD_DATASET_URL_TOKEN, RECORD_REUSE_URL_TOKEN, RECORD_SERVICE_URL_TOKEN, REQUEST_MORE_ON_AGGREGATION, REQUEST_MORE_RESULTS, REQUEST_NEW_RESULTS, RESULTS_LAYOUT_CONFIG, REUSE_LIGHT_CONFIGURATION, ROUTER_CONFIG, ROUTER_ROUTE_DATASET, ROUTER_ROUTE_ORGANIZATION, ROUTER_ROUTE_REUSE, ROUTER_ROUTE_SEARCH, ROUTER_ROUTE_SERVICE, ROUTER_STATE_KEY, ROUTE_PARAMS, RecordApiFormComponent, RecordFormComponent, RecordKindField, RecordMetaComponent, RecordMetricComponent, RecordPreviewCardComponent, RecordPreviewComponent, RecordPreviewFeedComponent, RecordPreviewListComponent, RecordPreviewRowComponent, RecordPreviewTextComponent, RecordPreviewTitleComponent, RecordStatusValues, RecordsMetricsComponent, RecordsRepositoryInterface, RecordsService, RequestMoreOnAggregation, RequestMoreResults, RequestNewResults, ResourceCreationRevisionDateSearchField, ResourceTypeLegacyField, ResultsHitsContainerComponent, ResultsHitsNumberComponent, ResultsHitsSearchKindComponent, ResultsLayoutComponent, ResultsLayoutConfigItem, ResultsListComponent, ResultsListContainerComponent, ResultsListItemComponent, ResultsTableComponent, ResultsTableContainerComponent, ReusePresentationForms, RoleLabels, RoleValues, RouterEffects, RouterFacade, RouterService, SEARCH_FEATURE_KEY, SETTINGS_URL, SET_CONFIG_AGGREGATIONS, SET_CONFIG_FILTERS, SET_CONFIG_REQUEST_FIELDS, SET_ERROR, SET_FAVORITES_ONLY, SET_FILTERS, SET_INCLUDE_ON_AGGREGATION, SET_PAGE_SIZE, SET_RESULTS_AGGREGATIONS, SET_RESULTS_HITS, SET_RESULTS_LAYOUT, SET_SEARCH, SET_SORT_BY, SET_SPATIAL_FILTER_ENABLED, SPATIAL_SCOPES, SearchEffects, SearchFacade, SearchFeatureCatalogComponent, SearchFiltersSummaryComponent, SearchFiltersSummaryItemComponent, SearchInputComponent, SearchRouterContainerDirective, SearchService, SearchStateContainerDirective, SelectionService, ServiceCapabilitiesComponent, SetConfigAggregations, SetConfigFilters, SetConfigRequestFields, SetError, SetFavoritesOnly, SetFilters, SetIncludeOnAggregation, SetPageSize, SetResultsAggregations, SetResultsHits, SetResultsLayout, SetSearch, SetSortBy, SetSpatialFilterEnabled, SimpleSearchField, SiteTitleComponent, SortByComponent, SortByEnum, SortableListComponent, SourceLabelComponent, SourcesService, SpatialExtentComponent, SpatialExtentDropdownComponent, SpinningLoaderComponent, StacItemsResultGridComponent, StacViewComponent, StarToggleComponent, StickyHeaderComponent, SupportedTypes, SwitchToggleComponent, THUMBNAIL_PLACEHOLDER, TRANSLATE_DEBUG_CONFIG, TRANSLATE_DEFAULT_CONFIG, TRANSLATE_WITH_OVERRIDES_CONFIG, TableViewComponent, TextAreaComponent, TextInputComponent, ThemeService, ThumbnailComponent, TranslatedSearchField, TruncatedTextComponent, UPDATE_CONFIG_AGGREGATIONS, UPDATE_FILTERS, UPDATE_REQUEST_AGGREGATION_TERM, UpdateConfigAggregations, UpdateFilters, UrlInputComponent, UserFeedbackItemComponent, UserPreviewComponent, UserSearchField, VECTOR_STYLE_DEFAULT, ViewportIntersectorComponent, WEB_COMPONENT_EMBEDDER_URL, XmlParseError, _reset, allChildrenElement, appConfigWithTranslationFixture, appendChildTree, appendChildren, assertValidXml, associationTypeValues, bboxToPolygon, blockModelFixture, bytesToMegabytes, canEditRecord, checkFileFormat, clearSelectedFeatures, createChild, createDocument, createElement, createFuzzyFilter, createNestedChild, createNestedElement, createSpatialExtentLayer, currentPage, defaultMapStyleFixture, defaultMapStyleHlFixture, downgradeImage, downsizeImage, draftSaveSuccess, dragPanCondition, dropEmptyTranslations, editorReducer, emptyBlockModelFixture, findChildElement, findChildOrCreate, findChildrenElement, findConverterForDocument, findNestedChildOrCreate, findNestedElement, findNestedElements, findParent, firstChildElement, formatDate, formatUserInfo, getAddressLines, getAllKeysValidator, getArrayItem, getAsArray, getAsUrl, getBadgeColor, getCustomTranslations, getError, getFavoritesOnly, getFileFormat, getFileFormatFromServiceOutput, getFirstValue, getFormatPriority, getGeometryBoundingBox, getGeometryFromGeoJSON, getGlobalConfig, getIndividualDisplayName, getIsMobile, getJsonDataItemsProxy, getKeywordHierarchyPath, getLayers, getLinkId, getLinkLabel, getLinkPriority, getMapContext, getMapContextLayerFromConfig, getMapState, getMetadataQualityConfig, getMimeTypeForFormat, getNamespace, getOptionalEditorConfig, getOptionalMapConfig, getOptionalSearchConfig, getPageSize, getQualityValidators, getResourceType, getReusePresentationForm, getReuseType, getRootElement, getSearchConfigAggregations, getSearchFilters, getSearchResults, getSearchResultsAggregations, getSearchResultsHits, getSearchResultsLayout, getSearchResultsLoading, getSearchSortBy, getSearchState, getSearchStateSearch, getSelectedFeatures, getSpatialFilterEnabled, getTemporalRangeUnion, getThemeConfig, handleScrollOnNavigation, hasRecordChangedSinceDraft, hasRecordChangedSinceDraftSuccess, initSearch, initialEditorState, initialMapState, initialState, isBoundingBox, isConfigLoaded, isDateRange, isFileExtensionValid, isFormatInQueryParam, isPublished, itemModelFixture, kindToCodeListValue, loadAppConfig, malformedConfigFixture, mapConfigFixture, mapContact, mapKeywords, mapLogo, mapOrganization, mapReducer, markRecordAsChanged, matchesNoApplicableConstraint, matchesNoKnownConstraint, megabytesToBytes, mimeTypeToFormat, minimalAppConfigFixture, missingMandatoryConfigFixture, mouseWheelZoomCondition, noDuplicateFileName, okAppConfigFixture, openDataset, openRecord, organizationsServiceFactory, parse, parseXmlString, placeholder, prioritizePageScroll, propagateToDocumentOnly, provideGn4, provideI18n, provideLocalizedDateAdapter, provideRepositoryUrl, readAttribute, readDataset, readDatasetHeaders, readFileAsText, readText, reducer$2 as reducer, reducerSearch, removeAllChildren, removeChildren, removeChildrenByName, removeSearchParams, removeWhitespace, renameElements, saveRecord, saveRecordFailure, saveRecordSuccess, selectCanEditRecord, selectCurrentPage, selectEditorConfig, selectEditorState, selectFallback, selectFallbackFields, selectField, selectHasRecordChanged, selectIsPublished, selectRecord, selectRecordChangedSinceSave, selectRecordSaveError, selectRecordSaving, selectRecordSections, selectRecordSource, selectTranslatedField, selectTranslatedValue, setContext, setCurrentPage, setEditorConfiguration, setFieldVisibility, setFocusedField, setSelectedFeatures, setTextContent, sortByFromString, sortByToString, sortByToStrings, spatialExtentToGeometry, spatialExtentsToFeatureCollection, stripHtml, stripNamespace, toDate, toIndividual, toLang2, toLang3, totalPages, undoRecordDraft, unrecognizedKeysConfigFixture, updateFrequencyCodeValues, updateLanguages, updateRecordField, updateRecordLanguages, wmsLayerFlatten, writeAttribute, wrongLanguageCodeConfigFixture, xmlToString };
41093
+ export { ADD_RESULTS, ADD_SEARCH, AVAILABLE_LICENSES, AbstractAction, AbstractSearchField, ActionMenuComponent, AddLayerFromCatalogComponent, AddLayerRecordPreviewComponent, AddResults, AddSearch, AnchorLinkDirective, ApiCardComponent, ApplicationBannerComponent, AuthService, AutocompleteComponent, AutofocusDirective, AvailableServicesField, AvatarComponent, AvatarServiceInterface, BASEMAP_LAYERS, BadgeComponent, BaseConverter, BaseFileReader, BaseReader, BlockListComponent, BoundingBoxSearchField, ButtonComponent, CHART_TYPE_VALUES, CLEAR_ERROR, CLEAR_RESULTS, CUSTOM_FIELDS, CarouselComponent, CatalogTitleComponent, CellPopinComponent, ChartComponent, ChartViewComponent, CheckToggleComponent, CheckboxComponent, ClearError, ClearResults, ColorScaleComponent, ConfirmationDialogComponent, ContactDetailsComponent, ContactDetailsFormComponent, ContactPillComponent, ContentGhostComponent, CopyTextButtonComponent, DEFAULT_BASEMAP_LAYER, DEFAULT_CONFIGURATION, DEFAULT_GEOCODING_PROVIDER, DEFAULT_GN4_LOGIN_URL, DEFAULT_GN4_LOGOUT_URL, DEFAULT_GN4_SETTINGS_URL, DEFAULT_LANG, DEFAULT_PAGE_SIZE, DEFAULT_RECORD_CONVERTER, DEFAULT_RESULTS_LAYOUT_CONFIG, DEFAULT_SEARCH_KEY, DEFAULT_SPATIAL_EXTENT_STYLE, DISABLE_AUTH, DISABLE_DRAFT, DO_NOT_USE_DEFAULT_BASEMAP, DataService, DataTableComponent, DataViewComponent, DataViewPermalinkComponent, DataViewShareComponent, DataViewWebComponentComponent, DatePickerComponent, DateRangeDropdownComponent, DateRangeInputsComponent, DateRangePickerComponent, DateRangeSearchField, DateService, DcatApConverter, DefaultRouterModule, DownloadItemComponent, DownloadsListComponent, DragAndDropFileInputComponent, DropdownMultiselectComponent, DropdownSelectorComponent, EDITOR_FEATURE_KEY, ES_QUERY_FIELDS_PRIORITY, ES_RESOURCES_VALUES, ES_SOURCE_SUMMARY, EXTERNAL_VIEWER_OPEN_NEW_TAB, EXTERNAL_VIEWER_URL_TEMPLATE, EditableLabelDirective, EditorFacade, EditorService, ElasticsearchService, ErrorComponent, ErrorType, ExpandablePanelButtonComponent, ExpandablePanelComponent, ExternalLinkCardComponent, ExternalViewerButtonComponent, FIELDS_BRIEF, FIELDS_SUMMARY, FILTER_GEOMETRY, FILTER_SUMMARY_IGNORE_LIST, FORMATS, FacetBlockComponent, FacetItemComponent, FacetListComponent, FacetsContainerComponent, FavoriteStarComponent, FavoritesService, FeatureCatalogListComponent, FeatureDetailComponent, FeatureEditorModule, FeatureMapModule, FeatureRecordModule, FeatureSearchModule, FetchError, FieldFocusDirective, FieldsService, FigureComponent, FigureContainerComponent, FileInputComponent, FileTranslateLoader, FilesDropDirective, FilterDropdownComponent, FormFieldArrayComponent, FormFieldComponent, FormFieldDateComponent, FormFieldFileComponent, FormFieldKeywordsComponent, FormFieldLicenseComponent, FormFieldObjectComponent, FormFieldRichComponent, FormFieldSimpleComponent, FormFieldSpatialExtentComponent, FormFieldTemporalExtentsComponent, FormFieldTopicsComponent, FormFieldWrapperComponent, FullTextSearchField, FuzzySearchComponent, GEOCODING_PROVIDER, GEOCODING_PROVIDER_LABELS, GEONETWORK_UI_TAG_NAME, GEONETWORK_UI_VERSION, GeoDataBadgeComponent, GeoTableViewComponent, GeocodingService, GeojsonReader, Gn4Converter, Gn4PlatformMapper, Gn4PlatformService, Gn4Repository, Gn4SettingsService, GnUiHumanizeDateDirective, GpfApiDlComponent, GravatarService, I18nInterceptor, ISO_TOPICS, ImageFallbackDirective, ImageInputComponent, ImageOverlayPreviewComponent, ImportRecordComponent, InlineFilterComponent, InteractiveTableColumnComponent, InteractiveTableComponent, InternalLinkCardComponent, IsSpatialSearchField, Iso191153Converter, Iso19139Converter, KeywordBadgeComponent, KindBadgeComponent, LANGUAGES_LIST, LANGUAGE_NAMES, LANGUAGE_STORAGE_KEY, LANG_2_TO_3_MAPPER, LOGIN_URL, LOGOUT_URL, LONLAT_CRS_CODES, LanguageSwitcherComponent, LayersPanelComponent, LicenseSearchField, LinkClassifierService, LinkUsage, LoadingMaskComponent, LocationSearchComponent, LogService, MAP_FEATURE_KEY, MAP_VIEW_CONSTRAINTS, MAX_UPLOAD_SIZE_MB, METADATA_LANGUAGE, MapContainerComponent, MapFacade, MapLegendComponent, MapStateContainerComponent, MapUtilsService, MapViewComponent, MarkdownEditorComponent, MarkdownParserComponent, MaxLinesComponent, mdview_actions as MdViewActions, MdViewFacade, MetadataCatalogComponent, MetadataContactComponent, MetadataDoiComponent, MetadataInfoComponent, MetadataLinkType, MetadataMapperContext, MetadataQualityComponent, MetadataQualityItemComponent, MetadataQualityPanelComponent, ModalDialogComponent, MultilingualPanelComponent, MultilingualSearchField, MyOrgService, NAMESPACES, NOT_APPLICABLE_CONSTRAINT, NOT_KNOWN_CONSTRAINT, NotificationComponent, NotificationsContainerComponent, NotificationsService, OPEN_DATA_LICENSE, ORGANIZATIONS_STRATEGY, ORGANIZATION_PAGE_URL_TOKEN, ORGANIZATION_URL_TOKEN, OnlineResourceCardComponent, OnlineServiceResourceInputComponent, OrganisationPreviewComponent, OrganisationsComponent, OrganisationsFilterComponent, OrganisationsResultComponent, OrganizationSearchField, OrganizationsFromGroupsService, OrganizationsFromMetadataService, OrganizationsServiceInterface, OwnerSearchField, PAGINATE, PARSE_DELIMITER, PATCH_RESULTS_AGGREGATIONS, PROXY_PATH, Paginate, PaginationButtonsComponent, PaginationComponent, PaginationDotsComponent, PatchResultsAggregations, PlatformServiceInterface, PopoverComponent, PopupAlertComponent, PossibleResourceTypes, PossibleResourceTypesDefinition, PreviousNextButtonsComponent, ProgressBarComponent, ProxyService, QUERY_FIELDS, RECORD_DATASET_URL_TOKEN, RECORD_REUSE_URL_TOKEN, RECORD_SERVICE_URL_TOKEN, REQUEST_MORE_ON_AGGREGATION, REQUEST_MORE_RESULTS, REQUEST_NEW_RESULTS, RESULTS_LAYOUT_CONFIG, REUSE_LIGHT_CONFIGURATION, ROUTER_CONFIG, ROUTER_ROUTE_DATASET, ROUTER_ROUTE_ORGANIZATION, ROUTER_ROUTE_REUSE, ROUTER_ROUTE_SEARCH, ROUTER_ROUTE_SERVICE, ROUTER_STATE_KEY, ROUTE_PARAMS, RecordApiFormComponent, RecordFormComponent, RecordKindField, RecordMetaComponent, RecordMetricComponent, RecordPreviewCardComponent, RecordPreviewComponent, RecordPreviewFeedComponent, RecordPreviewListComponent, RecordPreviewRowComponent, RecordPreviewTextComponent, RecordPreviewTitleComponent, RecordStatusValues, RecordsMetricsComponent, RecordsRepositoryInterface, RecordsService, RequestMoreOnAggregation, RequestMoreResults, RequestNewResults, ResourceCreationRevisionDateSearchField, ResourceTypeLegacyField, ResultsHitsContainerComponent, ResultsHitsNumberComponent, ResultsHitsSearchKindComponent, ResultsLayoutComponent, ResultsLayoutConfigItem, ResultsListComponent, ResultsListContainerComponent, ResultsListItemComponent, ResultsTableComponent, ResultsTableContainerComponent, ReusePresentationForms, RoleLabels, RoleValues, RouterEffects, RouterFacade, RouterService, SEARCH_FEATURE_KEY, SETTINGS_URL, SET_CONFIG_AGGREGATIONS, SET_CONFIG_FILTERS, SET_CONFIG_REQUEST_FIELDS, SET_ERROR, SET_FAVORITES_ONLY, SET_FILTERS, SET_INCLUDE_ON_AGGREGATION, SET_PAGE_SIZE, SET_RESULTS_AGGREGATIONS, SET_RESULTS_HITS, SET_RESULTS_LAYOUT, SET_SEARCH, SET_SORT_BY, SET_SPATIAL_FILTER_ENABLED, SPATIAL_EXTENT_MAX_FILE_SIZE, SPATIAL_SCOPES, SearchEffects, SearchFacade, SearchFeatureCatalogComponent, SearchFiltersSummaryComponent, SearchFiltersSummaryItemComponent, SearchInputComponent, SearchRouterContainerDirective, SearchService, SearchStateContainerDirective, SelectionService, ServiceCapabilitiesComponent, SetConfigAggregations, SetConfigFilters, SetConfigRequestFields, SetError, SetFavoritesOnly, SetFilters, SetIncludeOnAggregation, SetPageSize, SetResultsAggregations, SetResultsHits, SetResultsLayout, SetSearch, SetSortBy, SetSpatialFilterEnabled, SimpleSearchField, SiteTitleComponent, SortByComponent, SortByEnum, SortableListComponent, SourceLabelComponent, SourcesService, SpatialExtentComponent, SpatialExtentDropdownComponent, SpinningLoaderComponent, StacItemsResultGridComponent, StacViewComponent, StarToggleComponent, StickyHeaderComponent, SupportedTypes, SwitchToggleComponent, THUMBNAIL_PLACEHOLDER, TRANSLATE_DEBUG_CONFIG, TRANSLATE_DEFAULT_CONFIG, TRANSLATE_WITH_OVERRIDES_CONFIG, TableViewComponent, TextAreaComponent, TextInputComponent, ThemeService, ThumbnailComponent, TranslatedSearchField, TruncatedTextComponent, UPDATE_CONFIG_AGGREGATIONS, UPDATE_FILTERS, UPDATE_REQUEST_AGGREGATION_TERM, UpdateConfigAggregations, UpdateFilters, UrlInputComponent, UserFeedbackItemComponent, UserPreviewComponent, UserSearchField, VECTOR_STYLE_DEFAULT, ViewportIntersectorComponent, WEB_COMPONENT_EMBEDDER_URL, XmlParseError, _reset, allChildrenElement, appConfigWithTranslationFixture, appendChildTree, appendChildren, assertValidXml, associationTypeValues, bboxToPolygon, blockModelFixture, bytesToMegabytes, canEditRecord, checkFileFormat, clearSelectedFeatures, createChild, createDocument, createElement, createFuzzyFilter, createNestedChild, createNestedElement, createSpatialExtentLayer, currentPage, customFilterMissingMandatoryConfigFixture, downgradeImage, downsizeImage, draftSaveSuccess, dragPanCondition, dropEmptyTranslations, editorReducer, emptyBlockModelFixture, findChildElement, findChildOrCreate, findChildrenElement, findConverterForDocument, findNestedChildOrCreate, findNestedElement, findNestedElements, findParent, firstChildElement, formatDate, formatUserInfo, getAddressLines, getAllKeysValidator, getArrayItem, getAsArray, getAsUrl, getBadgeColor, getCustomTranslations, getError, getFavoritesOnly, getFileFormat, getFileFormatFromServiceOutput, getFirstValue, getFormatPriority, getGeometryBoundingBox, getGeometryFromGeoJSON, getGlobalConfig, getIndividualDisplayName, getIsMobile, getJsonDataItemsProxy, getKeywordHierarchyPath, getLayers, getLinkId, getLinkLabel, getLinkPriority, getMapContext, getMapContextLayerFromConfig, getMapState, getMetadataQualityConfig, getMimeTypeForFormat, getNamespace, getOptionalEditorConfig, getOptionalMapConfig, getOptionalSearchConfig, getPageSize, getQualityValidators, getResourceType, getReusePresentationForm, getReuseType, getRootElement, getSearchConfigAggregations, getSearchFilters, getSearchResults, getSearchResultsAggregations, getSearchResultsHits, getSearchResultsLayout, getSearchResultsLoading, getSearchSortBy, getSearchState, getSearchStateSearch, getSelectedFeatures, getSpatialFilterEnabled, getTemporalRangeUnion, getThemeConfig, handleScrollOnNavigation, hasRecordChangedSinceDraft, hasRecordChangedSinceDraftSuccess, initSearch, initialEditorState, initialMapState, initialState, isBoundingBox, isBoundingBoxWithinWorldExtent, isConfigLoaded, isDateRange, isFileExtensionValid, isFormatInQueryParam, isPublished, itemModelFixture, kindToCodeListValue, loadAppConfig, malformedConfigFixture, mapConfigFixture, mapContact, mapKeywords, mapLogo, mapOrganization, mapReducer, markRecordAsChanged, matchesNoApplicableConstraint, matchesNoKnownConstraint, megabytesToBytes, mimeTypeToFormat, minimalAppConfigFixture, missingMandatoryConfigFixture, mouseWheelZoomCondition, noDuplicateFileName, okAppConfigFixture, openDataset, openRecord, organizationsServiceFactory, parse, parseXmlString, placeholder, prioritizePageScroll, propagateToDocumentOnly, provideGn4, provideI18n, provideLocalizedDateAdapter, provideRepositoryUrl, readAttribute, readDataset, readDatasetHeaders, readFileAsText, readText, reducer$2 as reducer, reducerSearch, removeAllChildren, removeChildren, removeChildrenByName, removeSearchParams, removeWhitespace, renameElements, saveRecord, saveRecordFailure, saveRecordSuccess, selectCanEditRecord, selectCurrentPage, selectEditorConfig, selectEditorState, selectFallback, selectFallbackFields, selectField, selectHasRecordChanged, selectIsPublished, selectRecord, selectRecordChangedSinceSave, selectRecordSaveError, selectRecordSaving, selectRecordSections, selectRecordSource, selectTranslatedField, selectTranslatedValue, setContext, setCurrentPage, setEditorConfiguration, setFieldVisibility, setFocusedField, setSelectedFeatures, setTextContent, sortByFromString, sortByToString, sortByToStrings, spatialExtentToGeometry, spatialExtentsToFeatureCollection, stripHtml, stripNamespace, toDate, toIndividual, toLang2, toLang3, totalPages, undoRecordDraft, unrecognizedKeysConfigFixture, updateFrequencyCodeValues, updateLanguages, updateRecordField, updateRecordLanguages, wmsLayerFlatten, writeAttribute, wrongLanguageCodeConfigFixture, xmlToString };
40961
41094
  //# sourceMappingURL=geonetwork-ui.mjs.map