geonetwork-ui 2.11.0-dev.f5ee66b24 → 2.11.0-dev.fb48cfeee

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 (74) hide show
  1. package/fesm2022/geonetwork-ui.mjs +1570 -1196
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +153 -71
  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 +395 -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 +17 -6
  11. package/src/libs/api/metadata-converter/src/lib/iso19115-3/read-parts.ts +110 -0
  12. package/src/libs/api/metadata-converter/src/lib/iso19115-3/write-parts.ts +131 -0
  13. package/src/libs/api/metadata-converter/src/lib/iso19139/iso19139.converter.ts +9 -0
  14. package/src/libs/api/metadata-converter/src/lib/iso19139/read-parts.ts +2 -1
  15. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +29 -3
  16. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +83 -35
  17. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +11 -0
  18. package/src/libs/common/domain/src/lib/model/record/flags.model.ts +1 -0
  19. package/src/libs/common/domain/src/lib/model/record/index.ts +1 -0
  20. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +14 -18
  21. package/src/libs/common/domain/src/lib/model/search/aggregation.model.ts +2 -0
  22. package/src/libs/common/domain/src/lib/model/search/filter.model.ts +4 -1
  23. package/src/libs/common/domain/src/lib/platform.service.interface.ts +1 -0
  24. package/src/libs/common/domain/src/lib/repository/records-repository.interface.ts +20 -1
  25. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +42 -62
  26. package/src/libs/feature/dataviz/src/lib/service/data.service.ts +32 -19
  27. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints/form-field-constraints.component.ts +3 -5
  28. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-contacts/form-field-contacts.component.ts +2 -2
  29. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-record-flags/form-field-record-flag-component.css +0 -0
  30. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-record-flags/form-field-record-flag-component.html +18 -0
  31. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-record-flags/form-field-record-flag-component.ts +86 -0
  32. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +100 -88
  33. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +11 -4
  34. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +18 -4
  35. package/src/libs/feature/editor/src/lib/expressions.ts +67 -0
  36. package/src/libs/feature/editor/src/lib/fields.config.ts +13 -0
  37. package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +10 -4
  38. package/src/libs/feature/map/src/index.ts +0 -1
  39. package/src/libs/feature/notify-reuse/src/lib/notify-reuse-form/notify-reuse-form.component.ts +8 -3
  40. package/src/libs/feature/record/src/lib/state/mdview.effects.ts +3 -1
  41. package/src/libs/feature/record/src/lib/state/mdview.facade.ts +1 -1
  42. package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.html +7 -1
  43. package/src/libs/feature/search/src/lib/filter-dropdown/filter-dropdown.component.ts +26 -4
  44. package/src/libs/feature/search/src/lib/geocoding/geocoding.service.ts +52 -8
  45. package/src/libs/feature/search/src/lib/location-search/location-search.component.html +11 -1
  46. package/src/libs/feature/search/src/lib/location-search/location-search.component.ts +77 -3
  47. package/src/libs/feature/search/src/lib/search-filters-summary-item/search-filters-summary-item.component.ts +1 -0
  48. package/src/libs/feature/search/src/lib/state/reducer.ts +1 -4
  49. package/src/libs/feature/search/src/lib/utils/service/fields.service.ts +56 -4
  50. package/src/libs/feature/search/src/lib/utils/service/fields.ts +33 -9
  51. package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.html +3 -3
  52. package/src/libs/ui/elements/src/lib/record-feature-catalog/feature-catalog-list/feature-catalog-list.component.ts +2 -2
  53. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.css +0 -4
  54. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.html +2 -2
  55. package/src/libs/ui/inputs/src/lib/autocomplete/autocomplete.component.ts +3 -3
  56. package/src/libs/ui/inputs/src/lib/search-feature-catalog/search-feature-catalog.component.ts +2 -1
  57. package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.html +8 -2
  58. package/src/libs/ui/inputs/src/lib/spatial-extent-dropdown/spatial-extent-dropdown.component.ts +34 -5
  59. package/src/libs/ui/layout/src/lib/block-list/block-list.component.css +1 -0
  60. package/src/libs/util/app-config/src/lib/app-config.ts +34 -0
  61. package/src/libs/util/app-config/src/lib/fixtures.ts +37 -1
  62. package/src/libs/util/app-config/src/lib/model.ts +24 -1
  63. package/src/libs/util/shared/src/lib/utils/geojson.ts +16 -0
  64. package/translations/de.json +12 -1
  65. package/translations/en.json +14 -3
  66. package/translations/es.json +12 -1
  67. package/translations/fr.json +19 -8
  68. package/translations/it.json +12 -1
  69. package/translations/nl.json +12 -1
  70. package/translations/pt.json +12 -1
  71. package/translations/sk.json +12 -1
  72. package/src/libs/feature/map/src/lib/style/index.ts +0 -2
  73. package/src/libs/feature/map/src/lib/style/map-style.fixtures.ts +0 -47
  74. package/src/libs/feature/map/src/lib/style/map-style.service.ts +0 -108
@@ -14,7 +14,7 @@ import * as i4 from '@ngx-translate/core';
14
14
  import { TranslateLoader, TranslateCompiler, TranslateDefaultParser, TranslateParser, TranslateService, provideTranslateService, TranslateDirective, TranslatePipe, TranslateModule } from '@ngx-translate/core';
15
15
  import { TranslateMessageFormatCompiler } from 'ngx-translate-messageformat-compiler';
16
16
  import { TranslateHttpLoader, TRANSLATE_HTTP_LOADER_CONFIG } from '@ngx-translate/http-loader';
17
- import { map as map$1, shareReplay as shareReplay$1, catchError, tap as tap$1, filter as filter$1, startWith as startWith$1, withLatestFrom, switchMap as switchMap$1, take, mergeMap, delay, debounceTime, distinctUntilChanged, finalize, throttleTime, first as first$1, pairwise as pairwise$1, share, defaultIfEmpty, toArray } from 'rxjs/operators';
17
+ import { map as map$1, shareReplay as shareReplay$1, catchError, tap as tap$1, withLatestFrom, filter as filter$1, startWith as startWith$1, switchMap as switchMap$1, take, mergeMap, delay, debounceTime, distinctUntilChanged, finalize, throttleTime, first as first$1, pairwise as pairwise$1, share, defaultIfEmpty, toArray } from 'rxjs/operators';
18
18
  import { lt, valid, coerce, satisfies, ltr } from 'semver';
19
19
  import chroma from 'chroma-js';
20
20
  import * as i1$1 from '@angular/common';
@@ -36,11 +36,8 @@ import { createLegendFromLayer } from '@geospatial-sdk/legend';
36
36
  import { mouseOnly, noModifierKeys, primaryAction, platformModifierKeyOnly } from 'ol/events/condition.js';
37
37
  import { defaults, DragPan, MouseWheelZoom } from 'ol/interaction.js';
38
38
  import { extend } from 'ol/extent.js';
39
- import * as TOML from '@ltd/j-toml';
40
- import { Style, Stroke, Fill, Circle } from 'ol/style.js';
41
- import CircleStyle from 'ol/style/Circle.js';
42
39
  import EmblaCarousel from 'embla-carousel';
43
- 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';
44
41
  import { MatButtonModule } from '@angular/material/button';
45
42
  import * as i1$7 from '@angular/cdk/overlay';
46
43
  import { ScrollStrategyOptions, OverlayModule, CdkConnectedOverlay, ScrollDispatcher, Overlay, CdkOverlayOrigin } from '@angular/cdk/overlay';
@@ -55,7 +52,7 @@ import { matClose, matContentCopy, matExpandMore, matExpandLess, matSearch, matS
55
52
  import * as i1$4 from '@angular/material/checkbox';
56
53
  import { MatCheckboxModule } from '@angular/material/checkbox';
57
54
  import * as i1$5 from '@angular/material/tooltip';
58
- import { MatTooltipModule } from '@angular/material/tooltip';
55
+ import { MatTooltipModule, MatTooltip } from '@angular/material/tooltip';
59
56
  import { MAT_DATE_LOCALE, MAT_DATE_FORMATS, DateAdapter } from '@angular/material/core';
60
57
  import { MAT_DATE_FNS_FORMATS, DateFnsAdapter } from '@angular/material-date-fns-adapter';
61
58
  import { enUS } from 'date-fns/locale/en-US';
@@ -73,7 +70,8 @@ import { MatTabsModule } from '@angular/material/tabs';
73
70
  import * as i2$2 from '@ngrx/effects';
74
71
  import { Actions, createEffect, ofType, EffectsModule } from '@ngrx/effects';
75
72
  import { valid as valid$1 } from 'geojson-validation';
76
- import { queryDataGouvFr, queryGeonames, queryGeoadmin } from '@geospatial-sdk/geocoding';
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
  }
@@ -2466,6 +2469,8 @@ class Iso19139Converter extends BaseConverter {
2466
2469
  this.writers['resourceIdentifiers'](record, rootEl);
2467
2470
  if (record.kind === 'dataset') {
2468
2471
  fieldChanged('status') && this.writers['status'](record, rootEl);
2472
+ fieldChanged('featureTypeDescriptions') &&
2473
+ this.writers['featureTypeDescriptions'](record, rootEl);
2469
2474
  }
2470
2475
  if (record.kind === 'dataset' || record.kind === 'reuse') {
2471
2476
  fieldChanged('updateFrequency') &&
@@ -2633,6 +2638,34 @@ function readDefaultLanguage$1(rootEl) {
2633
2638
  function readOtherLanguages(rootEl) {
2634
2639
  return pipe(findChildrenElement('mdb:otherLocale', false), mapArray(readLocaleElement()), map((languages) => languages.filter((lang) => lang !== null)))(rootEl);
2635
2640
  }
2641
+ function extractCharacterStringOrText() {
2642
+ return fallback(extractCharacterString(), readText());
2643
+ }
2644
+ function extractListedValue() {
2645
+ return pipe(combine(pipe(findChildElement('gfc:code', false), extractCharacterString()), pipe(findChildElement('gfc:label', false), extractCharacterString()), pipe(findChildElement('gfc:definition', false), extractCharacterString())), map(([code, label, description]) => ({
2646
+ value: code ?? '',
2647
+ ...(label && { label }),
2648
+ ...(description && { description }),
2649
+ })));
2650
+ }
2651
+ function extractFeatureAttribute() {
2652
+ return pipe(combine(pipe(findChildElement('gfc:memberName', false), extractCharacterStringOrText()), pipe(findChildElement('gfc:designation', false), extractCharacterString()), 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.value || value.label)))), map(([name, label, description, code, type, values]) => ({
2653
+ name: name ?? '',
2654
+ ...(label && { label }),
2655
+ ...(description && { description }),
2656
+ ...(code && { code }),
2657
+ ...(type && { type }),
2658
+ ...(values.length > 0 && { values }),
2659
+ })));
2660
+ }
2661
+ function readFeatureTypeDescriptions(rootEl) {
2662
+ 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:designation', false), extractCharacterString()), pipe(findChildElement('gfc:definition', false), extractCharacterString()), pipe(findNestedElements('gfc:carrierOfCharacteristics', 'gfc:FC_FeatureAttribute'), mapArray(extractFeatureAttribute()))), map(([name, label, description, attributes]) => ({
2663
+ name: name ?? '',
2664
+ ...(label && { label }),
2665
+ ...(description && { description }),
2666
+ attributes,
2667
+ })))))(rootEl);
2668
+ }
2636
2669
 
2637
2670
  function writeUniqueIdentifier$1(record, rootEl) {
2638
2671
  pipe(findNestedChildOrCreate('mdb:metadataIdentifier', 'mcc:MD_Identifier', 'mcc:code'), writeCharacterString(record.uniqueIdentifier))(rootEl);
@@ -2787,6 +2820,52 @@ function writeAssociatedRecords(record, rootEl) {
2787
2820
  .filter((assoc) => assoc.uniqueIdentifier && assoc.associationType)
2788
2821
  .map((assoc) => pipe(createNestedElement('mri:associatedResource', 'mri:MD_AssociatedResource'), appendChildren(pipe(createNestedElement('mri:associationType', 'mri:DS_AssociationTypeCode'), writeAttribute('codeList', 'http://standards.iso.org/iso/19115/resources/Codelists/cat/codelists.xml#DS_AssociationTypeCode'), writeAttribute('codeListValue', assoc.associationType)), pipe(createElement('mri:metadataReference'), writeAttribute('uuidref', assoc.uniqueIdentifier)))))))(rootEl);
2789
2822
  }
2823
+ function createNilElement(name, nilReason) {
2824
+ return pipe(createElement(name), writeAttribute('gco:nilReason', nilReason));
2825
+ }
2826
+ function createFeatureCatalogueShell() {
2827
+ return pipe(createNestedElement('mdb:contentInfo', 'mrc:MD_FeatureCatalogue', 'mrc:featureCatalogue', 'gfc:FC_FeatureCatalogue'),
2828
+ // create mandatory elements which are not part of the model yet
2829
+ appendChildren(createNilElement('cat:name', 'missing'), createNilElement('cat:scope', 'missing'), createNilElement('cat:versionNumber', 'missing'), createNilElement('cat:versionDate', 'missing'), createNilElement('gfc:producer', 'missing')));
2830
+ }
2831
+ function createListedValue(value) {
2832
+ return pipe(createNestedElement('gfc:listedValue', 'gfc:FC_ListedValue'), appendChildren(value.label
2833
+ ? pipe(createElement('gfc:label'), writeCharacterString(value.label))
2834
+ : createNilElement('gfc:label', 'missing'), value.value
2835
+ ? pipe(createElement('gfc:code'), writeCharacterString(value.value))
2836
+ : null, value.description
2837
+ ? pipe(createElement('gfc:definition'), writeCharacterString(value.description))
2838
+ : null));
2839
+ }
2840
+ function createFeatureAttribute(attribute) {
2841
+ return pipe(createNestedElement('gfc:carrierOfCharacteristics', 'gfc:FC_FeatureAttribute'), appendChildren(pipe(createElement('gfc:memberName'), setTextContent(attribute.name)), attribute.description
2842
+ ? pipe(createElement('gfc:definition'), writeCharacterString(attribute.description))
2843
+ : null, createNilElement('gfc:cardinality', 'missing'), attribute.label
2844
+ ? pipe(createElement('gfc:designation'), writeCharacterString(attribute.label))
2845
+ : null, attribute.code
2846
+ ? pipe(createElement('gfc:code'), writeCharacterString(attribute.code))
2847
+ : null, attribute.type
2848
+ ? pipe(createNestedElement('gfc:valueType', 'gco:TypeName', 'gco:aName'), writeCharacterString(attribute.type))
2849
+ : null, ...(attribute.values ?? [])
2850
+ .filter((value) => value.value || value.label)
2851
+ .map(createListedValue)));
2852
+ }
2853
+ function createFeatureType(featureType) {
2854
+ return pipe(createNestedElement('gfc:featureType', 'gfc:FC_FeatureType'), appendChildren(pipe(createElement('gfc:typeName'), setTextContent(featureType.name)), featureType.description
2855
+ ? pipe(createElement('gfc:definition'), writeCharacterString(featureType.description))
2856
+ : null, pipe(createNestedElement('gfc:isAbstract', 'gco:Boolean'), setTextContent('false')), featureType.label
2857
+ ? pipe(createElement('gfc:designation'), writeCharacterString(featureType.label))
2858
+ : null, ...featureType.attributes.map(createFeatureAttribute), createNilElement('gfc:featureCatalogue', 'missing')));
2859
+ }
2860
+ function writeFeatureTypeDescriptions(record, rootEl) {
2861
+ const featureTypes = record.featureTypeDescriptions ?? [];
2862
+ const catalogues = findNestedElements('mdb:contentInfo', 'mrc:MD_FeatureCatalogue', 'mrc:featureCatalogue', 'gfc:FC_FeatureCatalogue')(rootEl);
2863
+ catalogues.forEach((catalogue) => removeChildrenByName('gfc:featureType')(catalogue));
2864
+ if (!featureTypes.length)
2865
+ return;
2866
+ const catalogue = catalogues[0] ?? appendChildTree(createFeatureCatalogueShell())(rootEl);
2867
+ appendChildren(...featureTypes.map(createFeatureType))(catalogue);
2868
+ }
2790
2869
 
2791
2870
  class Iso191153Converter extends Iso19139Converter {
2792
2871
  constructor() {
@@ -2803,6 +2882,7 @@ class Iso191153Converter extends Iso19139Converter {
2803
2882
  this.readers['lineage'] = readLineage;
2804
2883
  this.readers['sourceRecords'] = readSourceRecords;
2805
2884
  this.readers['associatedRecords'] = readAssociatedRecords;
2885
+ this.readers['featureTypeDescriptions'] = readFeatureTypeDescriptions;
2806
2886
  this.readers['onlineResources'] = readOnlineResources$1;
2807
2887
  this.readers['defaultLanguage'] = readDefaultLanguage$1;
2808
2888
  this.readers['otherLanguages'] = readOtherLanguages;
@@ -2823,6 +2903,7 @@ class Iso191153Converter extends Iso19139Converter {
2823
2903
  this.writers['lineage'] = writeLineage;
2824
2904
  this.writers['sourceRecords'] = writeSourceRecords;
2825
2905
  this.writers['associatedRecords'] = writeAssociatedRecords;
2906
+ this.writers['featureTypeDescriptions'] = writeFeatureTypeDescriptions;
2826
2907
  this.writers['onlineResources'] = writeOnlineResources;
2827
2908
  this.writers['status'] = writeStatus;
2828
2909
  this.writers['spatialRepresentation'] = writeSpatialRepresentation;
@@ -2912,10 +2993,12 @@ class Iso191153Converter extends Iso19139Converter {
2912
2993
  });
2913
2994
  }
2914
2995
  async writeRecord(record, reference) {
2915
- let result = await super.writeRecord(record, reference);
2916
- // fix gco namespace definition (changes between iso19139 and iso19115-3
2917
- result = result.replace('"http://www.isotc211.org/2005/gco"', '"http://standards.iso.org/iso/19115/-3/gco/1.0"');
2918
- return result;
2996
+ const result = await super.writeRecord(record, reference);
2997
+ // fix the gco and gfc namespace definitions (they change between iso19139 and iso19115-3);
2998
+ // only on the root element, where they are declared, so that nested declarations stay untouched
2999
+ return result.replace(/<mdb:MD_Metadata[^>]*>/, (rootTag) => rootTag
3000
+ .replace('"http://www.isotc211.org/2005/gco"', '"http://standards.iso.org/iso/19115/-3/gco/1.0"')
3001
+ .replace('"http://www.isotc211.org/2005/gfc"', '"http://standards.iso.org/iso/19110/gfc/1.1"'));
2919
3002
  }
2920
3003
  }
2921
3004
 
@@ -3459,6 +3542,7 @@ class DcatApConverter extends BaseConverter {
3459
3542
  lineage: () => '',
3460
3543
  sourceRecords: () => [],
3461
3544
  associatedRecords: () => [],
3545
+ featureTypeDescriptions: () => undefined,
3462
3546
  temporalExtents: () => [],
3463
3547
  spatialRepresentation: () => undefined,
3464
3548
  extras: () => undefined,
@@ -3494,6 +3578,7 @@ class DcatApConverter extends BaseConverter {
3494
3578
  lineage: () => undefined,
3495
3579
  sourceRecords: () => [],
3496
3580
  associatedRecords: () => [],
3581
+ featureTypeDescriptions: () => undefined,
3497
3582
  onlineResources: () => undefined,
3498
3583
  temporalExtents: () => undefined,
3499
3584
  spatialExtents: () => undefined,
@@ -18904,9 +18989,15 @@ class Gn4FieldMapper {
18904
18989
  isOpenData: (output, source) => this.addExtra({
18905
18990
  isOpenData: selectField(source, 'isOpenData') !== 'false',
18906
18991
  }, output),
18907
- featureTypes: (output, source) => this.addExtra({
18908
- featureTypes: selectField(source, 'featureTypes'),
18909
- }, output),
18992
+ featureTypes: (output, source) => {
18993
+ const featureTypes = getAsArray(selectField(source, 'featureTypes'));
18994
+ if (!featureTypes.length)
18995
+ return output;
18996
+ return {
18997
+ ...output,
18998
+ featureTypeDescriptions: this.featureTypesField(featureTypes),
18999
+ };
19000
+ },
18910
19001
  related: (output, source) => {
18911
19002
  const related = selectField(source, 'related');
18912
19003
  const fcatSource = selectField(getFirstValue(selectField(related, 'fcats')) ?? {}, '_source');
@@ -19042,6 +19133,27 @@ class Gn4FieldMapper {
19042
19133
  },
19043
19134
  };
19044
19135
  this.genericField = (output) => output;
19136
+ this.featureTypesField = (featureTypes) => featureTypes.map((featureType) => ({
19137
+ name: featureType.typeName ?? '',
19138
+ ...(featureType.definition && {
19139
+ description: featureType.definition,
19140
+ }),
19141
+ attributes: getAsArray(featureType.attributeTable ?? []).map((attr) => {
19142
+ const values = (attr.values ?? [])
19143
+ .filter((value) => value.code || value.label)
19144
+ .map((value) => ({
19145
+ value: value.code || '',
19146
+ ...(value.label && { label: value.label }),
19147
+ }));
19148
+ return {
19149
+ name: attr.name ?? '',
19150
+ ...(attr.definition && { description: attr.definition }),
19151
+ ...(attr.code && { code: attr.code }),
19152
+ ...(attr.type && { type: attr.type }),
19153
+ ...(values.length > 0 && { values }),
19154
+ };
19155
+ }),
19156
+ }));
19045
19157
  this.constraintField = (type, output, constraintArray) => {
19046
19158
  let outputField;
19047
19159
  switch (type) {
@@ -19596,6 +19708,19 @@ function isBoundingBox(value) {
19596
19708
  value.length === 4 &&
19597
19709
  value.every((item) => typeof item === 'number'));
19598
19710
  }
19711
+ /**
19712
+ * Checks that a bounding box's coordinates stay within the valid
19713
+ * longitude (-180/180) and latitude (-90/90) ranges.
19714
+ */
19715
+ function isBoundingBoxWithinWorldExtent(bbox) {
19716
+ const [minX, minY, maxX, maxY] = bbox;
19717
+ return (minX >= -180 &&
19718
+ maxX <= 180 &&
19719
+ minY >= -90 &&
19720
+ maxY <= 90 &&
19721
+ minX <= maxX &&
19722
+ minY <= maxY);
19723
+ }
19599
19724
  function getGeometryBoundingBox(geometry) {
19600
19725
  // use the bounding box if specified in the GeoJSON object
19601
19726
  if (geometry.bbox) {
@@ -20439,7 +20564,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
20439
20564
  }] } });
20440
20565
 
20441
20566
  var name = "geonetwork-ui";
20442
- var version = "2.11.0-dev.f5ee66b24";
20567
+ var version = "2.11.0-dev.fb48cfeee";
20443
20568
  var engines = {
20444
20569
  node: ">=24"
20445
20570
  };
@@ -20481,10 +20606,10 @@ var dependencies = {
20481
20606
  "@biesbjerg/ngx-translate-extract-marker": "~1.0.0",
20482
20607
  "@camptocamp/ogc-client": "1.3.1-dev.200c02a",
20483
20608
  "@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",
20609
+ "@geospatial-sdk/core": "0.0.5-dev.86.sha-124eae3",
20610
+ "@geospatial-sdk/geocoding": "0.0.5-dev.86.sha-124eae3",
20611
+ "@geospatial-sdk/legend": "0.0.5-dev.86.sha-124eae3",
20612
+ "@geospatial-sdk/openlayers": "0.0.5-dev.86.sha-124eae3",
20488
20613
  "@ltd/j-toml": "~1.38.0",
20489
20614
  "@messageformat/core": "~3.4.0",
20490
20615
  "@ng-icons/core": "~32.5.0",
@@ -20501,6 +20626,7 @@ var dependencies = {
20501
20626
  "embla-carousel": "~8.6.0",
20502
20627
  "flag-icons": "~7.5.0",
20503
20628
  "geojson-validation": "~1.0.2",
20629
+ jsonpointer: "^5.0.1",
20504
20630
  marked: "~17.0.4",
20505
20631
  "ngx-dropzone": "~3.1.0",
20506
20632
  "ngx-translate-messageformat-compiler": "~7.2.0",
@@ -20677,6 +20803,7 @@ class ElasticsearchService {
20677
20803
  // runtime fields are computed using a Painless script
20678
20804
  // see: https://www.elastic.co/guide/en/elasticsearch/reference/current/runtime-mapping-fields.html
20679
20805
  this.runtimeFields = {};
20806
+ this.fieldAliases = {};
20680
20807
  }
20681
20808
  // we're using getters in case the defined languages change over time
20682
20809
  get metadataLang() {
@@ -20748,6 +20875,9 @@ class ElasticsearchService {
20748
20875
  registerRuntimeField(fieldName, expression, type = 'keyword') {
20749
20876
  this.runtimeFields[fieldName] = { script: expression, type };
20750
20877
  }
20878
+ registerFieldAlias(fieldIdentifier, esFieldName) {
20879
+ this.fieldAliases[fieldIdentifier] = esFieldName;
20880
+ }
20751
20881
  getMetadataByIdsPayload(uuids) {
20752
20882
  return {
20753
20883
  query: {
@@ -20869,12 +20999,25 @@ class ElasticsearchService {
20869
20999
  }
20870
21000
  return Object.values(filters).find(isBoundingBox);
20871
21001
  }
20872
- // if a field registered min/max runtime fields, its dates form an interval
20873
- // the record matches if that interval intersects the filter range
21002
+ // builds a query matching records whose dates intersect the filter range
20874
21003
  buildDateRangeQuery(searchField, dateRange) {
21004
+ // fields ending with 'DateRange' maps as ES range type
21005
+ if (searchField.endsWith('DateRange')) {
21006
+ return {
21007
+ range: {
21008
+ [searchField]: {
21009
+ ...(dateRange.start && { gte: formatDate(dateRange.start) }),
21010
+ ...(dateRange.end && { lte: formatDate(dateRange.end) }),
21011
+ format: 'yyyy-MM-dd',
21012
+ relation: 'intersects',
21013
+ },
21014
+ },
21015
+ };
21016
+ }
20875
21017
  const minField = `${searchField}Min`;
20876
21018
  const maxField = `${searchField}Max`;
20877
21019
  if (minField in this.runtimeFields && maxField in this.runtimeFields) {
21020
+ // min/max runtime fields form an interval per record; match if it intersects the filter range
20878
21021
  const filter = [
20879
21022
  dateRange.start && {
20880
21023
  range: {
@@ -20929,7 +21072,7 @@ class ElasticsearchService {
20929
21072
  .filter((fieldname) => !Array.isArray(filters[fieldname]))
20930
21073
  .filter((fieldname) => filters[fieldname] &&
20931
21074
  JSON.stringify(filters[fieldname]) !== '{}')
20932
- .map((fieldname) => `${fieldname}:(${makeQuery(filters[fieldname])})`)
21075
+ .map((fieldname) => `${this.fieldAliases[fieldname] ?? fieldname}:(${makeQuery(filters[fieldname])})`)
20933
21076
  .join(' AND ');
20934
21077
  if (filters['gn-ui-crossFieldFilter']) {
20935
21078
  queryString = `${queryString} AND (${filters['gn-ui-crossFieldFilter']})`;
@@ -21227,6 +21370,12 @@ class ElasticsearchService {
21227
21370
  order: {
21228
21371
  [`_${aggregation.sort[1]}`]: aggregation.sort[0],
21229
21372
  },
21373
+ ...(aggregation.includeValues && {
21374
+ include: aggregation.includeValues,
21375
+ }),
21376
+ ...(aggregation.excludeValues && {
21377
+ exclude: aggregation.excludeValues,
21378
+ }),
21230
21379
  },
21231
21380
  };
21232
21381
  case 'histogram':
@@ -21328,10 +21477,21 @@ class Gn4Repository {
21328
21477
  this.platformService = inject(PlatformServiceInterface);
21329
21478
  this.gn4LanguagesApi = inject(LanguagesApiService);
21330
21479
  this.settingsService = inject(Gn4SettingsService);
21480
+ this.gn4TagsApi = inject(TagsApiService);
21331
21481
  this.disableDraft = inject(DISABLE_DRAFT, { optional: true }) ?? false;
21332
21482
  this.defaultConverter = inject(DEFAULT_RECORD_CONVERTER);
21333
21483
  this._draftsChanged = new Subject();
21334
21484
  this.draftsChanged$ = this._draftsChanged.asObservable();
21485
+ /*
21486
+ * FLAGS
21487
+ * Note: in GN4 API, categories are named "tags"
21488
+ */
21489
+ this.categoriesIdentifierForFlags = this.gn4TagsApi.getTags().pipe(map$1((categories) => categories.reduce((acc, category) => {
21490
+ if (category.name.startsWith('geonetwork-ui-flag:')) {
21491
+ acc[category.name.replace(/^geonetwork-ui-flag:/, '')] = category.id;
21492
+ }
21493
+ return acc;
21494
+ }, {})), shareReplay$1(1));
21335
21495
  }
21336
21496
  search({ filters, fields, offset, limit, sort, filterIds, filterGeometry, }) {
21337
21497
  return this.gn4SearchApi
@@ -21361,42 +21521,16 @@ class Gn4Repository {
21361
21521
  ? this.gn4Mapper.readRecords(records)
21362
21522
  : of(null)));
21363
21523
  }
21364
- mapEmbeddedFeatureCatalog(featureTypes) {
21365
- return {
21366
- featureTypes: featureTypes.map((featureType) => ({
21367
- name: featureType.typeName || '',
21368
- definition: featureType.definition || '',
21369
- attributes: Array.isArray(featureType.attributeTable)
21370
- ? featureType.attributeTable.map((attr) => {
21371
- const values = attr.values
21372
- ?.filter((v) => v.code || v.label)
21373
- .map((v) => ({
21374
- code: v.code,
21375
- label: v.label,
21376
- }));
21377
- return {
21378
- name: attr.name,
21379
- code: attr.code,
21380
- definition: attr.definition,
21381
- type: attr.type,
21382
- ...(values?.length > 0 ? { values } : {}),
21383
- };
21384
- })
21385
- : [],
21386
- })),
21387
- };
21388
- }
21389
- getFeatureCatalog(record, visited = new Set() // prevent looping
21524
+ queryLinkedFeatureCatalog(record, visited = new Set() // prevent looping
21390
21525
  ) {
21391
- if (record.extras?.['featureTypes'] &&
21392
- Array.isArray(record.extras['featureTypes']) &&
21393
- record.extras['featureTypes'].length > 0) {
21394
- return of(this.mapEmbeddedFeatureCatalog(record.extras['featureTypes']));
21526
+ if ('featureTypeDescriptions' in record &&
21527
+ record.featureTypeDescriptions?.length > 0) {
21528
+ return of({ featureTypes: record.featureTypeDescriptions });
21395
21529
  }
21396
21530
  const featureCatalogIdentifier = record.extras['featureCatalogIdentifier'];
21397
21531
  if (featureCatalogIdentifier && !visited.has(featureCatalogIdentifier)) {
21398
21532
  visited.add(featureCatalogIdentifier);
21399
- return this.getRecord(featureCatalogIdentifier).pipe(switchMap((record) => record ? this.getFeatureCatalog(record, visited) : of(null)));
21533
+ return this.getRecord(featureCatalogIdentifier).pipe(switchMap((record) => record ? this.queryLinkedFeatureCatalog(record, visited) : of(null)));
21400
21534
  }
21401
21535
  return of(null);
21402
21536
  }
@@ -21659,6 +21793,32 @@ class Gn4Repository {
21659
21793
  removeRecordFromLocalStorage(recordId) {
21660
21794
  window.localStorage.removeItem(this.getLocalStorageKeyForRecord(recordId));
21661
21795
  }
21796
+ getCategoryIdForFlag(flagName) {
21797
+ return this.categoriesIdentifierForFlags.pipe(map$1((categories) => {
21798
+ const categoryId = categories[flagName];
21799
+ if (categoryId === undefined) {
21800
+ console.warn(`The record flag ${flagName} is not created on GeoNetwork backend; please create a category with the name geonetwork-ui-flag:${flagName} for this to work.`);
21801
+ return null;
21802
+ }
21803
+ return categoryId;
21804
+ }));
21805
+ }
21806
+ setRecordFlag(uniqueIdentifier, flagName, value) {
21807
+ return this.getCategoryIdForFlag(flagName).pipe(switchMap((categoryId) => {
21808
+ if (categoryId === null)
21809
+ return of();
21810
+ return value
21811
+ ? this.gn4RecordsApi.tagRecord(uniqueIdentifier, [categoryId], false)
21812
+ : this.gn4RecordsApi.deleteTags(uniqueIdentifier, [categoryId]);
21813
+ }));
21814
+ }
21815
+ getRecordFlag(uniqueIdentifier, flagName) {
21816
+ return this.gn4RecordsApi.getRecordTags(uniqueIdentifier).pipe(withLatestFrom(this.getCategoryIdForFlag(flagName)), map$1(([tags, categoryId]) => {
21817
+ if (categoryId === null)
21818
+ return false;
21819
+ return Array.from(tags).some((tag) => tag.id === categoryId);
21820
+ }));
21821
+ }
21662
21822
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: Gn4Repository, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
21663
21823
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: Gn4Repository }); }
21664
21824
  }
@@ -22274,6 +22434,9 @@ class Gn4PlatformService {
22274
22434
  this.me$ = this.disableAuth
22275
22435
  ? of(null)
22276
22436
  : of(true).pipe(switchMap(() => this.meApi.getMe()), switchMap((apiUser) => this.mapper.userFromMeApi(apiUser)), shareReplay$1({ bufferSize: 1, refCount: true }));
22437
+ this.isAdmin$ = this.disableAuth
22438
+ ? of(false)
22439
+ : of(true).pipe(switchMap(() => this.meApi.getMe()), map$1((apiUser) => !!apiUser?.admin), shareReplay$1({ bufferSize: 1, refCount: true }));
22277
22440
  /**
22278
22441
  * A map of already loaded thesauri (groups of keywords); the key is a URI
22279
22442
  * @private
@@ -22309,6 +22472,9 @@ class Gn4PlatformService {
22309
22472
  isAnonymous() {
22310
22473
  return this.isUserAnonymous$;
22311
22474
  }
22475
+ isAdministrator() {
22476
+ return this.isAdmin$;
22477
+ }
22312
22478
  getOrganizations() {
22313
22479
  return undefined;
22314
22480
  }
@@ -23069,1117 +23235,409 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
23069
23235
  }]
23070
23236
  }] });
23071
23237
 
23072
- const flatten = (base, obj, keepLevel = false) => Object.keys(obj).reduce((prev, curr) => {
23073
- const path = base ? `${base}.${curr}` : curr;
23074
- const val = obj[curr];
23075
- if (keepLevel) {
23076
- return { ...prev, [path]: flatten('', val) };
23238
+ class AnchorLinkDirective {
23239
+ constructor() {
23240
+ this.changeDetector = inject(ChangeDetectorRef);
23241
+ this.disabled = false;
23242
+ this.observer = new MutationObserver(() => {
23243
+ this.refreshDisabledState();
23244
+ });
23245
+ this.inView = false;
23246
+ this.initialized = false;
23077
23247
  }
23078
- else if (typeof val === 'object' && !Array.isArray(val)) {
23079
- return {
23080
- ...prev,
23081
- ...flatten(path, val),
23082
- };
23248
+ get elementClass() {
23249
+ if (this.disabled) {
23250
+ return this.disabledClass;
23251
+ }
23252
+ if (this.inView) {
23253
+ return `${this.inViewClass} ${this.enabledClass}`;
23254
+ }
23255
+ else {
23256
+ return `${this.outOfViewClass} ${this.enabledClass}`;
23257
+ }
23083
23258
  }
23084
- else {
23085
- return { ...prev, [path]: val };
23259
+ ngOnInit() {
23260
+ this.observer.observe(document.body, {
23261
+ childList: true,
23262
+ subtree: true,
23263
+ });
23264
+ this.refreshDisabledState();
23086
23265
  }
23087
- }, {});
23088
- const checkKeys = (input, mandatory, optional) => {
23089
- const keys = Object.keys(input);
23090
- const missing = mandatory.filter((key) => keys.indexOf(key) === -1);
23091
- const unrecognized = keys.filter((key) => mandatory.indexOf(key) === -1 && optional.indexOf(key) === -1);
23092
- return {
23093
- missing,
23094
- unrecognized,
23095
- };
23096
- };
23097
- /**
23098
- * Only keeps recognized keys, flatten nested values (to allow having "." in keys),
23099
- * pushes warnings and errors to the given arrays; returns null in case of error
23100
- */
23101
- function parseConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
23102
- if (typeof fullConfigObj[sectionName] !== 'object') {
23103
- if (mandatoryKeys.length === 0)
23104
- return null;
23105
- outErrors.push(`The [${sectionName}] mandatory section is missing.`);
23106
- return null;
23266
+ ngAfterViewChecked() {
23267
+ if (!this.initialized && !this.disabled) {
23268
+ const target = document.getElementById(this.targetId);
23269
+ if (target) {
23270
+ this.initializeIntersectionObserver(target);
23271
+ this.initialized = true;
23272
+ }
23273
+ }
23107
23274
  }
23108
- const sectionConf = fullConfigObj[sectionName];
23109
- const keysCheck = checkKeys(sectionConf, mandatoryKeys, optionalKeys);
23110
- if (keysCheck.missing.length) {
23111
- // note: this is not thrown to allow merging several Errors down the line
23112
- outErrors.push(`In the [${sectionName}] section: ${keysCheck.missing.join(', ')}`);
23113
- return null;
23275
+ initializeIntersectionObserver(target) {
23276
+ this.intersectionObserver = new IntersectionObserver((entries) => {
23277
+ entries.forEach((entry) => {
23278
+ this.inView = entry.isIntersecting;
23279
+ this.changeDetector.detectChanges();
23280
+ });
23281
+ }, {
23282
+ root: null,
23283
+ rootMargin: '-30% 0% -60% 0%',
23284
+ });
23285
+ this.intersectionObserver.observe(target);
23114
23286
  }
23115
- else if (keysCheck.unrecognized.length) {
23116
- outWarnings.push(`In the [${sectionName}] section: ${keysCheck.unrecognized.join(', ')}`);
23117
- keysCheck.unrecognized.forEach((key) => delete sectionConf[key]);
23287
+ ngOnDestroy() {
23288
+ this.observer.disconnect();
23289
+ if (this.intersectionObserver) {
23290
+ this.intersectionObserver.disconnect();
23291
+ }
23118
23292
  }
23119
- return sectionConf;
23293
+ refreshDisabledState() {
23294
+ const targetNotPresent = !document.getElementById(this.targetId);
23295
+ if (targetNotPresent !== this.disabled) {
23296
+ this.disabled = targetNotPresent;
23297
+ this.changeDetector.detectChanges();
23298
+ }
23299
+ }
23300
+ scrollToTarget() {
23301
+ const target = document.getElementById(this.targetId);
23302
+ if (!target)
23303
+ return;
23304
+ target.scrollIntoView({
23305
+ behavior: 'smooth',
23306
+ block: 'start',
23307
+ });
23308
+ }
23309
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
23310
+ 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 }); }
23120
23311
  }
23121
- /**
23122
- * Same as parseConfigSection but keeps all keys, recognized or not
23123
- * Also the first level is the language code (e.g. 'en')
23124
- * This is optional
23125
- */
23126
- function parseTranslationsConfigSection(fullConfigObj, sectionName) {
23127
- if (typeof fullConfigObj[sectionName] !== 'object') {
23128
- return {};
23312
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, decorators: [{
23313
+ type: Directive,
23314
+ args: [{
23315
+ selector: '[gnUiAnchorLink]',
23316
+ standalone: true,
23317
+ }]
23318
+ }], propDecorators: { targetId: [{
23319
+ type: Input,
23320
+ args: ['gnUiAnchorLink']
23321
+ }], disabledClass: [{
23322
+ type: Input,
23323
+ args: ['gnUiAnchorLinkDisabledClass']
23324
+ }], enabledClass: [{
23325
+ type: Input,
23326
+ args: ['gnUiAnchorLinkEnabledClass']
23327
+ }], inViewClass: [{
23328
+ type: Input,
23329
+ args: ['gnUiAnchorLinkInViewClass']
23330
+ }], outOfViewClass: [{
23331
+ type: Input,
23332
+ args: ['gnUiAnchorLinkOutOfViewClass']
23333
+ }], elementClass: [{
23334
+ type: HostBinding,
23335
+ args: ['class']
23336
+ }], scrollToTarget: [{
23337
+ type: HostListener,
23338
+ args: ['click']
23339
+ }] } });
23340
+
23341
+ class PaginationDotsComponent {
23342
+ constructor() {
23343
+ this.containerClass = '';
23129
23344
  }
23130
- return flatten('', fullConfigObj[sectionName], true);
23345
+ // 1-based
23346
+ get steps() {
23347
+ return Array.from({ length: this.listComponent.pagesCount }, (_, i) => i + 1);
23348
+ }
23349
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23350
+ 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: [
23351
+ provideIcons({
23352
+ iconoirNavArrowRight,
23353
+ iconoirNavArrowLeft,
23354
+ }),
23355
+ ] }); }
23131
23356
  }
23132
- /**
23133
- * Same as parseConfigSection but handles an array of configs; this is
23134
- * considered optional; returns null in case of error in at least one of
23135
- * the sections
23136
- */
23137
- function parseMultiConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
23138
- const sections = fullConfigObj[sectionName];
23139
- if (!sections) {
23140
- return [];
23357
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, decorators: [{
23358
+ type: Component,
23359
+ args: [{ selector: 'gn-ui-pagination-dots', standalone: true, imports: [CommonModule], viewProviders: [
23360
+ provideIcons({
23361
+ iconoirNavArrowRight,
23362
+ iconoirNavArrowLeft,
23363
+ }),
23364
+ ], 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"] }]
23365
+ }], propDecorators: { listComponent: [{
23366
+ type: Input
23367
+ }], containerClass: [{
23368
+ type: Input
23369
+ }] } });
23370
+
23371
+ class CarouselComponent {
23372
+ constructor() {
23373
+ this.changeDetector = inject(ChangeDetectorRef);
23374
+ this.containerClass = '';
23375
+ this.stepsContainerClass = 'w-full bottom-0 top-auto';
23376
+ this.currentStepChange = new EventEmitter();
23377
+ this.steps = [];
23378
+ this.currentStep = 0;
23379
+ this.refreshSteps = () => {
23380
+ this.steps = this.emblaApi.scrollSnapList();
23381
+ this.currentStep = this.emblaApi.selectedScrollSnap();
23382
+ this.currentStepChange.emit(this.currentStep);
23383
+ this.changeDetector.detectChanges();
23384
+ };
23141
23385
  }
23142
- if (!Array.isArray(sections)) {
23143
- outErrors.push(`Expected [[${sectionName}]] to be an array of sections.`);
23144
- return null;
23386
+ // Paginable API
23387
+ get isFirstPage() {
23388
+ return this.currentStep === 0;
23145
23389
  }
23146
- const result = sections.map((section) => parseConfigSection({ [sectionName]: section }, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors));
23147
- if (result.some((r) => r === null)) {
23148
- return null;
23390
+ get isLastPage() {
23391
+ return this.currentStep === this.steps.length - 1;
23149
23392
  }
23150
- return result;
23151
- }
23152
- function checkMetadataLanguage(parsedConfigSection, outWarnings) {
23153
- const lang2 = toLang2(parsedConfigSection.metadata_language.toLowerCase());
23154
- if (lang2?.length !== 2) {
23155
- outWarnings.push(`In the [global] section: metadata_language = "${parsedConfigSection.metadata_language}" is not a recognized ISO 639 language code`);
23393
+ get currentPage() {
23394
+ return this.currentStep + 1; // this is 1-based
23156
23395
  }
23157
- return parsedConfigSection;
23158
- }
23159
- function checkNewRecordDefaultLanguage(parsedConfigSection, outWarnings) {
23160
- const lang2 = toLang2(parsedConfigSection.new_record_default_language.toLowerCase());
23161
- if (!(lang2 in LANG_2_TO_3_MAPPER)) {
23162
- outWarnings.push(`In the [editing] section: new_record_default_language = "${parsedConfigSection.new_record_default_language}" is not a recognized ISO 639 language code`);
23163
- return {
23164
- ...parsedConfigSection,
23165
- new_record_default_language: undefined,
23166
- };
23396
+ get pagesCount() {
23397
+ return this.steps.length;
23167
23398
  }
23168
- return {
23169
- ...parsedConfigSection,
23170
- new_record_default_language: lang2,
23171
- };
23172
- }
23173
- function checkNewRecordStandard(parsedConfigSection, outWarnings) {
23174
- const standard = parsedConfigSection.new_record_standard;
23175
- const normalizedStandard = typeof standard === 'string' ? standard.trim().toLowerCase() : null;
23176
- if (normalizedStandard === 'iso19139' ||
23177
- normalizedStandard === 'iso19115-3') {
23178
- return {
23179
- ...parsedConfigSection,
23180
- new_record_standard: normalizedStandard,
23181
- };
23399
+ goToPage(stepIndex) {
23400
+ this.emblaApi.scrollTo(stepIndex - 1); // this is 0-based
23182
23401
  }
23183
- outWarnings.push(`In the [editing] section: new_record_standard = "${standard}" is not a supported metadata standard`);
23184
- return {
23185
- ...parsedConfigSection,
23186
- new_record_standard: undefined,
23187
- };
23402
+ goToPrevPage() {
23403
+ if (this.isFirstPage)
23404
+ return;
23405
+ this.emblaApi.scrollPrev();
23406
+ }
23407
+ goToNextPage() {
23408
+ if (this.isLastPage)
23409
+ return;
23410
+ this.emblaApi.scrollNext();
23411
+ }
23412
+ ngAfterViewInit() {
23413
+ this.emblaApi = EmblaCarousel(this.carouselOverflowContainer.nativeElement, {
23414
+ duration: 15,
23415
+ });
23416
+ this.emblaApi
23417
+ .on('init', this.refreshSteps)
23418
+ .on('reInit', this.refreshSteps)
23419
+ .on('select', this.refreshSteps);
23420
+ }
23421
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23422
+ 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 }); }
23188
23423
  }
23424
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, decorators: [{
23425
+ type: Component,
23426
+ 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"] }]
23427
+ }], propDecorators: { carouselOverflowContainer: [{
23428
+ type: ViewChild,
23429
+ args: ['carouselOverflowContainer']
23430
+ }], containerClass: [{
23431
+ type: Input
23432
+ }], stepsContainerClass: [{
23433
+ type: Input
23434
+ }], currentStepChange: [{
23435
+ type: Output
23436
+ }] } });
23189
23437
 
23190
- /**
23191
- * This loader extends the default one based on JSON files but also loads custom translations
23192
- * defined in the app configuration
23193
- * Implements a fallback on default lang if translated labels are empty
23194
- */
23195
- class FileWithOverridesTranslateLoader extends FileTranslateLoader {
23196
- getTranslation(lang) {
23197
- const baseLang = lang.substring(0, 2); // removing the right part of e.g. en_EN
23198
- return super.getTranslation(baseLang).pipe(map$1((translations) => ({
23199
- ...translations,
23200
- ...getCustomTranslations(baseLang),
23201
- })));
23438
+ class ProgressBarComponent {
23439
+ constructor() {
23440
+ this.value = 0;
23441
+ this.type = 'default';
23442
+ }
23443
+ get progress() {
23444
+ return this.value > 0 ? (this.value < 100 ? this.value : 100) : 0;
23445
+ }
23446
+ get color() {
23447
+ switch (this.type) {
23448
+ case 'default':
23449
+ return {
23450
+ outerBar: 'bg-gray-200',
23451
+ innerBar: 'bg-gray-100',
23452
+ text: 'text-gray-900',
23453
+ };
23454
+ case 'primary':
23455
+ return {
23456
+ outerBar: 'bg-primary',
23457
+ innerBar: 'bg-primary-lighter',
23458
+ text: 'text-white',
23459
+ };
23460
+ case 'secondary':
23461
+ return {
23462
+ outerBar: 'bg-secondary',
23463
+ innerBar: 'bg-secondary-lighter',
23464
+ text: 'text-white',
23465
+ };
23466
+ case 'light':
23467
+ return {
23468
+ outerBar: 'bg-primary-white',
23469
+ innerBar: 'bg-primary',
23470
+ text: 'text-main',
23471
+ };
23472
+ }
23202
23473
  }
23474
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23475
+ 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"] }); }
23203
23476
  }
23477
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, decorators: [{
23478
+ type: Component,
23479
+ 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"] }]
23480
+ }], propDecorators: { value: [{
23481
+ type: Input
23482
+ }], type: [{
23483
+ type: Input
23484
+ }] } });
23204
23485
 
23205
- const MISSING_CONFIG_ERROR = `Application configuration was not initialized correctly.
23206
- This error might show up in case of an invalid/malformed configuration file.
23207
-
23208
- Note: make sure that you have called \`loadAppConfig\` from '../../../../../libs/util/app-config/src' before starting the Angular application.`;
23209
- let globalConfig = null;
23210
- function getGlobalConfig() {
23211
- if (globalConfig === null)
23212
- throw new Error(MISSING_CONFIG_ERROR);
23213
- return globalConfig;
23214
- }
23215
- let themeConfig = null;
23216
- function getThemeConfig() {
23217
- if (themeConfig === null)
23218
- throw new Error(MISSING_CONFIG_ERROR);
23219
- return themeConfig;
23220
- }
23221
- let mapConfig = null;
23222
- function getOptionalMapConfig() {
23223
- return mapConfig;
23224
- }
23225
- let searchConfig = null;
23226
- function getOptionalSearchConfig() {
23227
- return searchConfig;
23228
- }
23229
- let editorConfig = null;
23230
- function getOptionalEditorConfig() {
23231
- return editorConfig;
23232
- }
23233
- let metadataQualityConfig = null;
23234
- function getMetadataQualityConfig() {
23235
- return (metadataQualityConfig ||
23236
- {
23237
- ENABLED: false,
23238
- });
23239
- }
23240
- let customTranslations = null;
23241
- function getCustomTranslations(langCode) {
23242
- if (customTranslations === null)
23243
- throw new Error(MISSING_CONFIG_ERROR);
23244
- return langCode in customTranslations ? customTranslations[langCode] : {};
23245
- }
23246
- let appConfigLoaded = false;
23247
- function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
23248
- console.log(`[geonetwork-ui] Loading application configuration from ${configUrl}`);
23249
- return fetch(configUrl)
23250
- .then((resp) => {
23251
- if (!resp.ok)
23252
- throw new Error('Configuration file could not be loaded');
23253
- return resp.text();
23254
- })
23255
- .then((conf) => {
23256
- let parsed;
23257
- try {
23258
- parsed = TOML.parse(conf, { joiner: '\n', bigint: false });
23486
+ class PopoverComponent {
23487
+ constructor() {
23488
+ this.viewContainerRef = inject(ViewContainerRef);
23489
+ this.renderer = inject(Renderer2);
23490
+ }
23491
+ getContent() {
23492
+ if (this.content instanceof TemplateRef) {
23493
+ if (this.view) {
23494
+ this.view.destroy();
23495
+ }
23496
+ this.view = this.viewContainerRef.createEmbeddedView(this.content);
23497
+ this.view.detectChanges();
23498
+ const wrapper = this.renderer.createElement('div'); // Create a wrapper div
23499
+ this.view.rootNodes.forEach((node) => {
23500
+ this.renderer.appendChild(wrapper, node); // Append each root node to the wrapper
23501
+ });
23502
+ return wrapper;
23259
23503
  }
23260
- catch (e) {
23261
- throw new Error(`An error occurred when parsing the configuration file: ${e.message}`);
23504
+ return this.content;
23505
+ }
23506
+ ngAfterViewInit() {
23507
+ this.tippyInstance = tippy(this.popoverContent.nativeElement, {
23508
+ content: this.getContent(),
23509
+ allowHTML: true,
23510
+ theme: this.theme,
23511
+ });
23512
+ }
23513
+ ngOnChanges(changes) {
23514
+ if (changes['theme']) {
23515
+ this.theme = changes['theme'].currentValue;
23516
+ if (this.tippyInstance) {
23517
+ this.tippyInstance.setProps({ theme: this.theme });
23518
+ }
23262
23519
  }
23263
- const errors = [];
23264
- const warnings = [];
23265
- let parsedGlobalSection = parseConfigSection(parsed, 'global', ['geonetwork4_api_url'], [
23266
- 'datahub_url',
23267
- 'edit_url_template',
23268
- 'proxy_path',
23269
- 'metadata_language',
23270
- 'login_url',
23271
- 'logout_url',
23272
- 'settings_url',
23273
- 'web_component_embedder_url',
23274
- 'languages',
23275
- 'contact_email',
23276
- 'reuse_form_url',
23277
- ], warnings, errors);
23278
- if (parsedGlobalSection?.metadata_language) {
23279
- parsedGlobalSection = checkMetadataLanguage(parsedGlobalSection, warnings);
23520
+ if (changes['content']) {
23521
+ this.content = changes['content'].currentValue;
23522
+ if (this.tippyInstance) {
23523
+ this.tippyInstance.setContent(this.getContent());
23524
+ }
23280
23525
  }
23281
- globalConfig =
23282
- parsedGlobalSection === null
23283
- ? null
23284
- : {
23285
- GN4_API_URL: parsedGlobalSection.geonetwork4_api_url,
23286
- DATAHUB_URL: parsedGlobalSection.datahub_url,
23287
- EDIT_URL_TEMPLATE: parsedGlobalSection.edit_url_template,
23288
- PROXY_PATH: parsedGlobalSection.proxy_path,
23289
- METADATA_LANGUAGE: parsedGlobalSection.metadata_language
23290
- ? parsedGlobalSection.metadata_language.toLowerCase()
23291
- : undefined,
23292
- LOGIN_URL: parsedGlobalSection.login_url,
23293
- LOGOUT_URL: parsedGlobalSection.logout_url,
23294
- SETTINGS_URL: parsedGlobalSection.settings_url,
23295
- WEB_COMPONENT_EMBEDDER_URL: parsedGlobalSection.web_component_embedder_url,
23296
- LANGUAGES: parsedGlobalSection.languages,
23297
- CONTACT_EMAIL: parsedGlobalSection.contact_email,
23298
- REUSE_FORM_URL: parsedGlobalSection.reuse_form_url,
23299
- };
23300
- const parsedLayersSections = parseMultiConfigSection(parsed, 'map_layer', ['type'], ['name', 'url', 'data', 'styleUrl', 'accessToken'], warnings, errors);
23301
- const parsedMapSection = parseConfigSection(parsed, 'map', [], [
23302
- 'max_zoom',
23303
- 'do_not_tile_wms',
23304
- 'max_extent',
23305
- 'max_feature_count',
23306
- 'baselayer',
23307
- 'do_not_use_default_basemap',
23308
- 'external_viewer_url_template',
23309
- 'external_viewer_open_new_tab',
23310
- ], warnings, errors);
23311
- mapConfig =
23312
- parsedMapSection === null || parsedLayersSections === null
23313
- ? null
23314
- : {
23315
- MAX_ZOOM: parsedMapSection.max_zoom,
23316
- DO_NOT_TILE_WMS: parsedMapSection.do_not_tile_wms,
23317
- MAX_EXTENT: parsedMapSection.max_extent,
23318
- MAX_FEATURE_COUNT: parsedMapSection.max_feature_count,
23319
- EXTERNAL_VIEWER_URL_TEMPLATE: parsedMapSection.external_viewer_url_template,
23320
- EXTERNAL_VIEWER_OPEN_NEW_TAB: parsedMapSection.external_viewer_open_new_tab,
23321
- DO_NOT_USE_DEFAULT_BASEMAP: !!parsedMapSection.do_not_use_default_basemap,
23322
- MAP_LAYERS: parsedLayersSections.map((map_layer) => ({
23323
- TYPE: map_layer.type,
23324
- URL: map_layer.url,
23325
- NAME: map_layer.name,
23326
- DATA: map_layer.data,
23327
- STYLE_URL: map_layer.styleUrl,
23328
- ACCESS_TOKEN: map_layer.accessToken,
23329
- })),
23330
- };
23331
- const parsedThemeSection = parseConfigSection(parsed, 'theme', ['primary_color', 'secondary_color', 'main_color', 'background_color'], [
23332
- 'header_foreground_color',
23333
- 'main_font',
23334
- 'title_font',
23335
- 'fonts_stylesheet_url',
23336
- 'thumbnail_placeholder',
23337
- 'header_background',
23338
- 'favicon',
23339
- ], warnings, errors);
23340
- themeConfig =
23341
- parsedThemeSection === null
23342
- ? null
23343
- : {
23344
- PRIMARY_COLOR: parsedThemeSection.primary_color,
23345
- SECONDARY_COLOR: parsedThemeSection.secondary_color,
23346
- MAIN_COLOR: parsedThemeSection.main_color,
23347
- BACKGROUND_COLOR: parsedThemeSection.background_color,
23348
- HEADER_FOREGROUND_COLOR: parsedThemeSection.header_foreground_color,
23349
- THUMBNAIL_PLACEHOLDER: parsedThemeSection.thumbnail_placeholder,
23350
- HEADER_BACKGROUND: parsedThemeSection.header_background,
23351
- TITLE_FONT: parsedThemeSection.title_font,
23352
- MAIN_FONT: parsedThemeSection.main_font,
23353
- FONTS_STYLESHEET_URL: parsedThemeSection.fonts_stylesheet_url,
23354
- FAVICON: parsedThemeSection.favicon,
23355
- };
23356
- const parsedSearchSection = parseConfigSection(parsed, 'search', [], [
23357
- 'record_kind_quick_filter',
23358
- 'filter_geometry_data',
23359
- 'filter_geometry_url',
23360
- 'do_not_use_default_search_preset',
23361
- 'search_preset',
23362
- 'advanced_filters',
23363
- 'limit',
23364
- 'spatial_extent_max_file_size',
23365
- ], warnings, errors);
23366
- const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
23367
- searchConfig =
23368
- parsedSearchSection === null
23369
- ? null
23370
- : {
23371
- RECORD_KIND_QUICK_FILTER: parsedSearchSection.record_kind_quick_filter,
23372
- FILTER_GEOMETRY_DATA: parsedSearchSection.filter_geometry_data,
23373
- FILTER_GEOMETRY_URL: parsedSearchSection.filter_geometry_url,
23374
- DO_NOT_USE_DEFAULT_SEARCH_PRESET: !!parsedSearchSection.do_not_use_default_search_preset,
23375
- SEARCH_PRESET: parsedSearchParams.map((param) => ({
23376
- sort: param.sort,
23377
- name: param.name,
23378
- filters: param.filters,
23379
- })),
23380
- ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
23381
- LIMIT: parsedSearchSection.limit,
23382
- SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
23383
- };
23384
- const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
23385
- metadataQualityConfig =
23386
- parsedMetadataQualitySection === null
23387
- ? null
23388
- : {
23389
- ENABLED: parsedMetadataQualitySection.enabled,
23390
- SORTABLE: parsedMetadataQualitySection.sortable,
23391
- };
23392
- let parsedEditingSection = parseConfigSection(parsed, 'editing', [], ['new_record_default_language', 'new_record_standard'], warnings, errors);
23393
- if (parsedEditingSection !== null &&
23394
- parsedEditingSection.new_record_default_language !== undefined) {
23395
- parsedEditingSection = checkNewRecordDefaultLanguage(parsedEditingSection, warnings);
23396
- }
23397
- if (parsedEditingSection !== null &&
23398
- parsedEditingSection.new_record_standard !== undefined) {
23399
- parsedEditingSection = checkNewRecordStandard(parsedEditingSection, warnings);
23400
- }
23401
- editorConfig =
23402
- parsedEditingSection === null
23403
- ? null
23404
- : {
23405
- NEW_RECORD_DEFAULT_LANGUAGE: parsedEditingSection.new_record_default_language,
23406
- NEW_RECORD_STANDARD: parsedEditingSection.new_record_standard,
23407
- };
23408
- customTranslations = parseTranslationsConfigSection(parsed, 'translations');
23409
- if (errors.length) {
23410
- throw new Error(`One or more mandatory settings were missing from the configuration file.
23411
- ${errors.join('\n')}`);
23526
+ }
23527
+ ngOnDestroy() {
23528
+ if (this.tippyInstance) {
23529
+ this.tippyInstance.destroy();
23412
23530
  }
23413
- else if (warnings.length) {
23414
- console.warn(`One or more unexpected settings were encountered in the configuration file.
23415
- ${warnings.join('\n')}`);
23531
+ if (this.view) {
23532
+ this.view.destroy();
23416
23533
  }
23417
- appConfigLoaded = true;
23418
- });
23419
- }
23420
- function isConfigLoaded() {
23421
- return appConfigLoaded;
23422
- }
23423
- function _reset() {
23424
- globalConfig = null;
23425
- themeConfig = null;
23426
- editorConfig = null;
23427
- customTranslations = null;
23534
+ }
23535
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23536
+ 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: [""] }); }
23428
23537
  }
23429
- const TRANSLATE_WITH_OVERRIDES_CONFIG = {
23430
- compiler: {
23431
- provide: TranslateCompiler,
23432
- useClass: TranslateMessageFormatCompiler,
23433
- },
23434
- loader: [
23435
- {
23436
- provide: TRANSLATE_HTTP_LOADER_CONFIG,
23437
- useValue: {
23438
- prefix: './assets/i18n/',
23439
- suffix: '.json',
23440
- },
23441
- },
23442
- {
23443
- provide: TranslateLoader,
23444
- useClass: FileWithOverridesTranslateLoader,
23445
- deps: [HttpClient, TRANSLATE_HTTP_LOADER_CONFIG],
23446
- },
23447
- ],
23448
- };
23449
-
23450
- const okAppConfigFixture = () => `
23451
- [global]
23452
- geonetwork4_api_url = "/geonetwork/srv/api"
23453
- proxy_path = "/proxy/?url="
23454
- metadata_language = "fre"
23455
- login_url = "/cas/login?service="
23456
- logout_url = "/geonetwork/signout"
23457
- settings_url = "/geonetwork/settings"
23458
- web_component_embedder_url = "/datahub/wc-embedder.html"
23459
-
23460
- [map]
23461
- max_zoom = 10
23462
- max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
23463
- do_not_use_default_basemap = false
23464
- external_viewer_url_template = 'https://example.com/myviewer?'
23465
- external_viewer_open_new_tab = true
23466
- [[map_layer]]
23467
- type = "wms"
23468
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23469
- name = "masque_hdf_ign_carto_latin1"
23470
- [[map_layer]]
23471
- type = "wfs"
23472
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23473
- name = "masque_hdf_ign_carto_latin1"
23474
-
23475
- [theme]
23476
- primary_color = "#093564"
23477
- secondary_color = "#c2e9dc"
23478
- main_color = "#212029" # All-purpose text color
23479
- background_color = "#fdfbff"
23480
- thumbnail_placeholder = 'assets/img/placeholder.svg'
23481
- header_background = 'teal'
23482
- header_foreground_color = "#872e2e"
23483
- main_font = 'sans-serif'
23484
- title_font = 'serif'
23485
- fonts_stylesheet_url = "https://fonts.googleapis.com/css2?family=Open+Sans"
23486
-
23487
- [search]
23488
- record_kind_quick_filter = false
23489
- filter_geometry_url = 'https://my.domain.org/geom.json'
23490
- do_not_use_default_search_preset = false
23491
- advanced_filters = ['publicationYear', 'documentStandard', 'inspireKeyword', 'topic', 'license']
23492
-
23493
- [[search_preset]]
23494
- sort = "-createDate"
23495
- name = 'filterByOrgs'
23496
- filters.q = 'Carto'
23497
- filters.organisation = ['Org1', 'Org2']
23498
- filters.format = ['ESRI Shapefile']
23499
- filters.topic = ['boundaries']
23500
- filters.publicationYear = ['2023', '2022']
23501
- filters.spatial = ['yes']
23502
-
23503
- [translations.en]
23504
- "my.first.key" = 'First label.'
23505
- "my.second.key" = """
23506
- Second label,
23507
- on two lines."""
23508
-
23509
- [translations.de]
23510
- my.first.key = 'Erste Etikett.'
23511
-
23512
- [translations.fr]
23513
- my.sample.text = "Un bon exemple de texte."
23514
- "my.quoted.text" = 'du texte entre guillements.'
23515
- `;
23516
- const appConfigWithTranslationFixture = () => okAppConfigFixture();
23517
- const minimalAppConfigFixture = () => `
23518
- [global]
23519
- geonetwork4_api_url = "/geonetwork/srv/api"
23520
- proxy_path = "/proxy/?url="
23538
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, decorators: [{
23539
+ type: Component,
23540
+ args: [{ selector: 'gn-ui-popover', standalone: true, imports: [], template: "<span #popoverContent>\n <ng-content></ng-content>\n</span>\n" }]
23541
+ }], propDecorators: { popoverContent: [{
23542
+ type: ViewChild,
23543
+ args: ['popoverContent', { static: false }]
23544
+ }], content: [{
23545
+ type: Input
23546
+ }], theme: [{
23547
+ type: Input
23548
+ }] } });
23521
23549
 
23522
- [theme]
23523
- primary_color = "#093564"
23524
- secondary_color = "#c2e9dc"
23525
- main_color = "#212029" # All-purpose text color
23526
- background_color = "#fdfbff"
23527
- `;
23528
- const mapConfigFixture = () => ({
23529
- MAX_ZOOM: 10,
23530
- MAX_EXTENT: [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855],
23531
- DO_NOT_USE_DEFAULT_BASEMAP: false,
23532
- DO_NOT_TILE_WMS: false,
23533
- 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}"}]}]',
23534
- EXTERNAL_VIEWER_OPEN_NEW_TAB: true,
23535
- MAP_LAYERS: [
23536
- {
23537
- TYPE: 'xyz',
23538
- URL: 'https://some-basemap-server',
23539
- },
23540
- {
23541
- TYPE: 'wms',
23542
- URL: 'https://some-wms-server',
23543
- NAME: 'some_layername',
23544
- },
23545
- {
23546
- TYPE: 'wfs',
23547
- URL: 'https://some-wfs-server',
23548
- NAME: 'some_layername',
23549
- },
23550
- ],
23551
- });
23552
- const malformedConfigFixture = () => `
23553
- {
23554
- "I thought": "we were still doing json"
23550
+ class LoadingMaskComponent {
23551
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23552
+ 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 }); }
23555
23553
  }
23556
- `;
23557
- const missingMandatoryConfigFixture = () => `
23558
- [theme]
23559
- primary_color = "#093564"
23560
- secondary_color = "#c2e9dc"
23561
- background_color = "#fdfbff"
23562
- main_font = 'sans-serif'
23563
- `;
23564
- const wrongLanguageCodeConfigFixture = () => `
23565
- [global]
23566
- geonetwork4_api_url = "/geonetwork/srv/api"
23567
- proxy_path = "/proxy/?url="
23568
- metadata_language = "abc"
23569
-
23570
- [map]
23571
-
23572
- [theme]
23573
- primary_color = "#093564"
23574
- secondary_color = "#c2e9dc"
23575
- main_color = "#212029" # All-purpose text color
23576
- background_color = "#fdfbff"
23577
- `;
23578
- const unrecognizedKeysConfigFixture = () => `
23579
- [global]
23580
- geonetwork4_api_url = "/geonetwork/srv/api"
23581
- proxy_path = "/proxy/?url="
23582
- metadata_language = "fre"
23583
- another_path = '/whatever'
23584
-
23585
- [map]
23586
- max_zoom = 10
23587
- max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
23588
- do_not_use_default_basemap = false
23589
- external_viewer_url_template = 'https://example.com/myviewer?'
23590
- external_viewer_open_new_tab = true
23591
- another_zoom = 15
23592
- [[map_layer]]
23593
- type = "wms"
23594
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23595
- name = "masque_hdf_ign_carto_latin1"
23596
- [[map_layer]]
23597
- type = "wfs"
23598
- url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
23599
- name = "masque_hdf_ign_carto_latin1"
23600
- another_layer = "wrong layer definition"
23601
-
23602
- [theme]
23603
- primary_color = "#093564"
23604
- secondary_color = "#c2e9dc"
23605
- main_color = "#212029" # All-purpose text color
23606
- background_color = "#fdfbff"
23607
- thumbnail_placeholder = 'assets/img/placeholder.svg'
23608
- header_background = 'teal'
23609
- header_foreground_color = "#872e2e"
23610
- main_font = 'sans-serif'
23611
- title_font = 'serif'
23612
- another_color = 'red'
23613
- `;
23554
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, decorators: [{
23555
+ type: Component,
23556
+ 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"] }]
23557
+ }], propDecorators: { message: [{
23558
+ type: Input
23559
+ }] } });
23614
23560
 
23615
- function getMapContextLayerFromConfig(config) {
23616
- switch (config.TYPE) {
23617
- case 'wms':
23618
- return {
23619
- type: 'wms',
23620
- url: config.URL,
23621
- name: config.NAME,
23622
- };
23623
- case 'wfs':
23624
- return {
23625
- type: 'wfs',
23626
- url: config.URL,
23627
- featureType: config.NAME,
23628
- };
23629
- case 'xyz':
23630
- return {
23631
- type: config.TYPE,
23632
- url: config.URL,
23633
- };
23634
- case 'geojson':
23635
- return {
23636
- type: config.TYPE,
23637
- ...(config.DATA ? { data: config.DATA } : { url: config.URL }),
23638
- };
23639
- case 'maplibre-style':
23640
- return {
23641
- type: config.TYPE,
23642
- styleUrl: config.STYLE_URL,
23643
- accessToken: config.ACCESS_TOKEN,
23644
- };
23645
- }
23561
+ class ColorScaleComponent {
23562
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23563
+ 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: [""] }); }
23646
23564
  }
23565
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, decorators: [{
23566
+ type: Component,
23567
+ 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" }]
23568
+ }] });
23647
23569
 
23648
- class MapStyleService {
23570
+ class PopupAlertComponent {
23649
23571
  constructor() {
23650
- this.styles = {
23651
- default: this.createStyleFunction(this.createGeometryStyles({
23652
- color: isConfigLoaded() ? getThemeConfig().PRIMARY_COLOR : 'blue',
23653
- })),
23654
- defaultHL: this.createStyleFunction(this.createGeometryStyles({
23655
- color: isConfigLoaded() ? getThemeConfig().SECONDARY_COLOR : 'red',
23656
- isFocused: true,
23657
- })),
23658
- };
23572
+ this.changeDetector = inject(ChangeDetectorRef);
23573
+ this.type = 'info';
23574
+ this.position = 'top';
23575
+ this.expanded = false;
23576
+ this.timeout = null;
23659
23577
  }
23660
- createGeometryStyles(options) {
23661
- const { color, isFocused } = options;
23662
- const zIndex = isFocused ? 10 : undefined;
23663
- return {
23664
- polygon: new Style({
23665
- fill: new Fill({
23666
- color: this.computeTransparentFillColor(color),
23667
- }),
23668
- stroke: new Stroke({
23669
- color: 'white',
23670
- width: 2,
23671
- }),
23672
- zIndex,
23673
- }),
23674
- point: new Style({
23675
- image: new CircleStyle({
23676
- fill: new Fill({
23677
- color,
23678
- }),
23679
- stroke: new Stroke({
23680
- color: 'white',
23681
- width: isFocused ? 3 : 2,
23682
- }),
23683
- radius: isFocused ? 8 : 7,
23684
- }),
23685
- zIndex,
23686
- }),
23687
- line: [
23688
- new Style({
23689
- stroke: new Stroke({
23690
- color: 'white',
23691
- width: isFocused ? 8 : 6,
23692
- }),
23693
- zIndex,
23694
- }),
23695
- new Style({
23696
- stroke: new Stroke({
23697
- color,
23698
- width: isFocused ? 3 : 2,
23699
- }),
23700
- zIndex,
23701
- }),
23702
- ],
23703
- };
23578
+ get showDuration() {
23579
+ const chars = this.content.nativeElement.innerHTML.length;
23580
+ return Math.max(3000, chars * 20);
23704
23581
  }
23705
- createStyleFunction(styleByGeometryType) {
23706
- return (feature) => {
23707
- const geometryType = feature?.getGeometry()?.getType();
23708
- switch (geometryType) {
23709
- case 'LinearRing':
23710
- case 'LineString':
23711
- case 'MultiLineString':
23712
- return styleByGeometryType.line;
23713
- case 'Point':
23714
- case 'MultiPoint':
23715
- return styleByGeometryType.point;
23716
- case 'Circle':
23717
- case 'Polygon':
23718
- case 'MultiPolygon':
23719
- return styleByGeometryType.polygon;
23720
- default:
23721
- return styleByGeometryType.point;
23722
- }
23723
- };
23582
+ ngOnInit() {
23583
+ this.expandAndClose();
23584
+ }
23585
+ expand() {
23586
+ this.expanded = true;
23587
+ this.changeDetector.detectChanges();
23588
+ clearTimeout(this.timeout);
23724
23589
  }
23725
- computeTransparentFillColor(color, alpha = 0.25) {
23726
- return chroma(color).alpha(alpha).css();
23590
+ expandAndClose() {
23591
+ this.expanded = true;
23592
+ this.changeDetector.detectChanges();
23593
+ clearTimeout(this.timeout);
23594
+ this.timeout = setTimeout(() => {
23595
+ this.expanded = false;
23596
+ this.changeDetector.detectChanges();
23597
+ }, this.showDuration);
23727
23598
  }
23728
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MapStyleService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
23729
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MapStyleService, providedIn: 'root' }); }
23599
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopupAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23600
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: PopupAlertComponent, isStandalone: true, selector: "gn-ui-popup-alert", inputs: { icon: "icon", type: "type", position: "position" }, providers: [
23601
+ provideIcons({ matErrorOutlineOutline }),
23602
+ provideNgIconsConfig({
23603
+ size: '1.5em',
23604
+ }),
23605
+ ], viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true }], ngImport: i0, template: "<div class=\"h-full relative container\">\n <div\n class=\"pointer-events-auto absolute text-white flex flex-row p-2 rounded message\"\n role=\"alert\"\n [ngClass]=\"{\n 'position-bottom': position === 'bottom',\n 'position-top': position === 'top',\n expanded: this.expanded,\n 'bg-red-500': type === 'danger',\n 'bg-yellow-500': type === 'warning',\n 'bg-blue-500': type === 'info',\n }\"\n (mouseenter)=\"expand()\"\n (mouseleave)=\"expandAndClose()\"\n >\n <ng-icon class=\"mr-2 shrink-0 select-none\" [name]=\"icon\"></ng-icon>\n <div class=\"grow\" #content [ngClass]=\"{ invisible: !expanded }\">\n <ng-content></ng-content>\n </div>\n </div>\n</div>\n", styles: [":host{pointer-events:none}.container{filter:drop-shadow(0px 4px 3px rgba(0,0,0,.2))}.message{transition:clip-path .3s cubic-bezier(.25,.46,.45,.94)}.message.expanded{clip-path:circle(100%)}.position-top{clip-path:circle(19px at 20px 20px);align-items:start;top:0;left:0}.position-bottom{clip-path:circle(19px at 20px calc(100% - 20px));align-items:end;bottom:0;left:0}.container ::ng-deep a{text-decoration:underline;font-weight:700}.container ::ng-deep a:hover{opacity:.85}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
23730
23606
  }
23731
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: MapStyleService, decorators: [{
23732
- type: Injectable,
23733
- args: [{
23734
- providedIn: 'root',
23735
- }]
23736
- }] });
23607
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopupAlertComponent, decorators: [{
23608
+ type: Component,
23609
+ args: [{ selector: 'gn-ui-popup-alert', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, NgIconComponent], providers: [
23610
+ provideIcons({ matErrorOutlineOutline }),
23611
+ provideNgIconsConfig({
23612
+ size: '1.5em',
23613
+ }),
23614
+ ], template: "<div class=\"h-full relative container\">\n <div\n class=\"pointer-events-auto absolute text-white flex flex-row p-2 rounded message\"\n role=\"alert\"\n [ngClass]=\"{\n 'position-bottom': position === 'bottom',\n 'position-top': position === 'top',\n expanded: this.expanded,\n 'bg-red-500': type === 'danger',\n 'bg-yellow-500': type === 'warning',\n 'bg-blue-500': type === 'info',\n }\"\n (mouseenter)=\"expand()\"\n (mouseleave)=\"expandAndClose()\"\n >\n <ng-icon class=\"mr-2 shrink-0 select-none\" [name]=\"icon\"></ng-icon>\n <div class=\"grow\" #content [ngClass]=\"{ invisible: !expanded }\">\n <ng-content></ng-content>\n </div>\n </div>\n</div>\n", styles: [":host{pointer-events:none}.container{filter:drop-shadow(0px 4px 3px rgba(0,0,0,.2))}.message{transition:clip-path .3s cubic-bezier(.25,.46,.45,.94)}.message.expanded{clip-path:circle(100%)}.position-top{clip-path:circle(19px at 20px 20px);align-items:start;top:0;left:0}.position-bottom{clip-path:circle(19px at 20px calc(100% - 20px));align-items:end;bottom:0;left:0}.container ::ng-deep a{text-decoration:underline;font-weight:700}.container ::ng-deep a:hover{opacity:.85}\n"] }]
23615
+ }], propDecorators: { icon: [{
23616
+ type: Input
23617
+ }], type: [{
23618
+ type: Input
23619
+ }], position: [{
23620
+ type: Input
23621
+ }], content: [{
23622
+ type: ViewChild,
23623
+ args: ['content']
23624
+ }] } });
23737
23625
 
23738
- const colorPrimary = 'blue';
23739
- const colorSecondary = 'red';
23740
- const colorStroke = 'white';
23741
- const defaultMapStyleFixture = () => new Style({
23742
- image: new Circle({
23743
- fill: new Fill({
23744
- color: colorPrimary,
23745
- }),
23746
- stroke: new Stroke({
23747
- color: colorStroke,
23748
- width: 2,
23749
- }),
23750
- radius: 5,
23751
- }),
23752
- fill: new Fill({
23753
- color: 'rgba(0,0,255,0.25)',
23754
- }),
23755
- stroke: new Stroke({
23756
- color: colorStroke,
23757
- width: 2,
23758
- }),
23759
- });
23760
- const defaultMapStyleHlFixture = () => new Style({
23761
- image: new Circle({
23762
- fill: new Fill({
23763
- color: colorSecondary,
23764
- }),
23765
- stroke: new Stroke({
23766
- color: colorStroke,
23767
- width: 3,
23768
- }),
23769
- radius: 6,
23770
- }),
23771
- fill: new Fill({
23772
- color: 'rgba(255,0,0,0.25)',
23773
- }),
23774
- stroke: new Stroke({
23775
- color: colorSecondary,
23776
- width: 3,
23777
- }),
23778
- });
23626
+ class SpinningLoaderComponent {
23627
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpinningLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23628
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: SpinningLoaderComponent, isStandalone: true, selector: "gn-ui-spinning-loader", ngImport: i0, template: "<span>\n <svg\n class=\"animate-spin\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n</span>\n", styles: [""] }); }
23629
+ }
23630
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpinningLoaderComponent, decorators: [{
23631
+ type: Component,
23632
+ args: [{ selector: 'gn-ui-spinning-loader', standalone: true, template: "<span>\n <svg\n class=\"animate-spin\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n</span>\n" }]
23633
+ }] });
23779
23634
 
23780
- class AnchorLinkDirective {
23635
+ class ButtonComponent {
23781
23636
  constructor() {
23782
- this.changeDetector = inject(ChangeDetectorRef);
23637
+ this.btnClass = 'gn-ui-btn-default';
23783
23638
  this.disabled = false;
23784
- this.observer = new MutationObserver(() => {
23785
- this.refreshDisabledState();
23786
- });
23787
- this.inView = false;
23788
- this.initialized = false;
23789
- }
23790
- get elementClass() {
23791
- if (this.disabled) {
23792
- return this.disabledClass;
23793
- }
23794
- if (this.inView) {
23795
- return `${this.inViewClass} ${this.enabledClass}`;
23796
- }
23797
- else {
23798
- return `${this.outOfViewClass} ${this.enabledClass}`;
23799
- }
23800
- }
23801
- ngOnInit() {
23802
- this.observer.observe(document.body, {
23803
- childList: true,
23804
- subtree: true,
23805
- });
23806
- this.refreshDisabledState();
23807
- }
23808
- ngAfterViewChecked() {
23809
- if (!this.initialized && !this.disabled) {
23810
- const target = document.getElementById(this.targetId);
23811
- if (target) {
23812
- this.initializeIntersectionObserver(target);
23813
- this.initialized = true;
23814
- }
23815
- }
23816
- }
23817
- initializeIntersectionObserver(target) {
23818
- this.intersectionObserver = new IntersectionObserver((entries) => {
23819
- entries.forEach((entry) => {
23820
- this.inView = entry.isIntersecting;
23821
- this.changeDetector.detectChanges();
23822
- });
23823
- }, {
23824
- root: null,
23825
- rootMargin: '-30% 0% -60% 0%',
23826
- });
23827
- this.intersectionObserver.observe(target);
23828
- }
23829
- ngOnDestroy() {
23830
- this.observer.disconnect();
23831
- if (this.intersectionObserver) {
23832
- this.intersectionObserver.disconnect();
23833
- }
23834
- }
23835
- refreshDisabledState() {
23836
- const targetNotPresent = !document.getElementById(this.targetId);
23837
- if (targetNotPresent !== this.disabled) {
23838
- this.disabled = targetNotPresent;
23839
- this.changeDetector.detectChanges();
23840
- }
23841
- }
23842
- scrollToTarget() {
23843
- const target = document.getElementById(this.targetId);
23844
- if (!target)
23845
- return;
23846
- target.scrollIntoView({
23847
- behavior: 'smooth',
23848
- block: 'start',
23849
- });
23850
- }
23851
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
23852
- 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 }); }
23853
- }
23854
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AnchorLinkDirective, decorators: [{
23855
- type: Directive,
23856
- args: [{
23857
- selector: '[gnUiAnchorLink]',
23858
- standalone: true,
23859
- }]
23860
- }], propDecorators: { targetId: [{
23861
- type: Input,
23862
- args: ['gnUiAnchorLink']
23863
- }], disabledClass: [{
23864
- type: Input,
23865
- args: ['gnUiAnchorLinkDisabledClass']
23866
- }], enabledClass: [{
23867
- type: Input,
23868
- args: ['gnUiAnchorLinkEnabledClass']
23869
- }], inViewClass: [{
23870
- type: Input,
23871
- args: ['gnUiAnchorLinkInViewClass']
23872
- }], outOfViewClass: [{
23873
- type: Input,
23874
- args: ['gnUiAnchorLinkOutOfViewClass']
23875
- }], elementClass: [{
23876
- type: HostBinding,
23877
- args: ['class']
23878
- }], scrollToTarget: [{
23879
- type: HostListener,
23880
- args: ['click']
23881
- }] } });
23882
-
23883
- class PaginationDotsComponent {
23884
- constructor() {
23885
- this.containerClass = '';
23886
- }
23887
- // 1-based
23888
- get steps() {
23889
- return Array.from({ length: this.listComponent.pagesCount }, (_, i) => i + 1);
23890
- }
23891
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23892
- 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: [
23893
- provideIcons({
23894
- iconoirNavArrowRight,
23895
- iconoirNavArrowLeft,
23896
- }),
23897
- ] }); }
23898
- }
23899
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PaginationDotsComponent, decorators: [{
23900
- type: Component,
23901
- args: [{ selector: 'gn-ui-pagination-dots', standalone: true, imports: [CommonModule], viewProviders: [
23902
- provideIcons({
23903
- iconoirNavArrowRight,
23904
- iconoirNavArrowLeft,
23905
- }),
23906
- ], 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"] }]
23907
- }], propDecorators: { listComponent: [{
23908
- type: Input
23909
- }], containerClass: [{
23910
- type: Input
23911
- }] } });
23912
-
23913
- class CarouselComponent {
23914
- constructor() {
23915
- this.changeDetector = inject(ChangeDetectorRef);
23916
- this.containerClass = '';
23917
- this.stepsContainerClass = 'w-full bottom-0 top-auto';
23918
- this.currentStepChange = new EventEmitter();
23919
- this.steps = [];
23920
- this.currentStep = 0;
23921
- this.refreshSteps = () => {
23922
- this.steps = this.emblaApi.scrollSnapList();
23923
- this.currentStep = this.emblaApi.selectedScrollSnap();
23924
- this.currentStepChange.emit(this.currentStep);
23925
- this.changeDetector.detectChanges();
23926
- };
23927
- }
23928
- // Paginable API
23929
- get isFirstPage() {
23930
- return this.currentStep === 0;
23931
- }
23932
- get isLastPage() {
23933
- return this.currentStep === this.steps.length - 1;
23934
- }
23935
- get currentPage() {
23936
- return this.currentStep + 1; // this is 1-based
23937
- }
23938
- get pagesCount() {
23939
- return this.steps.length;
23940
- }
23941
- goToPage(stepIndex) {
23942
- this.emblaApi.scrollTo(stepIndex - 1); // this is 0-based
23943
- }
23944
- goToPrevPage() {
23945
- if (this.isFirstPage)
23946
- return;
23947
- this.emblaApi.scrollPrev();
23948
- }
23949
- goToNextPage() {
23950
- if (this.isLastPage)
23951
- return;
23952
- this.emblaApi.scrollNext();
23953
- }
23954
- ngAfterViewInit() {
23955
- this.emblaApi = EmblaCarousel(this.carouselOverflowContainer.nativeElement, {
23956
- duration: 15,
23957
- });
23958
- this.emblaApi
23959
- .on('init', this.refreshSteps)
23960
- .on('reInit', this.refreshSteps)
23961
- .on('select', this.refreshSteps);
23962
- }
23963
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
23964
- 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 }); }
23965
- }
23966
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: CarouselComponent, decorators: [{
23967
- type: Component,
23968
- 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"] }]
23969
- }], propDecorators: { carouselOverflowContainer: [{
23970
- type: ViewChild,
23971
- args: ['carouselOverflowContainer']
23972
- }], containerClass: [{
23973
- type: Input
23974
- }], stepsContainerClass: [{
23975
- type: Input
23976
- }], currentStepChange: [{
23977
- type: Output
23978
- }] } });
23979
-
23980
- class ProgressBarComponent {
23981
- constructor() {
23982
- this.value = 0;
23983
- this.type = 'default';
23984
- }
23985
- get progress() {
23986
- return this.value > 0 ? (this.value < 100 ? this.value : 100) : 0;
23987
- }
23988
- get color() {
23989
- switch (this.type) {
23990
- case 'default':
23991
- return {
23992
- outerBar: 'bg-gray-200',
23993
- innerBar: 'bg-gray-100',
23994
- text: 'text-gray-900',
23995
- };
23996
- case 'primary':
23997
- return {
23998
- outerBar: 'bg-primary',
23999
- innerBar: 'bg-primary-lighter',
24000
- text: 'text-white',
24001
- };
24002
- case 'secondary':
24003
- return {
24004
- outerBar: 'bg-secondary',
24005
- innerBar: 'bg-secondary-lighter',
24006
- text: 'text-white',
24007
- };
24008
- case 'light':
24009
- return {
24010
- outerBar: 'bg-primary-white',
24011
- innerBar: 'bg-primary',
24012
- text: 'text-main',
24013
- };
24014
- }
24015
- }
24016
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24017
- 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"] }); }
24018
- }
24019
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ProgressBarComponent, decorators: [{
24020
- type: Component,
24021
- 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"] }]
24022
- }], propDecorators: { value: [{
24023
- type: Input
24024
- }], type: [{
24025
- type: Input
24026
- }] } });
24027
-
24028
- class PopoverComponent {
24029
- constructor() {
24030
- this.viewContainerRef = inject(ViewContainerRef);
24031
- this.renderer = inject(Renderer2);
24032
- }
24033
- getContent() {
24034
- if (this.content instanceof TemplateRef) {
24035
- if (this.view) {
24036
- this.view.destroy();
24037
- }
24038
- this.view = this.viewContainerRef.createEmbeddedView(this.content);
24039
- this.view.detectChanges();
24040
- const wrapper = this.renderer.createElement('div'); // Create a wrapper div
24041
- this.view.rootNodes.forEach((node) => {
24042
- this.renderer.appendChild(wrapper, node); // Append each root node to the wrapper
24043
- });
24044
- return wrapper;
24045
- }
24046
- return this.content;
24047
- }
24048
- ngAfterViewInit() {
24049
- this.tippyInstance = tippy(this.popoverContent.nativeElement, {
24050
- content: this.getContent(),
24051
- allowHTML: true,
24052
- theme: this.theme,
24053
- });
24054
- }
24055
- ngOnChanges(changes) {
24056
- if (changes['theme']) {
24057
- this.theme = changes['theme'].currentValue;
24058
- if (this.tippyInstance) {
24059
- this.tippyInstance.setProps({ theme: this.theme });
24060
- }
24061
- }
24062
- if (changes['content']) {
24063
- this.content = changes['content'].currentValue;
24064
- if (this.tippyInstance) {
24065
- this.tippyInstance.setContent(this.getContent());
24066
- }
24067
- }
24068
- }
24069
- ngOnDestroy() {
24070
- if (this.tippyInstance) {
24071
- this.tippyInstance.destroy();
24072
- }
24073
- if (this.view) {
24074
- this.view.destroy();
24075
- }
24076
- }
24077
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24078
- 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: [""] }); }
24079
- }
24080
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopoverComponent, decorators: [{
24081
- type: Component,
24082
- args: [{ selector: 'gn-ui-popover', standalone: true, imports: [], template: "<span #popoverContent>\n <ng-content></ng-content>\n</span>\n" }]
24083
- }], propDecorators: { popoverContent: [{
24084
- type: ViewChild,
24085
- args: ['popoverContent', { static: false }]
24086
- }], content: [{
24087
- type: Input
24088
- }], theme: [{
24089
- type: Input
24090
- }] } });
24091
-
24092
- class LoadingMaskComponent {
24093
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24094
- 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 }); }
24095
- }
24096
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LoadingMaskComponent, decorators: [{
24097
- type: Component,
24098
- 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"] }]
24099
- }], propDecorators: { message: [{
24100
- type: Input
24101
- }] } });
24102
-
24103
- class ColorScaleComponent {
24104
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24105
- 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: [""] }); }
24106
- }
24107
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: ColorScaleComponent, decorators: [{
24108
- type: Component,
24109
- 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" }]
24110
- }] });
24111
-
24112
- class PopupAlertComponent {
24113
- constructor() {
24114
- this.changeDetector = inject(ChangeDetectorRef);
24115
- this.type = 'info';
24116
- this.position = 'top';
24117
- this.expanded = false;
24118
- this.timeout = null;
24119
- }
24120
- get showDuration() {
24121
- const chars = this.content.nativeElement.innerHTML.length;
24122
- return Math.max(3000, chars * 20);
24123
- }
24124
- ngOnInit() {
24125
- this.expandAndClose();
24126
- }
24127
- expand() {
24128
- this.expanded = true;
24129
- this.changeDetector.detectChanges();
24130
- clearTimeout(this.timeout);
24131
- }
24132
- expandAndClose() {
24133
- this.expanded = true;
24134
- this.changeDetector.detectChanges();
24135
- clearTimeout(this.timeout);
24136
- this.timeout = setTimeout(() => {
24137
- this.expanded = false;
24138
- this.changeDetector.detectChanges();
24139
- }, this.showDuration);
24140
- }
24141
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopupAlertComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24142
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: PopupAlertComponent, isStandalone: true, selector: "gn-ui-popup-alert", inputs: { icon: "icon", type: "type", position: "position" }, providers: [
24143
- provideIcons({ matErrorOutlineOutline }),
24144
- provideNgIconsConfig({
24145
- size: '1.5em',
24146
- }),
24147
- ], viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true }], ngImport: i0, template: "<div class=\"h-full relative container\">\n <div\n class=\"pointer-events-auto absolute text-white flex flex-row p-2 rounded message\"\n role=\"alert\"\n [ngClass]=\"{\n 'position-bottom': position === 'bottom',\n 'position-top': position === 'top',\n expanded: this.expanded,\n 'bg-red-500': type === 'danger',\n 'bg-yellow-500': type === 'warning',\n 'bg-blue-500': type === 'info',\n }\"\n (mouseenter)=\"expand()\"\n (mouseleave)=\"expandAndClose()\"\n >\n <ng-icon class=\"mr-2 shrink-0 select-none\" [name]=\"icon\"></ng-icon>\n <div class=\"grow\" #content [ngClass]=\"{ invisible: !expanded }\">\n <ng-content></ng-content>\n </div>\n </div>\n</div>\n", styles: [":host{pointer-events:none}.container{filter:drop-shadow(0px 4px 3px rgba(0,0,0,.2))}.message{transition:clip-path .3s cubic-bezier(.25,.46,.45,.94)}.message.expanded{clip-path:circle(100%)}.position-top{clip-path:circle(19px at 20px 20px);align-items:start;top:0;left:0}.position-bottom{clip-path:circle(19px at 20px calc(100% - 20px));align-items:end;bottom:0;left:0}.container ::ng-deep a{text-decoration:underline;font-weight:700}.container ::ng-deep a:hover{opacity:.85}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
24148
- }
24149
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: PopupAlertComponent, decorators: [{
24150
- type: Component,
24151
- args: [{ selector: 'gn-ui-popup-alert', changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, NgIconComponent], providers: [
24152
- provideIcons({ matErrorOutlineOutline }),
24153
- provideNgIconsConfig({
24154
- size: '1.5em',
24155
- }),
24156
- ], template: "<div class=\"h-full relative container\">\n <div\n class=\"pointer-events-auto absolute text-white flex flex-row p-2 rounded message\"\n role=\"alert\"\n [ngClass]=\"{\n 'position-bottom': position === 'bottom',\n 'position-top': position === 'top',\n expanded: this.expanded,\n 'bg-red-500': type === 'danger',\n 'bg-yellow-500': type === 'warning',\n 'bg-blue-500': type === 'info',\n }\"\n (mouseenter)=\"expand()\"\n (mouseleave)=\"expandAndClose()\"\n >\n <ng-icon class=\"mr-2 shrink-0 select-none\" [name]=\"icon\"></ng-icon>\n <div class=\"grow\" #content [ngClass]=\"{ invisible: !expanded }\">\n <ng-content></ng-content>\n </div>\n </div>\n</div>\n", styles: [":host{pointer-events:none}.container{filter:drop-shadow(0px 4px 3px rgba(0,0,0,.2))}.message{transition:clip-path .3s cubic-bezier(.25,.46,.45,.94)}.message.expanded{clip-path:circle(100%)}.position-top{clip-path:circle(19px at 20px 20px);align-items:start;top:0;left:0}.position-bottom{clip-path:circle(19px at 20px calc(100% - 20px));align-items:end;bottom:0;left:0}.container ::ng-deep a{text-decoration:underline;font-weight:700}.container ::ng-deep a:hover{opacity:.85}\n"] }]
24157
- }], propDecorators: { icon: [{
24158
- type: Input
24159
- }], type: [{
24160
- type: Input
24161
- }], position: [{
24162
- type: Input
24163
- }], content: [{
24164
- type: ViewChild,
24165
- args: ['content']
24166
- }] } });
24167
-
24168
- class SpinningLoaderComponent {
24169
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpinningLoaderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
24170
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: SpinningLoaderComponent, isStandalone: true, selector: "gn-ui-spinning-loader", ngImport: i0, template: "<span>\n <svg\n class=\"animate-spin\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n</span>\n", styles: [""] }); }
24171
- }
24172
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpinningLoaderComponent, decorators: [{
24173
- type: Component,
24174
- args: [{ selector: 'gn-ui-spinning-loader', standalone: true, template: "<span>\n <svg\n class=\"animate-spin\"\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n class=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"4\"\n ></circle>\n <path\n class=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z\"\n ></path>\n </svg>\n</span>\n" }]
24175
- }] });
24176
-
24177
- class ButtonComponent {
24178
- constructor() {
24179
- this.btnClass = 'gn-ui-btn-default';
24180
- this.disabled = false;
24181
- this.extraClass = '';
24182
- this.buttonClick = new EventEmitter();
23639
+ this.extraClass = '';
23640
+ this.buttonClick = new EventEmitter();
24183
23641
  }
24184
23642
  set type(value) {
24185
23643
  // btn-classes are written in full to be picked up by tailwind
@@ -24293,15 +23751,15 @@ class AutocompleteComponent {
24293
23751
  getExtraClass() {
24294
23752
  if (this.allowSubmit) {
24295
23753
  if (this.enterButton) {
24296
- return 'border rounded-lg absolute w-8 h-8 right-[calc(var(--icon-width)+var(--icon-padding))] inset-y-[--icon-padding]';
23754
+ return 'border rounded-lg absolute w-8 h-8 right-[calc(var(--icon-width)+var(--icon-padding))] top-1/2 -translate-y-1/2';
24297
23755
  }
24298
23756
  else {
24299
- 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))]';
23757
+ 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';
24300
23758
  }
24301
23759
  }
24302
23760
  else {
24303
23761
  if (!this.enterButton) {
24304
- return 'border rounded-lg absolute w-8 h-8 right-2 inset-y-2';
23762
+ return 'border rounded-lg absolute w-8 h-8 right-2 top-1/2 -translate-y-1/2';
24305
23763
  }
24306
23764
  }
24307
23765
  return 'border rounded-lg absolute w-8 h-8';
@@ -24446,7 +23904,7 @@ class AutocompleteComponent {
24446
23904
  provideNgIconsConfig({
24447
23905
  size: '1.75rem',
24448
23906
  }),
24449
- ], 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 @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}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.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 }); }
23907
+ ], 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 }); }
24450
23908
  }
24451
23909
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: AutocompleteComponent, decorators: [{
24452
23910
  type: Component,
@@ -24467,7 +23925,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
24467
23925
  provideNgIconsConfig({
24468
23926
  size: '1.75rem',
24469
23927
  }),
24470
- ], 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 @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}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"] }]
23928
+ ], 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"] }]
24471
23929
  }], propDecorators: { placeholder: [{
24472
23930
  type: Input
24473
23931
  }], enterButton: [{
@@ -25943,7 +25401,8 @@ class SearchFeatureCatalogComponent {
25943
25401
  const filtered = (this.featureCatalog?.featureTypes || []).filter((featureType) => {
25944
25402
  const fuzzyFilter = createFuzzyFilter(searchTerm);
25945
25403
  return (fuzzyFilter(featureType.name) ||
25946
- (featureType.definition && fuzzyFilter(featureType.definition)));
25404
+ (featureType.description &&
25405
+ fuzzyFilter(featureType.description)));
25947
25406
  });
25948
25407
  this.filteredFeatureCatalog = {
25949
25408
  ...this.featureCatalog,
@@ -26028,8 +25487,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
26028
25487
  marker('search.filters.spatialExtent.import');
26029
25488
  marker('search.filters.spatialExtent.helpText');
26030
25489
  marker('search.filters.spatialExtent.error.title');
25490
+ marker('search.filters.spatialExtent.error.outOfBounds');
26031
25491
  const LABEL_FROM_FILE = marker('search.filters.spatialExtent.bboxFromFile');
26032
25492
  const LABEL_FROM_FILE_DELETE = marker('search.filters.spatialExtent.bboxFromFileDelete');
25493
+ const LABEL_FROM_LOCATION = marker('search.filters.spatialExtent.bboxFromLocation');
25494
+ const LABEL_FROM_LOCATION_DELETE = marker('search.filters.spatialExtent.bboxFromLocationDelete');
26033
25495
  const LABEL_INITIAL = marker('search.filters.spatialExtent.bboxInitial');
26034
25496
  const LABEL_INITIAL_DELETE = marker('search.filters.spatialExtent.bboxInitialDelete');
26035
25497
  class SpatialExtentDropdownComponent {
@@ -26041,6 +25503,7 @@ class SpatialExtentDropdownComponent {
26041
25503
  this.errorChange = new EventEmitter();
26042
25504
  this.bbox = null;
26043
25505
  this.fileName = '';
25506
+ this.locationName = '';
26044
25507
  this.overlayPositions = [
26045
25508
  {
26046
25509
  originX: 'start',
@@ -26071,13 +25534,21 @@ class SpatialExtentDropdownComponent {
26071
25534
  return !!this.bbox;
26072
25535
  }
26073
25536
  get selectionLabelKey() {
26074
- return this.fileName ? LABEL_FROM_FILE : LABEL_INITIAL;
25537
+ if (this.fileName)
25538
+ return LABEL_FROM_FILE;
25539
+ if (this.locationName)
25540
+ return LABEL_FROM_LOCATION;
25541
+ return LABEL_INITIAL;
26075
25542
  }
26076
25543
  get selectionDeleteLabelKey() {
26077
- return this.fileName ? LABEL_FROM_FILE_DELETE : LABEL_INITIAL_DELETE;
25544
+ if (this.fileName)
25545
+ return LABEL_FROM_FILE_DELETE;
25546
+ if (this.locationName)
25547
+ return LABEL_FROM_LOCATION_DELETE;
25548
+ return LABEL_INITIAL_DELETE;
26078
25549
  }
26079
25550
  get selectionLabelParams() {
26080
- return { fileName: this.fileName };
25551
+ return { fileName: this.fileName, locationName: this.locationName };
26081
25552
  }
26082
25553
  openOverlay() {
26083
25554
  this.overlayMinWidth =
@@ -26108,8 +25579,13 @@ class SpatialExtentDropdownComponent {
26108
25579
  return;
26109
25580
  }
26110
25581
  const bbox = getGeometryBoundingBox(geometry);
25582
+ if (!isBoundingBoxWithinWorldExtent(bbox)) {
25583
+ this.setError(marker('search.filters.spatialExtent.error.outOfBounds'));
25584
+ return;
25585
+ }
26111
25586
  this.bbox = bbox;
26112
25587
  this.fileName = file.name;
25588
+ this.locationName = '';
26113
25589
  this.bboxChange.emit(bbox);
26114
25590
  this.cd.markForCheck();
26115
25591
  }
@@ -26118,6 +25594,15 @@ class SpatialExtentDropdownComponent {
26118
25594
  return;
26119
25595
  }
26120
25596
  }
25597
+ setLocationBbox(bbox, name) {
25598
+ this.errorKey = null;
25599
+ this.bbox = bbox;
25600
+ this.locationName = name;
25601
+ this.fileName = '';
25602
+ this.fileInput?.clear();
25603
+ this.bboxChange.emit(bbox);
25604
+ this.cd.markForCheck();
25605
+ }
26121
25606
  handleFileError(error) {
26122
25607
  if (error === 'file-too-large') {
26123
25608
  this.setError(marker('search.filters.spatialExtent.error.fileTooLarge'), {
@@ -26136,6 +25621,7 @@ class SpatialExtentDropdownComponent {
26136
25621
  removeSelection(event) {
26137
25622
  this.bbox = null;
26138
25623
  this.fileName = '';
25624
+ this.locationName = '';
26139
25625
  this.errorKey = null;
26140
25626
  this.fileInput?.clear();
26141
25627
  this.bboxChange.emit(null);
@@ -26145,14 +25631,14 @@ class SpatialExtentDropdownComponent {
26145
25631
  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: [
26146
25632
  provideIcons({
26147
25633
  iconoirCheckCircle,
26148
- iconoirImport,
26149
25634
  iconoirSquareDashed,
26150
25635
  iconoirTrash,
25636
+ iconoirUpload,
26151
25637
  matClose,
26152
25638
  matExpandLess,
26153
25639
  matExpandMore,
26154
25640
  }),
26155
- ], 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 }); }
25641
+ ], 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 }); }
26156
25642
  }
26157
25643
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: SpatialExtentDropdownComponent, decorators: [{
26158
25644
  type: Component,
@@ -26165,14 +25651,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
26165
25651
  ], providers: [
26166
25652
  provideIcons({
26167
25653
  iconoirCheckCircle,
26168
- iconoirImport,
26169
25654
  iconoirSquareDashed,
26170
25655
  iconoirTrash,
25656
+ iconoirUpload,
26171
25657
  matClose,
26172
25658
  matExpandLess,
26173
25659
  matExpandMore,
26174
25660
  }),
26175
- ], 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" }]
25661
+ ], 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" }]
26176
25662
  }], propDecorators: { title: [{
26177
25663
  type: Input
26178
25664
  }], maxFileSizeMb: [{
@@ -26698,11 +26184,11 @@ class BlockListComponent {
26698
26184
  this.goToPage(this.currentPage + 1);
26699
26185
  }
26700
26186
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: BlockListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
26701
- 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 }); }
26187
+ 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 }); }
26702
26188
  }
26703
26189
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: BlockListComponent, decorators: [{
26704
26190
  type: Component,
26705
- 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"] }]
26191
+ 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"] }]
26706
26192
  }], propDecorators: { containerClass: [{
26707
26193
  type: Input
26708
26194
  }], paginationContainerClass: [{
@@ -27441,9 +26927,7 @@ const initSearch = () => {
27441
26927
  },
27442
26928
  params: {
27443
26929
  filters: {},
27444
- pageSize: getOptionalSearchConfig()?.LIMIT
27445
- ? getOptionalSearchConfig().LIMIT
27446
- : DEFAULT_PAGE_SIZE,
26930
+ pageSize: DEFAULT_PAGE_SIZE,
27447
26931
  currentPage: 0,
27448
26932
  favoritesOnly: false,
27449
26933
  useSpatialFilter: true,
@@ -27892,10 +27376,36 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
27892
27376
  }]
27893
27377
  }] });
27894
27378
 
27379
+ const DEFAULT_GEOCODING_PROVIDER = [
27380
+ 'geonames',
27381
+ { maxRows: 5 },
27382
+ ];
27895
27383
  const GEOCODING_PROVIDER = new InjectionToken('geocoding-provider', {
27896
27384
  providedIn: 'root',
27897
- factory: () => ['geonames', { maxRows: 5 }],
27385
+ factory: () => DEFAULT_GEOCODING_PROVIDER,
27898
27386
  });
27387
+ // these options are arrays in the providers, but they can be configured
27388
+ // with a single value for simplicity
27389
+ const GEOCODING_PROVIDER_ARRAY_OPTIONS = {
27390
+ geoadmin: ['origins', 'features'],
27391
+ geoplateforme: [
27392
+ 'index',
27393
+ 'category',
27394
+ 'type',
27395
+ 'postCode',
27396
+ 'cityCode',
27397
+ 'depCode',
27398
+ ],
27399
+ };
27400
+ function wrapArrayOptions(options, keys) {
27401
+ const wrapped = { ...options };
27402
+ for (const key of keys) {
27403
+ if (typeof wrapped[key] === 'string') {
27404
+ wrapped[key] = [wrapped[key]];
27405
+ }
27406
+ }
27407
+ return wrapped;
27408
+ }
27899
27409
  class GeocodingService {
27900
27410
  constructor() {
27901
27411
  this.provider = inject(GEOCODING_PROVIDER);
@@ -27904,13 +27414,16 @@ class GeocodingService {
27904
27414
  let queryObservable;
27905
27415
  switch (this.provider[0]) {
27906
27416
  case 'geoadmin':
27907
- queryObservable = from(queryGeoadmin(text, this.provider[1]));
27417
+ queryObservable = from(queryGeoadmin(text, wrapArrayOptions(this.provider[1], GEOCODING_PROVIDER_ARRAY_OPTIONS.geoadmin)));
27908
27418
  break;
27909
27419
  case 'geonames':
27910
27420
  queryObservable = from(queryGeonames(text, this.provider[1]));
27911
27421
  break;
27912
- case 'data-gouv-fr':
27913
- queryObservable = from(queryDataGouvFr(text, this.provider[1]));
27422
+ case 'geoplateforme':
27423
+ queryObservable = from(queryGeoplateforme(text, {
27424
+ ...wrapArrayOptions(this.provider[1], GEOCODING_PROVIDER_ARRAY_OPTIONS.geoplateforme),
27425
+ returnTrueGeometry: true,
27426
+ }));
27914
27427
  break;
27915
27428
  default:
27916
27429
  return throwError(() => new Error(`Unsupported geocoding provider: ${this.provider[0]}`));
@@ -27927,29 +27440,80 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
27927
27440
  }]
27928
27441
  }] });
27929
27442
 
27443
+ const GEOCODING_PROVIDER_LABELS = new InjectionToken('geocodingProviderLabels', {
27444
+ factory: () => ({}),
27445
+ });
27930
27446
  class LocationSearchComponent {
27931
27447
  constructor() {
27932
27448
  this.geocodingService = inject(GeocodingService);
27449
+ this.labels = inject(GEOCODING_PROVIDER_LABELS);
27933
27450
  this.placeholder = '';
27934
27451
  this.resultSelected = new EventEmitter();
27452
+ this.bboxSelected = new EventEmitter();
27935
27453
  this.displayWithFn = (item) => item.label;
27936
27454
  this.searchAction = (text) => this.geocodingService.query(text);
27937
27455
  }
27456
+ getSecondaryLabel(result) {
27457
+ return this.resolveLabel(result, this.labels.secondary);
27458
+ }
27459
+ getMainLabel(result) {
27460
+ return this.resolveLabel(result, this.labels.main) ?? result.label;
27461
+ }
27462
+ getTertiaryLabel(result) {
27463
+ return this.resolveLabel(result, this.labels.tertiary);
27464
+ }
27465
+ getDisplayLabel(result) {
27466
+ const tertiary = this.getTertiaryLabel(result);
27467
+ return this.getMainLabel(result) + (tertiary ? ', ' + tertiary : '');
27468
+ }
27469
+ resolveLabel(result, path) {
27470
+ if (!path)
27471
+ return undefined;
27472
+ let value;
27473
+ try {
27474
+ value = pointer.get(result, path);
27475
+ }
27476
+ catch {
27477
+ return undefined;
27478
+ }
27479
+ const values = Array.isArray(value) ? value : [value];
27480
+ const label = values
27481
+ .filter((v) => typeof v === 'string' || typeof v === 'number')
27482
+ .join(', ');
27483
+ return label || undefined;
27484
+ }
27485
+ // geoplateforme keeps a simplified geometry in geom and puts the real one,
27486
+ // as a JSON string, in properties.truegeometry when returnTrueGeometry is set
27487
+ getGeometry(result) {
27488
+ const trueGeometry = result.properties?.['truegeometry'];
27489
+ if (typeof trueGeometry === 'string') {
27490
+ return JSON.parse(trueGeometry);
27491
+ }
27492
+ return trueGeometry ?? result.geom;
27493
+ }
27938
27494
  handleItemSelected(item) {
27939
- this.resultSelected.emit(item);
27495
+ const result = item;
27496
+ this.resultSelected.emit(result);
27497
+ const geometry = this.getGeometry(result);
27498
+ if (geometry) {
27499
+ this.bboxSelected.emit({
27500
+ bbox: getGeometryBoundingBox(geometry),
27501
+ label: this.getDisplayLabel(result),
27502
+ });
27503
+ }
27940
27504
  }
27941
27505
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
27942
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: LocationSearchComponent, isStandalone: true, selector: "gn-ui-location-search", inputs: { placeholder: "placeholder", displayWithTemplate: "displayWithTemplate" }, outputs: { resultSelected: "resultSelected" }, ngImport: i0, template: "<gn-ui-autocomplete\n [action]=\"searchAction\"\n [displayWithFn]=\"displayWithFn\"\n [placeholder]=\"placeholder\"\n [displayWithTemplate]=\"displayWithTemplate\"\n (itemSelected)=\"handleItemSelected($event)\"\n>\n</gn-ui-autocomplete>\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 }); }
27506
+ 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 }); }
27943
27507
  }
27944
27508
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: LocationSearchComponent, decorators: [{
27945
27509
  type: Component,
27946
- 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]=\"displayWithTemplate\"\n (itemSelected)=\"handleItemSelected($event)\"\n>\n</gn-ui-autocomplete>\n" }]
27510
+ 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" }]
27947
27511
  }], propDecorators: { placeholder: [{
27948
27512
  type: Input
27949
- }], displayWithTemplate: [{
27950
- type: Input
27951
27513
  }], resultSelected: [{
27952
27514
  type: Output
27515
+ }], bboxSelected: [{
27516
+ type: Output
27953
27517
  }] } });
27954
27518
 
27955
27519
  // expects the replacement key ${uuid}
@@ -28110,6 +27674,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
28110
27674
  class AbstractSearchField {
28111
27675
  }
28112
27676
  class SimpleSearchField {
27677
+ get fieldIdentifier() {
27678
+ return this.customIdentifier ?? this.esFieldName;
27679
+ }
28113
27680
  constructor(esFieldName, injector, order = 'asc', orderType = 'key') {
28114
27681
  this.esFieldName = esFieldName;
28115
27682
  this.injector = injector;
@@ -28118,14 +27685,26 @@ class SimpleSearchField {
28118
27685
  this.repository = this.injector.get(RecordsRepositoryInterface);
28119
27686
  // FIXME: this is required to register runtime fields; abstract this as well
28120
27687
  this.esService = this.injector.get(ElasticsearchService);
27688
+ this.includeValues = [];
27689
+ this.excludeValues = [];
27690
+ }
27691
+ setFieldIdentifier(fieldIdentifier) {
27692
+ this.customIdentifier = fieldIdentifier;
27693
+ this.esService.registerFieldAlias(fieldIdentifier, this.esFieldName);
28121
27694
  }
28122
27695
  getAggregations() {
28123
27696
  return {
28124
- [this.esFieldName]: {
27697
+ [this.fieldIdentifier]: {
28125
27698
  type: 'terms',
28126
27699
  field: this.esFieldName,
28127
27700
  limit: 1000,
28128
27701
  sort: [this.order, this.orderType],
27702
+ ...(this.includeValues?.length && {
27703
+ includeValues: this.includeValues,
27704
+ }),
27705
+ ...(this.excludeValues?.length && {
27706
+ excludeValues: this.excludeValues,
27707
+ }),
28129
27708
  },
28130
27709
  };
28131
27710
  }
@@ -28133,7 +27712,7 @@ class SimpleSearchField {
28133
27712
  return bucket.term.toString();
28134
27713
  }
28135
27714
  getAvailableValues() {
28136
- return this.repository.aggregate(this.getAggregations()).pipe(map$1((response) => response[this.esFieldName].buckets || []), switchMap((buckets) => {
27715
+ return this.repository.aggregate(this.getAggregations()).pipe(map$1((response) => response[this.fieldIdentifier].buckets || []), switchMap((buckets) => {
28137
27716
  const bucketPromises = buckets.map(async (bucket) => ({
28138
27717
  label: `${await this.getBucketLabel(bucket)} (${bucket.count})`,
28139
27718
  value: bucket.term.toString(),
@@ -28146,7 +27725,7 @@ class SimpleSearchField {
28146
27725
  // FieldValue[]
28147
27726
  if (this.getType() === 'values') {
28148
27727
  return of({
28149
- [this.esFieldName]: values.reduce((acc, val) => {
27728
+ [this.fieldIdentifier]: values.reduce((acc, val) => {
28150
27729
  const value = val.toString();
28151
27730
  if (value !== '') {
28152
27731
  return { ...acc, [value]: true };
@@ -28157,11 +27736,11 @@ class SimpleSearchField {
28157
27736
  }
28158
27737
  // DateRange
28159
27738
  return of({
28160
- [this.esFieldName]: values[0] !== '' ? values[0] : {},
27739
+ [this.fieldIdentifier]: values[0] !== '' ? values[0] : {},
28161
27740
  });
28162
27741
  }
28163
27742
  getValuesForFilter(filters) {
28164
- const filter = filters[this.esFieldName];
27743
+ const filter = filters[this.fieldIdentifier];
28165
27744
  if (!filter)
28166
27745
  return of([]);
28167
27746
  // filter by expression
@@ -28179,6 +27758,9 @@ class SimpleSearchField {
28179
27758
  getType() {
28180
27759
  return 'values';
28181
27760
  }
27761
+ clone() {
27762
+ return Object.create(this);
27763
+ }
28182
27764
  }
28183
27765
  class TranslatedSearchField extends SimpleSearchField {
28184
27766
  constructor(esFieldName, injector, order = 'asc', orderType = 'key') {
@@ -28448,11 +28030,11 @@ class BoundingBoxSearchField extends SimpleSearchField {
28448
28030
  }
28449
28031
  getFiltersForValues(values) {
28450
28032
  return of({
28451
- [this.esFieldName]: values.map(Number),
28033
+ [this.fieldIdentifier]: values.map(Number),
28452
28034
  });
28453
28035
  }
28454
28036
  getValuesForFilter(filters) {
28455
- const filter = filters[this.esFieldName];
28037
+ const filter = filters[this.fieldIdentifier];
28456
28038
  return of(isBoundingBox(filter) ? filter : []);
28457
28039
  }
28458
28040
  getType() {
@@ -28551,7 +28133,7 @@ class RecordKindField extends SimpleSearchField {
28551
28133
  }
28552
28134
  getFiltersForValues(values) {
28553
28135
  const filters = {
28554
- [this.esFieldName]: values.reduce((acc, value) => {
28136
+ [this.fieldIdentifier]: values.reduce((acc, value) => {
28555
28137
  if (value === '')
28556
28138
  return { ...acc, [value]: true };
28557
28139
  const keysToAdd = this.TYPE_MAPPING[value] || [value];
@@ -28574,7 +28156,7 @@ class RecordKindField extends SimpleSearchField {
28574
28156
  return of(filters);
28575
28157
  }
28576
28158
  getValuesForFilter(filters) {
28577
- const filter = filters[this.esFieldName];
28159
+ const filter = filters[this.fieldIdentifier];
28578
28160
  if (!filter)
28579
28161
  return of([]);
28580
28162
  const activeValues = Object.keys(filter).filter((v) => filter[v]);
@@ -28604,11 +28186,15 @@ marker('search.filters.publisherOrg');
28604
28186
  marker('search.filters.user');
28605
28187
  marker('search.filters.changeDate');
28606
28188
  marker('search.filters.resourceCreationRevisionDate');
28189
+ marker('search.filters.temporalExtent');
28607
28190
  marker('search.filters.spatialExtent');
28191
+ marker('search.filters.documentStandard');
28192
+ const CUSTOM_FIELDS = new InjectionToken('custom-fields');
28608
28193
  class FieldsService {
28609
28194
  constructor() {
28610
28195
  this.injector = inject(Injector);
28611
- this.fields = {
28196
+ this.customFields = inject(CUSTOM_FIELDS, { optional: true }) ?? [];
28197
+ this.baseFields = {
28612
28198
  organization: new OrganizationSearchField(this.injector),
28613
28199
  format: new SimpleSearchField('format', this.injector, 'asc'),
28614
28200
  resourceType: new ResourceTypeLegacyField(this.injector), // Deprecated, use `recordKind` instead
@@ -28628,9 +28214,31 @@ class FieldsService {
28628
28214
  user: new UserSearchField(this.injector),
28629
28215
  changeDate: new DateRangeSearchField('changeDate', this.injector, 'desc'),
28630
28216
  resourceCreationRevisionDate: new ResourceCreationRevisionDateSearchField(this.injector, 'desc'),
28217
+ temporalExtent: new DateRangeSearchField('resourceTemporalExtentDateRange', this.injector, 'desc'),
28631
28218
  availableServices: new AvailableServicesField(this.injector),
28632
28219
  spatialExtent: new BoundingBoxSearchField('spatialExtent', this.injector),
28633
28220
  };
28221
+ this.fields = { ...this.baseFields };
28222
+ for (const customField of this.customFields) {
28223
+ const baseField = this.baseFields[customField.baseFilter];
28224
+ if (!(baseField instanceof SimpleSearchField)) {
28225
+ console.warn(`The custom field '${customField.name}' relies on a base field '${customField.baseFilter}' that is not supported. This field will be ignored.`);
28226
+ continue;
28227
+ }
28228
+ if (!customField.name.includes(':')) {
28229
+ 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.`);
28230
+ continue;
28231
+ }
28232
+ const newField = baseField.clone();
28233
+ newField.setFieldIdentifier(customField.name);
28234
+ if (customField.includeValues) {
28235
+ newField.includeValues = customField.includeValues;
28236
+ }
28237
+ if (customField.excludeValues) {
28238
+ newField.excludeValues = customField.excludeValues;
28239
+ }
28240
+ this.fields[customField.name] = newField;
28241
+ }
28634
28242
  }
28635
28243
  get supportedFields() {
28636
28244
  return Object.keys(this.fields);
@@ -28678,7 +28286,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
28678
28286
  args: [{
28679
28287
  providedIn: 'root',
28680
28288
  }]
28681
- }] });
28289
+ }], ctorParameters: () => [] });
28682
28290
 
28683
28291
  class ApiCardComponent {
28684
28292
  constructor() {
@@ -30704,14 +30312,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
30704
30312
  marker('feature.catalog.attribute.type');
30705
30313
  marker('feature.catalog.attribute.name');
30706
30314
  marker('feature.catalog.attribute.code');
30707
- marker('feature.catalog.attribute.definition');
30315
+ marker('feature.catalog.attribute.description');
30708
30316
  marker('feature.catalog.attribute.values');
30709
30317
  class FeatureCatalogListComponent {
30710
30318
  constructor() {
30711
30319
  this.COLUMNS_DEFAULT = [
30712
30320
  { key: 'type', width: '25%' },
30713
30321
  { key: 'name', width: '40%' },
30714
- { key: 'definition', width: 'minmax(0px, 1fr)' },
30322
+ { key: 'description', width: 'minmax(0px, 1fr)' },
30715
30323
  ];
30716
30324
  this.COLUMN_VALUES = {
30717
30325
  key: 'values',
@@ -30732,7 +30340,7 @@ class FeatureCatalogListComponent {
30732
30340
  return col.key;
30733
30341
  }
30734
30342
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureCatalogListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
30735
- 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" }] }); }
30343
+ 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.value }}\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" }] }); }
30736
30344
  }
30737
30345
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FeatureCatalogListComponent, decorators: [{
30738
30346
  type: Component,
@@ -30745,7 +30353,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
30745
30353
  TruncatedTextComponent,
30746
30354
  NgIconComponent,
30747
30355
  ScrollingModule,
30748
- ], 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" }]
30356
+ ], 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.value }}\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" }]
30749
30357
  }], propDecorators: { filteredFeatureCatalog: [{
30750
30358
  type: Input
30751
30359
  }], scrollContainer: [{
@@ -31883,6 +31491,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
31883
31491
  ], 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" }]
31884
31492
  }] });
31885
31493
 
31494
+ marker('search.filters.spatialExtent.searchLocation');
31495
+ // in MB, null means no limit
31496
+ const SPATIAL_EXTENT_MAX_FILE_SIZE = new InjectionToken('spatialExtentMaxFileSize', { factory: () => null });
31886
31497
  class FilterDropdownComponent {
31887
31498
  constructor() {
31888
31499
  this.searchFacade = inject(SearchFacade);
@@ -31890,7 +31501,7 @@ class FilterDropdownComponent {
31890
31501
  this.fieldsService = inject(FieldsService);
31891
31502
  this.notificationsService = inject(NotificationsService);
31892
31503
  this.translateService = inject(TranslateService);
31893
- this.spatialExtentMaxFileSize = getOptionalSearchConfig()?.SPATIAL_EXTENT_MAX_FILE_SIZE;
31504
+ this.spatialExtentMaxFileSize = inject(SPATIAL_EXTENT_MAX_FILE_SIZE);
31894
31505
  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([])));
31895
31506
  this.selectedDateRange$ = this.selected$.pipe(map$1((selected) => (Array.isArray(selected) ? {} : selected)));
31896
31507
  this.selectedBoundingBox$ = this.selected$.pipe(map$1((selected) => Array.isArray(selected) && selected.length > 0
@@ -31911,6 +31522,9 @@ class FilterDropdownComponent {
31911
31522
  .subscribe((filters) => this.searchService.updateFilters(filters));
31912
31523
  this.clearSpatialExtentErrorNotification();
31913
31524
  }
31525
+ onLocationSelected({ bbox, label }) {
31526
+ this.spatialExtentDropdown.setLocationBbox(bbox, label);
31527
+ }
31914
31528
  onSpatialExtentError(error) {
31915
31529
  this.clearSpatialExtentErrorNotification();
31916
31530
  this.spatialExtentErrorNotificationId =
@@ -31941,7 +31555,7 @@ class FilterDropdownComponent {
31941
31555
  .subscribe((filters) => this.searchService.updateFilters(filters));
31942
31556
  }
31943
31557
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
31944
- 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 }); }
31558
+ 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 }); }
31945
31559
  }
31946
31560
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FilterDropdownComponent, decorators: [{
31947
31561
  type: Component,
@@ -31950,11 +31564,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
31950
31564
  DateRangeDropdownComponent,
31951
31565
  DropdownMultiselectComponent,
31952
31566
  SpatialExtentDropdownComponent,
31953
- ], 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" }]
31567
+ LocationSearchComponent,
31568
+ TranslatePipe,
31569
+ ], 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" }]
31954
31570
  }], propDecorators: { fieldName: [{
31955
31571
  type: Input
31956
31572
  }], title: [{
31957
31573
  type: Input
31574
+ }], spatialExtentDropdown: [{
31575
+ type: ViewChild,
31576
+ args: [SpatialExtentDropdownComponent]
31958
31577
  }] } });
31959
31578
 
31960
31579
  class FuzzySearchComponent {
@@ -32571,6 +32190,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
32571
32190
  marker('search.filters.summaryLabel.user');
32572
32191
  marker('search.filters.summaryLabel.changeDate');
32573
32192
  marker('search.filters.summaryLabel.resourceCreationRevisionDate');
32193
+ marker('search.filters.summaryLabel.temporalExtent');
32574
32194
  const OPEN_BOUND = '…';
32575
32195
  class SearchFiltersSummaryItemComponent {
32576
32196
  constructor() {
@@ -34134,7 +33754,7 @@ class DataService {
34134
33754
  }));
34135
33755
  }
34136
33756
  async getDownloadLinksFromOgcApiFeatures(ogcApiLink) {
34137
- const collectionInfo = await this.getDownloadUrlsFromOgcApi(ogcApiLink.url.href);
33757
+ const collectionInfo = await this.getDownloadUrlsFromOgcApi(ogcApiLink.url.href, ogcApiLink.name);
34138
33758
  return Object.keys(collectionInfo.bulkDownloadLinks).map((mimeType) => {
34139
33759
  const urlWithoutLimit = new URL(collectionInfo.bulkDownloadLinks[mimeType]);
34140
33760
  urlWithoutLimit.searchParams.delete('limit');
@@ -34147,27 +33767,31 @@ class DataService {
34147
33767
  };
34148
33768
  });
34149
33769
  }
34150
- async getDownloadUrlsFromOgcApi(url) {
33770
+ async getTargetCollectionId(endpoint, collectionId) {
33771
+ const collections = await endpoint.featureCollections;
33772
+ return collections.length === 1 && !collectionId
33773
+ ? collections[0]
33774
+ : collectionId;
33775
+ }
33776
+ async getDownloadUrlsFromOgcApi(url, collectionId) {
34151
33777
  const endpoint = new OgcApiEndpoint(url);
34152
- return await endpoint.featureCollections
34153
- .then((collections) => {
34154
- return endpoint.getCollectionInfo(collections[0]);
34155
- })
34156
- .catch((error) => {
34157
- throw new Error(`ogc.unreachable.unknown`);
34158
- });
33778
+ try {
33779
+ const id = await this.getTargetCollectionId(endpoint, collectionId);
33780
+ return await endpoint.getCollectionInfo(id);
33781
+ }
33782
+ catch {
33783
+ throw new Error('ogc.unreachable.unknown');
33784
+ }
34159
33785
  }
34160
- async getItemsFromOgcApi(url, limit) {
33786
+ async getItemsFromOgcApi(url, collectionId, limit) {
34161
33787
  const endpoint = new OgcApiEndpoint(url);
34162
- return await endpoint.featureCollections
34163
- .then((collections) => {
34164
- return collections.length
34165
- ? endpoint.getCollectionItems(collections[0], limit)
34166
- : null;
34167
- })
34168
- .catch(() => {
34169
- throw new Error(`ogc.unreachable.unknown`);
34170
- });
33788
+ try {
33789
+ const id = await this.getTargetCollectionId(endpoint, collectionId);
33790
+ return await endpoint.getCollectionItems(id, limit);
33791
+ }
33792
+ catch {
33793
+ throw new Error('ogc.unreachable.unknown');
33794
+ }
34171
33795
  }
34172
33796
  async getItemsFromStacApi(url, options) {
34173
33797
  return await StacEndpoint.getItemsFromUrl(url, options)
@@ -34255,7 +33879,7 @@ class DataService {
34255
33879
  }
34256
33880
  else if (link.type === 'service' &&
34257
33881
  link.accessServiceProtocol === 'ogcFeatures') {
34258
- return from(this.getDownloadUrlsFromOgcApi(link.url.href)).pipe(switchMap$1((collectionInfo) => {
33882
+ return from(this.getDownloadUrlsFromOgcApi(link.url.href, link.name)).pipe(switchMap$1((collectionInfo) => {
34259
33883
  const isMimeTypeJson = (mimeType) => {
34260
33884
  return mimeType.toLowerCase().indexOf('json') > -1;
34261
33885
  };
@@ -35199,7 +34823,7 @@ class MdViewFacade {
35199
34823
  if (this.linkClassifier.hasUsage(link, LinkUsage.GEODATA)) {
35200
34824
  if (link.type === 'service' &&
35201
34825
  link.accessServiceProtocol === 'ogcFeatures') {
35202
- return from(this.dataService.getItemsFromOgcApi(link.url.href, 1)).pipe(map$1((collectionRecords) => {
34826
+ return from(this.dataService.getItemsFromOgcApi(link.url.href, link.name, 1)).pipe(map$1((collectionRecords) => {
35203
34827
  return collectionRecords &&
35204
34828
  collectionRecords[0] &&
35205
34829
  collectionRecords[0].geometry
@@ -35282,7 +34906,7 @@ class MdViewEffects {
35282
34906
  }
35283
34907
  return loadFullMetadataSuccess({ full: record });
35284
34908
  }), catchError((error) => of(loadFullMetadataFailure({ otherError: error.message })))));
35285
- this.loadFeatureCatalog$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), filter$1(({ full }) => full !== undefined), switchMap$1(({ full }) => this.recordsRepository.getFeatureCatalog(full)), map$1((featureCatalog) => loadFeatureCatalogSuccess({
34909
+ this.loadFeatureCatalog$ = createEffect(() => this.actions$.pipe(ofType(loadFullMetadataSuccess), filter$1(({ full }) => full !== undefined), switchMap$1(({ full }) => this.recordsRepository.queryLinkedFeatureCatalog(full)), map$1((featureCatalog) => loadFeatureCatalogSuccess({
35286
34910
  datasetCatalog: featureCatalog,
35287
34911
  })), catchError((error) => of(loadFeatureCatalogFailure({
35288
34912
  error: error.message,
@@ -36941,6 +36565,15 @@ const DEFAULT_CONFIGURATION = {
36941
36565
  labelKey: marker('editor.record.form.field.title'),
36942
36566
  },
36943
36567
  },
36568
+ {
36569
+ model: 'flags',
36570
+ modelSpecifier: 'flags:IS_REFERENCE_DATASET',
36571
+ formFieldConfig: {
36572
+ labelKey: marker('editor.record.form.field.flags.IS_REFERENCE_DATASET'),
36573
+ hintKey: marker('editor.record.form.field.hint.flags.IS_REFERENCE_DATASET'),
36574
+ },
36575
+ hidden: '${record.kind != "dataset" || !user.isAdmin}',
36576
+ },
36944
36577
  {
36945
36578
  model: 'abstract',
36946
36579
  formFieldConfig: {
@@ -39825,6 +39458,56 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
39825
39458
  type: Output
39826
39459
  }] } });
39827
39460
 
39461
+ class FormFieldRecordFlagComponent {
39462
+ constructor() {
39463
+ this.flagName = input(...(ngDevMode ? [undefined, { debugName: "flagName" }] : []));
39464
+ this.labelKey = input(...(ngDevMode ? [undefined, { debugName: "labelKey" }] : []));
39465
+ this.hintKey = input(...(ngDevMode ? [undefined, { debugName: "hintKey" }] : []));
39466
+ this.editorFacade = inject(EditorFacade);
39467
+ this.repository = inject(RecordsRepositoryInterface);
39468
+ this.notificationsService = inject(NotificationsService);
39469
+ this.translateService = inject(TranslateService);
39470
+ this.record = toSignal(this.editorFacade.record$);
39471
+ this.recordKind = toSignal(this.editorFacade.record$.pipe(map$1((record) => record.kind)));
39472
+ this.initialValue$ = this.editorFacade.record$.pipe(filter((record) => !!record), switchMap$1((record) => this.repository.getRecordFlag(record.uniqueIdentifier, this.flagName())));
39473
+ }
39474
+ onToggle(enabled) {
39475
+ if (this.record() === null) {
39476
+ return;
39477
+ }
39478
+ this.repository
39479
+ .setRecordFlag(this.record().uniqueIdentifier, this.flagName(), enabled)
39480
+ .subscribe({
39481
+ next: () => {
39482
+ // do nothing
39483
+ },
39484
+ error: (error) => {
39485
+ this.notificationsService.showNotification({
39486
+ type: 'error',
39487
+ title: this.translateService.instant('editor.record.flag.saveError.title'),
39488
+ text: `${this.translateService.instant('editor.record.flag.saveError.body', {
39489
+ recordKind: this.recordKind(),
39490
+ })} ${error.message}`,
39491
+ }, undefined, error);
39492
+ },
39493
+ });
39494
+ }
39495
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldRecordFlagComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
39496
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FormFieldRecordFlagComponent, isStandalone: true, selector: "gn-ui-form-field-record-flag", inputs: { flagName: { classPropertyName: "flagName", publicName: "flagName", isSignal: true, isRequired: false, transformFunction: null }, labelKey: { classPropertyName: "labelKey", publicName: "labelKey", isSignal: true, isRequired: false, transformFunction: null }, hintKey: { classPropertyName: "hintKey", publicName: "hintKey", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<div class=\"flex-1 flex justify-between items-center\">\n <gn-ui-check-toggle\n [label]=\"labelKey() | translate\"\n [value]=\"initialValue$ | async\"\n (toggled)=\"onToggle($event)\"\n [attr.data-cy]=\"'record-flag-toggle-' + flagName()\"\n ></gn-ui-check-toggle>\n\n @if (hintKey()) {\n <ng-icon\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"hintKey() | translate\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n }\n</div>\n", styles: [""], dependencies: [{ kind: "component", type: CheckToggleComponent, selector: "gn-ui-check-toggle", inputs: ["title", "label", "value", "color"], outputs: ["toggled"] }, { kind: "component", type: NgIcon, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], viewProviders: [
39497
+ provideIcons({
39498
+ matHelpOutline,
39499
+ }),
39500
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
39501
+ }
39502
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldRecordFlagComponent, decorators: [{
39503
+ type: Component,
39504
+ args: [{ selector: 'gn-ui-form-field-record-flag', standalone: true, imports: [AsyncPipe, CheckToggleComponent, TranslatePipe, NgIcon, MatTooltip], viewProviders: [
39505
+ provideIcons({
39506
+ matHelpOutline,
39507
+ }),
39508
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"flex-1 flex justify-between items-center\">\n <gn-ui-check-toggle\n [label]=\"labelKey() | translate\"\n [value]=\"initialValue$ | async\"\n (toggled)=\"onToggle($event)\"\n [attr.data-cy]=\"'record-flag-toggle-' + flagName()\"\n ></gn-ui-check-toggle>\n\n @if (hintKey()) {\n <ng-icon\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"hintKey() | translate\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n }\n</div>\n" }]
39509
+ }], propDecorators: { flagName: [{ type: i0.Input, args: [{ isSignal: true, alias: "flagName", required: false }] }], labelKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelKey", required: false }] }], hintKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "hintKey", required: false }] }] } });
39510
+
39828
39511
  class FormFieldComponent {
39829
39512
  constructor() {
39830
39513
  this.valueChange = new EventEmitter();
@@ -39843,6 +39526,7 @@ class FormFieldComponent {
39843
39526
  this.model === 'legalConstraints' ||
39844
39527
  this.model === 'securityConstraints' ||
39845
39528
  this.model === 'otherConstraints' ||
39529
+ this.model === 'flags' ||
39846
39530
  this.componentName === 'form-field-constraints-shortcuts');
39847
39531
  }
39848
39532
  get valueAsString() {
@@ -39882,6 +39566,9 @@ class FormFieldComponent {
39882
39566
  const identifiers = this.value;
39883
39567
  return identifiers?.[0]?.code || '';
39884
39568
  }
39569
+ get recordFlag() {
39570
+ return this.modelSpecifier?.replace(/^flags:/, '');
39571
+ }
39885
39572
  handleResourceIdentifierChange(code) {
39886
39573
  const identifiers = this.value;
39887
39574
  if (!code) {
@@ -39899,7 +39586,7 @@ class FormFieldComponent {
39899
39586
  }
39900
39587
  }
39901
39588
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
39902
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.19", type: FormFieldComponent, isStandalone: true, selector: "gn-ui-form-field", inputs: { uniqueIdentifier: "uniqueIdentifier", recordKind: "recordKind", model: "model", modelSpecifier: "modelSpecifier", componentName: "componentName", config: "config", value: "value" }, outputs: { valueChange: "valueChange" }, providers: [provideIcons({ matEditOutline, matHelpOutline })], viewQueries: [{ propertyName: "titleInput", first: true, predicate: ["titleInput"], descendants: true }], hostDirectives: [{ directive: FieldFocusDirective }], ngImport: i0, template: "<!-- TEMPORARY - disabling the open data switch -->\n<!-- <ng-container *ngIf=\"model === 'licenses'\">\n <gn-ui-form-field-open-data\n [value]=\"valueAsConstraints\"\n (valueChange)=\"valueChange.emit($event)\"\n (openDataChange)=\"toggleIsOpenData($event)\"\n ></gn-ui-form-field-open-data>\n</ng-container> -->\n<div class=\"flex flex-col h-full\">\n <ng-container *ngIf=\"withoutWrapper; else withGenericWrapper\">\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </ng-container>\n <ng-template #withGenericWrapper>\n <gn-ui-form-field-wrapper\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n >\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </gn-ui-form-field-wrapper>\n </ng-template>\n</div>\n\n<ng-template #fieldContent>\n <ng-container [ngSwitch]=\"model\">\n <ng-container *ngSwitchCase=\"'title'\">\n <div class=\"flex flex-row flex-start items-center gap-3 mb-[12px]\">\n <textarea\n #titleInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"1\"\n data-test=\"recordTitleInput\"\n class=\"grow font-title text-3xl font-normal overflow-hidden text-black/80\"\n [value]=\"valueAsString\"\n (change)=\"valueChange.emit($event.target.value)\"\n [placeholder]=\"\n 'editor.record.form.field.title.placeholder'\n | translate: { recordKind }\n \"\n ></textarea>\n <div class=\"flex flex-row justify-between self-start mt-0.5\">\n <ng-icon\n name=\"matEditOutline\"\n size=\"16\"\n class=\"m-2 cursor-pointer\"\n (click)=\"focusTitleInput()\"\n ></ng-icon>\n <ng-icon\n *ngIf=\"config.hintKey\"\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"config.hintKey! | translate: { recordKind }\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'abstract'\">\n <gn-ui-form-field-rich\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n [value]=\"valueAsString\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-rich>\n </ng-container>\n <ng-container *ngSwitchCase=\"'overviews'\">\n <gn-ui-form-field-overviews\n [metadataUuid]=\"uniqueIdentifier\"\n [recordKind]=\"recordKind\"\n [value]=\"valueAsOverviews\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-overviews>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceIdentifiers'\">\n <gn-ui-form-field-simple\n [type]=\"'text'\"\n [value]=\"valueAsResourceIdentifierCode\"\n (valueChange)=\"handleResourceIdentifierChange($event)\"\n ></gn-ui-form-field-simple>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceCreated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceUpdated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'updateFrequency'\">\n <gn-ui-form-field-update-frequency\n [value]=\"valueAsUpdateFrequency\"\n (valueChange)=\"valueChange.emit($event)\"\n [recordKind]=\"recordKind\"\n ></gn-ui-form-field-update-frequency>\n </ng-container>\n <ng-container *ngSwitchCase=\"'associatedRecords'\">\n <gn-ui-form-field-associated-records\n [value]=\"valueAsAssociatedRecords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-associated-records>\n </ng-container>\n <ng-container *ngSwitchCase=\"'temporalExtents'\">\n <gn-ui-form-field-temporal-extents\n [value]=\"valueAsTemporalExtents\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-temporal-extents>\n </ng-container>\n <ng-container *ngSwitchCase=\"'spatialExtents'\">\n <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>\n </ng-container>\n <ng-container *ngSwitchCase=\"'keywords'\">\n <gn-ui-form-field-keywords\n [value]=\"valueAsKeywords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-keywords>\n </ng-container>\n <ng-container *ngSwitchCase=\"'topics'\">\n <gn-ui-form-field-topics\n [value]=\"valueAsTopics\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-topics>\n </ng-container>\n <ng-container *ngSwitchCase=\"'licenses'\">\n <gn-ui-form-field-license\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [recordLicences]=\"valueAsConstraints\"\n (recordLicencesChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-license>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'legalConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'securityConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'otherConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container\n ></ng-container>\n <ng-template #formFieldConstraints>\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints\n ></ng-template>\n\n <ng-container *ngSwitchCase=\"'contactsForResource'\">\n <gn-ui-form-field-contacts-for-resource\n [value]=\"valueAsIndividuals\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts-for-resource>\n </ng-container>\n <ng-container *ngSwitchCase=\"'contacts'\">\n <gn-ui-form-field-contacts\n [value]=\"valueAsIndividuals\"\n [modelSpecifier]=\"modelSpecifier\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:!link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-link-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-link-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-single-link-resource\n *ngIf=\"modelSpecifier === 'onlineResourceType:singleLink'\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-single-link-resource>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"!model\">\n <ng-container [ngSwitch]=\"componentName\">\n <ng-container *ngSwitchCase=\"'form-field-constraints-shortcuts'\">\n <gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'form-field-spatial-toggle'\">\n <gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>\n </ng-container>\n </ng-container>\n </ng-container>\n</ng-template>\n", styles: [":host{scroll-margin-top:90px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: FormFieldWrapperComponent, selector: "gn-ui-form-field-wrapper", inputs: ["label", "hint"] }, { kind: "component", type: FormFieldLicenseComponent, selector: "gn-ui-form-field-license", inputs: ["label", "recordLicences"], outputs: ["recordLicencesChange"] }, { kind: "component", type: FormFieldDateComponent, selector: "gn-ui-form-field-date", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldUpdateFrequencyComponent, selector: "gn-ui-form-field-update-frequency", inputs: ["value", "recordKind"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldAssociatedRecordsComponent, selector: "gn-ui-form-field-associated-records", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldTemporalExtentsComponent, selector: "gn-ui-form-field-temporal-extents", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldSimpleComponent, selector: "gn-ui-form-field-simple", inputs: ["type", "readonly", "invalid", "placeholder", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldRichComponent, selector: "gn-ui-form-field-rich", inputs: ["label", "hint", "placeholder", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldSpatialExtentComponent, selector: "gn-ui-form-field-spatial-extent" }, { kind: "component", type: FormFieldKeywordsComponent, selector: "gn-ui-form-field-keywords", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOverviewsComponent, selector: "gn-ui-form-field-overviews", inputs: ["metadataUuid", "recordKind", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldContactsForResourceComponent, selector: "gn-ui-form-field-contacts-for-resource", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineResourcesComponent, selector: "gn-ui-form-field-online-resources", inputs: ["metadataUuid", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineLinkResourcesComponent, selector: "gn-ui-form-field-online-link-resources", inputs: ["metadataUuid", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineSingleLinkResourceComponent, selector: "gn-ui-form-field-online-single-link-resource", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldContactsComponent, selector: "gn-ui-form-field-contacts", inputs: ["value", "modelSpecifier"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldConstraintsComponent, selector: "gn-ui-form-field-constraints", inputs: ["label", "value", "constraintType"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldConstraintsShortcutsComponent, selector: "gn-ui-form-field-constraints-shortcuts" }, { kind: "component", type: FormFieldSpatialToggleComponent, selector: "gn-ui-form-field-spatial-toggle" }, { kind: "component", type: FormFieldTopicsComponent, selector: "gn-ui-form-field-topics", inputs: ["value"], outputs: ["valueChange"] }, { kind: "ngmodule", type: TextFieldModule }, { kind: "directive", type: i4$1.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
39589
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.19", type: FormFieldComponent, isStandalone: true, selector: "gn-ui-form-field", inputs: { uniqueIdentifier: "uniqueIdentifier", recordKind: "recordKind", model: "model", modelSpecifier: "modelSpecifier", componentName: "componentName", config: "config", value: "value" }, outputs: { valueChange: "valueChange" }, providers: [provideIcons({ matEditOutline, matHelpOutline })], viewQueries: [{ propertyName: "titleInput", first: true, predicate: ["titleInput"], descendants: true }], hostDirectives: [{ directive: FieldFocusDirective }], ngImport: i0, template: "<!-- TEMPORARY - disabling the open data switch -->\n<!-- <ng-container *ngIf=\"model === 'licenses'\">\n <gn-ui-form-field-open-data\n [value]=\"valueAsConstraints\"\n (valueChange)=\"valueChange.emit($event)\"\n (openDataChange)=\"toggleIsOpenData($event)\"\n ></gn-ui-form-field-open-data>\n</ng-container> -->\n<div class=\"flex flex-col h-full\">\n @if (withoutWrapper) {\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n } @else {\n <gn-ui-form-field-wrapper\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n >\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </gn-ui-form-field-wrapper>\n }\n</div>\n\n<ng-template #fieldContent>\n @switch (model) {\n @case ('title') {\n <div class=\"flex flex-row flex-start items-center gap-3\">\n <textarea\n #titleInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"1\"\n data-test=\"recordTitleInput\"\n class=\"grow font-title text-3xl font-normal overflow-hidden text-black/80\"\n [value]=\"valueAsString\"\n (change)=\"valueChange.emit($event.target.value)\"\n [placeholder]=\"\n 'editor.record.form.field.title.placeholder'\n | translate: { recordKind }\n \"\n ></textarea>\n <div class=\"flex flex-row justify-between self-start mt-0.5\">\n <ng-icon\n name=\"matEditOutline\"\n size=\"16\"\n class=\"m-2 cursor-pointer\"\n (click)=\"focusTitleInput()\"\n ></ng-icon>\n @if (config.hintKey) {\n <ng-icon\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"config.hintKey! | translate: { recordKind }\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n }\n </div>\n </div>\n }\n @case ('abstract') {\n <gn-ui-form-field-rich\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n [value]=\"valueAsString\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-rich>\n }\n @case ('overviews') {\n <gn-ui-form-field-overviews\n [metadataUuid]=\"uniqueIdentifier\"\n [recordKind]=\"recordKind\"\n [value]=\"valueAsOverviews\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-overviews>\n }\n @case ('resourceIdentifiers') {\n <gn-ui-form-field-simple\n [type]=\"'text'\"\n [value]=\"valueAsResourceIdentifierCode\"\n (valueChange)=\"handleResourceIdentifierChange($event)\"\n ></gn-ui-form-field-simple>\n }\n @case ('resourceCreated') {\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n }\n @case ('resourceUpdated') {\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n }\n @case ('updateFrequency') {\n <gn-ui-form-field-update-frequency\n [value]=\"valueAsUpdateFrequency\"\n (valueChange)=\"valueChange.emit($event)\"\n [recordKind]=\"recordKind\"\n ></gn-ui-form-field-update-frequency>\n }\n @case ('associatedRecords') {\n <gn-ui-form-field-associated-records\n [value]=\"valueAsAssociatedRecords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-associated-records>\n }\n @case ('temporalExtents') {\n <gn-ui-form-field-temporal-extents\n [value]=\"valueAsTemporalExtents\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-temporal-extents>\n }\n @case ('spatialExtents') {\n <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>\n }\n @case ('keywords') {\n <gn-ui-form-field-keywords\n [value]=\"valueAsKeywords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-keywords>\n }\n @case ('topics') {\n <gn-ui-form-field-topics\n [value]=\"valueAsTopics\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-topics>\n }\n @case ('licenses') {\n <gn-ui-form-field-license\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [recordLicences]=\"valueAsConstraints\"\n (recordLicencesChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-license>\n }\n\n <!-- TODO: merge these cases together when migrated to angular 21 -->\n @case ('legalConstraints') {\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints>\n }\n @case ('securityConstraints') {\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints>\n }\n @case ('otherConstraints') {\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints>\n }\n\n @case ('contactsForResource') {\n <gn-ui-form-field-contacts-for-resource\n [value]=\"valueAsIndividuals\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts-for-resource>\n }\n @case ('contacts') {\n <gn-ui-form-field-contacts\n [value]=\"valueAsIndividuals\"\n [modelSpecifier]=\"modelSpecifier\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts>\n }\n @case ('onlineResources') {\n @if (modelSpecifier === 'onlineResourceType:!link') {\n <gn-ui-form-field-online-resources\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-resources>\n } @else if (modelSpecifier === 'onlineResourceType:link') {\n <gn-ui-form-field-online-link-resources\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-link-resources>\n } @else if (modelSpecifier === 'onlineResourceType:singleLink') {\n <gn-ui-form-field-online-single-link-resource\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-single-link-resource>\n }\n }\n @case ('flags') {\n <gn-ui-form-field-record-flag\n [flagName]=\"recordFlag\"\n [labelKey]=\"config.labelKey\"\n [hintKey]=\"config.hintKey\"\n ></gn-ui-form-field-record-flag>\n }\n }\n\n @if (!model) {\n @switch (componentName) {\n @case ('form-field-constraints-shortcuts') {\n <gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>\n }\n @case ('form-field-spatial-toggle') {\n <gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>\n }\n }\n }\n</ng-template>\n", styles: [":host{scroll-margin-top:90px}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i1$5.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: FormFieldWrapperComponent, selector: "gn-ui-form-field-wrapper", inputs: ["label", "hint"] }, { kind: "component", type: FormFieldLicenseComponent, selector: "gn-ui-form-field-license", inputs: ["label", "recordLicences"], outputs: ["recordLicencesChange"] }, { kind: "component", type: FormFieldDateComponent, selector: "gn-ui-form-field-date", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldUpdateFrequencyComponent, selector: "gn-ui-form-field-update-frequency", inputs: ["value", "recordKind"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldAssociatedRecordsComponent, selector: "gn-ui-form-field-associated-records", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldTemporalExtentsComponent, selector: "gn-ui-form-field-temporal-extents", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldSimpleComponent, selector: "gn-ui-form-field-simple", inputs: ["type", "readonly", "invalid", "placeholder", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldRichComponent, selector: "gn-ui-form-field-rich", inputs: ["label", "hint", "placeholder", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldSpatialExtentComponent, selector: "gn-ui-form-field-spatial-extent" }, { kind: "component", type: FormFieldKeywordsComponent, selector: "gn-ui-form-field-keywords", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOverviewsComponent, selector: "gn-ui-form-field-overviews", inputs: ["metadataUuid", "recordKind", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldContactsForResourceComponent, selector: "gn-ui-form-field-contacts-for-resource", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineResourcesComponent, selector: "gn-ui-form-field-online-resources", inputs: ["metadataUuid", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineLinkResourcesComponent, selector: "gn-ui-form-field-online-link-resources", inputs: ["metadataUuid", "value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldOnlineSingleLinkResourceComponent, selector: "gn-ui-form-field-online-single-link-resource", inputs: ["value"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldContactsComponent, selector: "gn-ui-form-field-contacts", inputs: ["value", "modelSpecifier"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldConstraintsComponent, selector: "gn-ui-form-field-constraints", inputs: ["label", "value", "constraintType"], outputs: ["valueChange"] }, { kind: "component", type: FormFieldConstraintsShortcutsComponent, selector: "gn-ui-form-field-constraints-shortcuts" }, { kind: "component", type: FormFieldSpatialToggleComponent, selector: "gn-ui-form-field-spatial-toggle" }, { kind: "component", type: FormFieldTopicsComponent, selector: "gn-ui-form-field-topics", inputs: ["value"], outputs: ["valueChange"] }, { kind: "ngmodule", type: TextFieldModule }, { kind: "directive", type: i4$1.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "component", type: NgIconComponent, selector: "ng-icon", inputs: ["name", "svg", "size", "strokeWidth", "color"] }, { kind: "component", type: FormFieldRecordFlagComponent, selector: "gn-ui-form-field-record-flag", inputs: ["flagName", "labelKey", "hintKey"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
39903
39590
  }
39904
39591
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: FormFieldComponent, decorators: [{
39905
39592
  type: Component,
@@ -39929,7 +39616,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
39929
39616
  FormFieldTopicsComponent,
39930
39617
  TextFieldModule,
39931
39618
  NgIconComponent,
39932
- ], providers: [provideIcons({ matEditOutline, matHelpOutline })], hostDirectives: [FieldFocusDirective], template: "<!-- TEMPORARY - disabling the open data switch -->\n<!-- <ng-container *ngIf=\"model === 'licenses'\">\n <gn-ui-form-field-open-data\n [value]=\"valueAsConstraints\"\n (valueChange)=\"valueChange.emit($event)\"\n (openDataChange)=\"toggleIsOpenData($event)\"\n ></gn-ui-form-field-open-data>\n</ng-container> -->\n<div class=\"flex flex-col h-full\">\n <ng-container *ngIf=\"withoutWrapper; else withGenericWrapper\">\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </ng-container>\n <ng-template #withGenericWrapper>\n <gn-ui-form-field-wrapper\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n >\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </gn-ui-form-field-wrapper>\n </ng-template>\n</div>\n\n<ng-template #fieldContent>\n <ng-container [ngSwitch]=\"model\">\n <ng-container *ngSwitchCase=\"'title'\">\n <div class=\"flex flex-row flex-start items-center gap-3 mb-[12px]\">\n <textarea\n #titleInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"1\"\n data-test=\"recordTitleInput\"\n class=\"grow font-title text-3xl font-normal overflow-hidden text-black/80\"\n [value]=\"valueAsString\"\n (change)=\"valueChange.emit($event.target.value)\"\n [placeholder]=\"\n 'editor.record.form.field.title.placeholder'\n | translate: { recordKind }\n \"\n ></textarea>\n <div class=\"flex flex-row justify-between self-start mt-0.5\">\n <ng-icon\n name=\"matEditOutline\"\n size=\"16\"\n class=\"m-2 cursor-pointer\"\n (click)=\"focusTitleInput()\"\n ></ng-icon>\n <ng-icon\n *ngIf=\"config.hintKey\"\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"config.hintKey! | translate: { recordKind }\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n </div>\n </div>\n </ng-container>\n <ng-container *ngSwitchCase=\"'abstract'\">\n <gn-ui-form-field-rich\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n [value]=\"valueAsString\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-rich>\n </ng-container>\n <ng-container *ngSwitchCase=\"'overviews'\">\n <gn-ui-form-field-overviews\n [metadataUuid]=\"uniqueIdentifier\"\n [recordKind]=\"recordKind\"\n [value]=\"valueAsOverviews\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-overviews>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceIdentifiers'\">\n <gn-ui-form-field-simple\n [type]=\"'text'\"\n [value]=\"valueAsResourceIdentifierCode\"\n (valueChange)=\"handleResourceIdentifierChange($event)\"\n ></gn-ui-form-field-simple>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceCreated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'resourceUpdated'\">\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n </ng-container>\n <ng-container *ngSwitchCase=\"'updateFrequency'\">\n <gn-ui-form-field-update-frequency\n [value]=\"valueAsUpdateFrequency\"\n (valueChange)=\"valueChange.emit($event)\"\n [recordKind]=\"recordKind\"\n ></gn-ui-form-field-update-frequency>\n </ng-container>\n <ng-container *ngSwitchCase=\"'associatedRecords'\">\n <gn-ui-form-field-associated-records\n [value]=\"valueAsAssociatedRecords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-associated-records>\n </ng-container>\n <ng-container *ngSwitchCase=\"'temporalExtents'\">\n <gn-ui-form-field-temporal-extents\n [value]=\"valueAsTemporalExtents\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-temporal-extents>\n </ng-container>\n <ng-container *ngSwitchCase=\"'spatialExtents'\">\n <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>\n </ng-container>\n <ng-container *ngSwitchCase=\"'keywords'\">\n <gn-ui-form-field-keywords\n [value]=\"valueAsKeywords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-keywords>\n </ng-container>\n <ng-container *ngSwitchCase=\"'topics'\">\n <gn-ui-form-field-topics\n [value]=\"valueAsTopics\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-topics>\n </ng-container>\n <ng-container *ngSwitchCase=\"'licenses'\">\n <gn-ui-form-field-license\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [recordLicences]=\"valueAsConstraints\"\n (recordLicencesChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-license>\n </ng-container>\n\n <ng-container *ngSwitchCase=\"'legalConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'securityConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container>\n </ng-container>\n <ng-container *ngSwitchCase=\"'otherConstraints'\">\n <ng-container *ngTemplateOutlet=\"formFieldConstraints\"></ng-container\n ></ng-container>\n <ng-template #formFieldConstraints>\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints\n ></ng-template>\n\n <ng-container *ngSwitchCase=\"'contactsForResource'\">\n <gn-ui-form-field-contacts-for-resource\n [value]=\"valueAsIndividuals\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts-for-resource>\n </ng-container>\n <ng-container *ngSwitchCase=\"'contacts'\">\n <gn-ui-form-field-contacts\n [value]=\"valueAsIndividuals\"\n [modelSpecifier]=\"modelSpecifier\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:!link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-link-resources\n *ngIf=\"modelSpecifier === 'onlineResourceType:link'\"\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-link-resources>\n </ng-container>\n <ng-container *ngSwitchCase=\"'onlineResources'\">\n <gn-ui-form-field-online-single-link-resource\n *ngIf=\"modelSpecifier === 'onlineResourceType:singleLink'\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-single-link-resource>\n </ng-container>\n </ng-container>\n\n <ng-container *ngIf=\"!model\">\n <ng-container [ngSwitch]=\"componentName\">\n <ng-container *ngSwitchCase=\"'form-field-constraints-shortcuts'\">\n <gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>\n </ng-container>\n <ng-container *ngSwitchCase=\"'form-field-spatial-toggle'\">\n <gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>\n </ng-container>\n </ng-container>\n </ng-container>\n</ng-template>\n", styles: [":host{scroll-margin-top:90px}\n"] }]
39619
+ FormFieldRecordFlagComponent,
39620
+ ], providers: [provideIcons({ matEditOutline, matHelpOutline })], hostDirectives: [FieldFocusDirective], template: "<!-- TEMPORARY - disabling the open data switch -->\n<!-- <ng-container *ngIf=\"model === 'licenses'\">\n <gn-ui-form-field-open-data\n [value]=\"valueAsConstraints\"\n (valueChange)=\"valueChange.emit($event)\"\n (openDataChange)=\"toggleIsOpenData($event)\"\n ></gn-ui-form-field-open-data>\n</ng-container> -->\n<div class=\"flex flex-col h-full\">\n @if (withoutWrapper) {\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n } @else {\n <gn-ui-form-field-wrapper\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n >\n <ng-container *ngTemplateOutlet=\"fieldContent\"></ng-container>\n </gn-ui-form-field-wrapper>\n }\n</div>\n\n<ng-template #fieldContent>\n @switch (model) {\n @case ('title') {\n <div class=\"flex flex-row flex-start items-center gap-3\">\n <textarea\n #titleInput\n cdkTextareaAutosize\n #autosize=\"cdkTextareaAutosize\"\n cdkAutosizeMinRows=\"1\"\n data-test=\"recordTitleInput\"\n class=\"grow font-title text-3xl font-normal overflow-hidden text-black/80\"\n [value]=\"valueAsString\"\n (change)=\"valueChange.emit($event.target.value)\"\n [placeholder]=\"\n 'editor.record.form.field.title.placeholder'\n | translate: { recordKind }\n \"\n ></textarea>\n <div class=\"flex flex-row justify-between self-start mt-0.5\">\n <ng-icon\n name=\"matEditOutline\"\n size=\"16\"\n class=\"m-2 cursor-pointer\"\n (click)=\"focusTitleInput()\"\n ></ng-icon>\n @if (config.hintKey) {\n <ng-icon\n name=\"matHelpOutline\"\n size=\"16\"\n class=\"m-2\"\n [matTooltip]=\"config.hintKey! | translate: { recordKind }\"\n matTooltipPosition=\"above\"\n ></ng-icon>\n }\n </div>\n </div>\n }\n @case ('abstract') {\n <gn-ui-form-field-rich\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [hint]=\"config.hintKey! | translate: { recordKind }\"\n [value]=\"valueAsString\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-rich>\n }\n @case ('overviews') {\n <gn-ui-form-field-overviews\n [metadataUuid]=\"uniqueIdentifier\"\n [recordKind]=\"recordKind\"\n [value]=\"valueAsOverviews\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-overviews>\n }\n @case ('resourceIdentifiers') {\n <gn-ui-form-field-simple\n [type]=\"'text'\"\n [value]=\"valueAsResourceIdentifierCode\"\n (valueChange)=\"handleResourceIdentifierChange($event)\"\n ></gn-ui-form-field-simple>\n }\n @case ('resourceCreated') {\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n }\n @case ('resourceUpdated') {\n <gn-ui-form-field-date\n [value]=\"valueAsDate\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-date>\n }\n @case ('updateFrequency') {\n <gn-ui-form-field-update-frequency\n [value]=\"valueAsUpdateFrequency\"\n (valueChange)=\"valueChange.emit($event)\"\n [recordKind]=\"recordKind\"\n ></gn-ui-form-field-update-frequency>\n }\n @case ('associatedRecords') {\n <gn-ui-form-field-associated-records\n [value]=\"valueAsAssociatedRecords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-associated-records>\n }\n @case ('temporalExtents') {\n <gn-ui-form-field-temporal-extents\n [value]=\"valueAsTemporalExtents\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-temporal-extents>\n }\n @case ('spatialExtents') {\n <gn-ui-form-field-spatial-extent></gn-ui-form-field-spatial-extent>\n }\n @case ('keywords') {\n <gn-ui-form-field-keywords\n [value]=\"valueAsKeywords\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-keywords>\n }\n @case ('topics') {\n <gn-ui-form-field-topics\n [value]=\"valueAsTopics\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-topics>\n }\n @case ('licenses') {\n <gn-ui-form-field-license\n [label]=\"config.labelKey! | translate: { recordKind }\"\n [recordLicences]=\"valueAsConstraints\"\n (recordLicencesChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-license>\n }\n\n <!-- TODO: merge these cases together when migrated to angular 21 -->\n @case ('legalConstraints') {\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints>\n }\n @case ('securityConstraints') {\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints>\n }\n @case ('otherConstraints') {\n <gn-ui-form-field-constraints\n [label]=\"config.labelKey\"\n [value]=\"valueAsConstraints\"\n [constraintType]=\"model\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-constraints>\n }\n\n @case ('contactsForResource') {\n <gn-ui-form-field-contacts-for-resource\n [value]=\"valueAsIndividuals\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts-for-resource>\n }\n @case ('contacts') {\n <gn-ui-form-field-contacts\n [value]=\"valueAsIndividuals\"\n [modelSpecifier]=\"modelSpecifier\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-contacts>\n }\n @case ('onlineResources') {\n @if (modelSpecifier === 'onlineResourceType:!link') {\n <gn-ui-form-field-online-resources\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-resources>\n } @else if (modelSpecifier === 'onlineResourceType:link') {\n <gn-ui-form-field-online-link-resources\n [metadataUuid]=\"uniqueIdentifier\"\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-link-resources>\n } @else if (modelSpecifier === 'onlineResourceType:singleLink') {\n <gn-ui-form-field-online-single-link-resource\n [value]=\"valueAsOnlineResources\"\n (valueChange)=\"valueChange.emit($event)\"\n ></gn-ui-form-field-online-single-link-resource>\n }\n }\n @case ('flags') {\n <gn-ui-form-field-record-flag\n [flagName]=\"recordFlag\"\n [labelKey]=\"config.labelKey\"\n [hintKey]=\"config.hintKey\"\n ></gn-ui-form-field-record-flag>\n }\n }\n\n @if (!model) {\n @switch (componentName) {\n @case ('form-field-constraints-shortcuts') {\n <gn-ui-form-field-constraints-shortcuts></gn-ui-form-field-constraints-shortcuts>\n }\n @case ('form-field-spatial-toggle') {\n <gn-ui-form-field-spatial-toggle></gn-ui-form-field-spatial-toggle>\n }\n }\n }\n</ng-template>\n", styles: [":host{scroll-margin-top:90px}\n"] }]
39933
39621
  }], propDecorators: { uniqueIdentifier: [{
39934
39622
  type: Input
39935
39623
  }], recordKind: [{
@@ -39960,9 +39648,13 @@ const TOKEN_OPERATOR_LOGICAL = ['==', '!='];
39960
39648
  const TOKEN_STRING_LITERAL = ["'", '"'];
39961
39649
  const TOKEN_GROUP_START = '(';
39962
39650
  const TOKEN_GROUP_END = ')';
39651
+ const TOKEN_OPERATOR_BOOLEAN = ['&&', '||'];
39652
+ const TOKEN_OPERATOR_NOT = '!';
39963
39653
  // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence
39964
39654
  const OPERATORS_BY_PRECEDENCE = [
39965
39655
  [TOKEN_OPERATOR_TERNARY_FIRST, TOKEN_OPERATOR_TERNARY_SECOND],
39656
+ TOKEN_OPERATOR_BOOLEAN,
39657
+ [TOKEN_OPERATOR_NOT],
39966
39658
  TOKEN_OPERATOR_LOGICAL,
39967
39659
  ];
39968
39660
  const ALL_OPERATORS = OPERATORS_BY_PRECEDENCE.flat();
@@ -40072,6 +39764,16 @@ function evaluateInternal(expression, currentContext) {
40072
39764
  pos++;
40073
39765
  continue;
40074
39766
  }
39767
+ // BOOLEAN LITERAL
39768
+ const isBooleanLiteral = readNext(expression, pos, 4) === 'true' ||
39769
+ readNext(expression, pos, 5) === 'false';
39770
+ if (isBooleanLiteral) {
39771
+ const literal = readNext(expression, pos, 4) === 'true' ? 'true' : 'false';
39772
+ pos += literal.length;
39773
+ const booleanLiteral = literal === 'true';
39774
+ currentEvaluator = () => booleanLiteral;
39775
+ continue;
39776
+ }
40075
39777
  // SYMBOL (NAME)
40076
39778
  const isSymbol = /[a-zA-Z]/.test(readNext(expression, pos));
40077
39779
  if (isSymbol) {
@@ -40162,6 +39864,35 @@ function evaluateInternal(expression, currentContext) {
40162
39864
  };
40163
39865
  continue;
40164
39866
  }
39867
+ // BOOLEAN OPERATORS
39868
+ const isBooleanOperator = TOKEN_OPERATOR_BOOLEAN.some((token) => readNext(expression, pos, token.length) === token);
39869
+ if (isBooleanOperator) {
39870
+ const matchingOperator = TOKEN_OPERATOR_BOOLEAN.find((token) => readNext(expression, pos, token.length) === token);
39871
+ const isAnd = matchingOperator === '&&';
39872
+ pos += matchingOperator.length;
39873
+ const leftEvaluator = currentEvaluator;
39874
+ const rightExpression = readUntilNextOperator(expression, pos, matchingOperator);
39875
+ pos += rightExpression.length;
39876
+ const rightEvaluator = evaluateInternal(rightExpression, currentContext).evaluator;
39877
+ currentEvaluator = (context) => {
39878
+ return isAnd
39879
+ ? Boolean(leftEvaluator(context) && rightEvaluator(context))
39880
+ : Boolean(leftEvaluator(context) || rightEvaluator(context));
39881
+ };
39882
+ continue;
39883
+ }
39884
+ // PREFIX OPERATORS
39885
+ const isNotOperator = readNext(expression, pos) === TOKEN_OPERATOR_NOT;
39886
+ if (isNotOperator) {
39887
+ pos++;
39888
+ const operandExpression = readUntilNextOperator(expression, pos, TOKEN_OPERATOR_NOT);
39889
+ pos += operandExpression.length;
39890
+ const operandEvaluator = evaluateInternal(operandExpression, currentContext).evaluator;
39891
+ currentEvaluator = (context) => {
39892
+ return !operandEvaluator(context);
39893
+ };
39894
+ continue;
39895
+ }
40165
39896
  // TERNARY OPERATOR
40166
39897
  const isTernary = readNext(expression, pos) === TOKEN_OPERATOR_TERNARY_FIRST;
40167
39898
  if (isTernary) {
@@ -40232,6 +39963,7 @@ class RecordFormComponent {
40232
39963
  constructor() {
40233
39964
  this.facade = inject(EditorFacade);
40234
39965
  this.notifications = inject(NotificationsService);
39966
+ this.platform = inject(PlatformServiceInterface);
40235
39967
  this.subscription = new Subscription();
40236
39968
  this.recordUniqueIdentifier$ = this.facade.record$.pipe(map$2((record) => record.uniqueIdentifier));
40237
39969
  this.recordKind$ = this.facade.record$.pipe(map$2((record) => record.kind));
@@ -40242,6 +39974,8 @@ class RecordFormComponent {
40242
39974
  this.formFields = viewChildren(FormFieldComponent, ...(ngDevMode ? [{ debugName: "formFields" }] : []));
40243
39975
  this.sectionFocusDirectives = viewChildren('sectionFocus', ...(ngDevMode ? [{ debugName: "sectionFocusDirectives" }] : []));
40244
39976
  this.recordSignal = toSignal(this.facade.record$, { requireSync: true });
39977
+ this.userSignal = toSignal(this.platform.getMe());
39978
+ this.isAdminSignal = toSignal(this.platform.isAdministrator());
40245
39979
  this.expressionCache = new Map();
40246
39980
  }
40247
39981
  focusField(model, sectionIndex) {
@@ -40266,7 +40000,7 @@ class RecordFormComponent {
40266
40000
  this.subscription.unsubscribe();
40267
40001
  }
40268
40002
  handleFieldValueChange(model, newValue) {
40269
- if (!model) {
40003
+ if (!model || model === 'flags') {
40270
40004
  return;
40271
40005
  }
40272
40006
  this.facade.updateRecordField(model, newValue);
@@ -40309,7 +40043,15 @@ ${errors.map((err) => `> ${err}`).join('\n')}`);
40309
40043
  text: 'An error happened while evaluating an expression inside the editor configuration; open the developer console for more information',
40310
40044
  });
40311
40045
  }
40312
- this.expressionCache.set(expression, computed(() => evaluator({ globals: { record: this.recordSignal() } })));
40046
+ this.expressionCache.set(expression, computed(() => evaluator({
40047
+ globals: {
40048
+ record: this.recordSignal(),
40049
+ user: {
40050
+ ...this.userSignal(),
40051
+ isAdmin: this.isAdminSignal(),
40052
+ },
40053
+ },
40054
+ })));
40313
40055
  return this.expressionCache.get(expression);
40314
40056
  }
40315
40057
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.19", ngImport: i0, type: RecordFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
@@ -40916,6 +40658,638 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.19", ngImpo
40916
40658
  args: ['gnUiSearchRouterContainer']
40917
40659
  }] } });
40918
40660
 
40661
+ const flatten = (base, obj, keepLevel = false) => Object.keys(obj).reduce((prev, curr) => {
40662
+ const path = base ? `${base}.${curr}` : curr;
40663
+ const val = obj[curr];
40664
+ if (keepLevel) {
40665
+ return { ...prev, [path]: flatten('', val) };
40666
+ }
40667
+ else if (typeof val === 'object' && !Array.isArray(val)) {
40668
+ return {
40669
+ ...prev,
40670
+ ...flatten(path, val),
40671
+ };
40672
+ }
40673
+ else {
40674
+ return { ...prev, [path]: val };
40675
+ }
40676
+ }, {});
40677
+ const checkKeys = (input, mandatory, optional) => {
40678
+ const keys = Object.keys(input);
40679
+ const missing = mandatory.filter((key) => keys.indexOf(key) === -1);
40680
+ const unrecognized = keys.filter((key) => mandatory.indexOf(key) === -1 && optional.indexOf(key) === -1);
40681
+ return {
40682
+ missing,
40683
+ unrecognized,
40684
+ };
40685
+ };
40686
+ /**
40687
+ * Only keeps recognized keys, flatten nested values (to allow having "." in keys),
40688
+ * pushes warnings and errors to the given arrays; returns null in case of error
40689
+ */
40690
+ function parseConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
40691
+ if (typeof fullConfigObj[sectionName] !== 'object') {
40692
+ if (mandatoryKeys.length === 0)
40693
+ return null;
40694
+ outErrors.push(`The [${sectionName}] mandatory section is missing.`);
40695
+ return null;
40696
+ }
40697
+ const sectionConf = fullConfigObj[sectionName];
40698
+ const keysCheck = checkKeys(sectionConf, mandatoryKeys, optionalKeys);
40699
+ if (keysCheck.missing.length) {
40700
+ // note: this is not thrown to allow merging several Errors down the line
40701
+ outErrors.push(`In the [${sectionName}] section: ${keysCheck.missing.join(', ')}`);
40702
+ return null;
40703
+ }
40704
+ else if (keysCheck.unrecognized.length) {
40705
+ outWarnings.push(`In the [${sectionName}] section: ${keysCheck.unrecognized.join(', ')}`);
40706
+ keysCheck.unrecognized.forEach((key) => delete sectionConf[key]);
40707
+ }
40708
+ return sectionConf;
40709
+ }
40710
+ /**
40711
+ * Same as parseConfigSection but keeps all keys, recognized or not
40712
+ * Also the first level is the language code (e.g. 'en')
40713
+ * This is optional
40714
+ */
40715
+ function parseTranslationsConfigSection(fullConfigObj, sectionName) {
40716
+ if (typeof fullConfigObj[sectionName] !== 'object') {
40717
+ return {};
40718
+ }
40719
+ return flatten('', fullConfigObj[sectionName], true);
40720
+ }
40721
+ /**
40722
+ * Same as parseConfigSection but handles an array of configs; this is
40723
+ * considered optional; returns null in case of error in at least one of
40724
+ * the sections
40725
+ */
40726
+ function parseMultiConfigSection(fullConfigObj, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors) {
40727
+ const sections = fullConfigObj[sectionName];
40728
+ if (!sections) {
40729
+ return [];
40730
+ }
40731
+ if (!Array.isArray(sections)) {
40732
+ outErrors.push(`Expected [[${sectionName}]] to be an array of sections.`);
40733
+ return null;
40734
+ }
40735
+ const result = sections.map((section) => parseConfigSection({ [sectionName]: section }, sectionName, mandatoryKeys, optionalKeys, outWarnings, outErrors));
40736
+ if (result.some((r) => r === null)) {
40737
+ return null;
40738
+ }
40739
+ return result;
40740
+ }
40741
+ function checkMetadataLanguage(parsedConfigSection, outWarnings) {
40742
+ const lang2 = toLang2(parsedConfigSection.metadata_language.toLowerCase());
40743
+ if (lang2?.length !== 2) {
40744
+ outWarnings.push(`In the [global] section: metadata_language = "${parsedConfigSection.metadata_language}" is not a recognized ISO 639 language code`);
40745
+ }
40746
+ return parsedConfigSection;
40747
+ }
40748
+ function checkNewRecordDefaultLanguage(parsedConfigSection, outWarnings) {
40749
+ const lang2 = toLang2(parsedConfigSection.new_record_default_language.toLowerCase());
40750
+ if (!(lang2 in LANG_2_TO_3_MAPPER)) {
40751
+ outWarnings.push(`In the [editing] section: new_record_default_language = "${parsedConfigSection.new_record_default_language}" is not a recognized ISO 639 language code`);
40752
+ return {
40753
+ ...parsedConfigSection,
40754
+ new_record_default_language: undefined,
40755
+ };
40756
+ }
40757
+ return {
40758
+ ...parsedConfigSection,
40759
+ new_record_default_language: lang2,
40760
+ };
40761
+ }
40762
+ function checkNewRecordStandard(parsedConfigSection, outWarnings) {
40763
+ const standard = parsedConfigSection.new_record_standard;
40764
+ const normalizedStandard = typeof standard === 'string' ? standard.trim().toLowerCase() : null;
40765
+ if (normalizedStandard === 'iso19139' ||
40766
+ normalizedStandard === 'iso19115-3') {
40767
+ return {
40768
+ ...parsedConfigSection,
40769
+ new_record_standard: normalizedStandard,
40770
+ };
40771
+ }
40772
+ outWarnings.push(`In the [editing] section: new_record_standard = "${standard}" is not a supported metadata standard`);
40773
+ return {
40774
+ ...parsedConfigSection,
40775
+ new_record_standard: undefined,
40776
+ };
40777
+ }
40778
+
40779
+ /**
40780
+ * This loader extends the default one based on JSON files but also loads custom translations
40781
+ * defined in the app configuration
40782
+ * Implements a fallback on default lang if translated labels are empty
40783
+ */
40784
+ class FileWithOverridesTranslateLoader extends FileTranslateLoader {
40785
+ getTranslation(lang) {
40786
+ const baseLang = lang.substring(0, 2); // removing the right part of e.g. en_EN
40787
+ return super.getTranslation(baseLang).pipe(map$1((translations) => ({
40788
+ ...translations,
40789
+ ...getCustomTranslations(baseLang),
40790
+ })));
40791
+ }
40792
+ }
40793
+
40794
+ const MISSING_CONFIG_ERROR = `Application configuration was not initialized correctly.
40795
+ This error might show up in case of an invalid/malformed configuration file.
40796
+
40797
+ Note: make sure that you have called \`loadAppConfig\` from '../../../../../libs/util/app-config/src' before starting the Angular application.`;
40798
+ let globalConfig = null;
40799
+ function getGlobalConfig() {
40800
+ if (globalConfig === null)
40801
+ throw new Error(MISSING_CONFIG_ERROR);
40802
+ return globalConfig;
40803
+ }
40804
+ let themeConfig = null;
40805
+ function getThemeConfig() {
40806
+ if (themeConfig === null)
40807
+ throw new Error(MISSING_CONFIG_ERROR);
40808
+ return themeConfig;
40809
+ }
40810
+ let mapConfig = null;
40811
+ function getOptionalMapConfig() {
40812
+ return mapConfig;
40813
+ }
40814
+ let searchConfig = null;
40815
+ function getOptionalSearchConfig() {
40816
+ return searchConfig;
40817
+ }
40818
+ let editorConfig = null;
40819
+ function getOptionalEditorConfig() {
40820
+ return editorConfig;
40821
+ }
40822
+ let metadataQualityConfig = null;
40823
+ function getMetadataQualityConfig() {
40824
+ return (metadataQualityConfig ||
40825
+ {
40826
+ ENABLED: false,
40827
+ });
40828
+ }
40829
+ let customTranslations = null;
40830
+ function getCustomTranslations(langCode) {
40831
+ if (customTranslations === null)
40832
+ throw new Error(MISSING_CONFIG_ERROR);
40833
+ return langCode in customTranslations ? customTranslations[langCode] : {};
40834
+ }
40835
+ let appConfigLoaded = false;
40836
+ function loadAppConfig(configUrl = 'assets/configuration/default.toml') {
40837
+ console.log(`[geonetwork-ui] Loading application configuration from ${configUrl}`);
40838
+ return fetch(configUrl)
40839
+ .then((resp) => {
40840
+ if (!resp.ok)
40841
+ throw new Error('Configuration file could not be loaded');
40842
+ return resp.text();
40843
+ })
40844
+ .then((conf) => {
40845
+ let parsed;
40846
+ try {
40847
+ parsed = TOML.parse(conf, { joiner: '\n', bigint: false });
40848
+ }
40849
+ catch (e) {
40850
+ throw new Error(`An error occurred when parsing the configuration file: ${e.message}`);
40851
+ }
40852
+ const errors = [];
40853
+ const warnings = [];
40854
+ let parsedGlobalSection = parseConfigSection(parsed, 'global', ['geonetwork4_api_url'], [
40855
+ 'datahub_url',
40856
+ 'edit_url_template',
40857
+ 'proxy_path',
40858
+ 'metadata_language',
40859
+ 'login_url',
40860
+ 'logout_url',
40861
+ 'settings_url',
40862
+ 'web_component_embedder_url',
40863
+ 'languages',
40864
+ 'contact_email',
40865
+ 'reuse_form_url',
40866
+ ], warnings, errors);
40867
+ if (parsedGlobalSection?.metadata_language) {
40868
+ parsedGlobalSection = checkMetadataLanguage(parsedGlobalSection, warnings);
40869
+ }
40870
+ globalConfig =
40871
+ parsedGlobalSection === null
40872
+ ? null
40873
+ : {
40874
+ GN4_API_URL: parsedGlobalSection.geonetwork4_api_url,
40875
+ DATAHUB_URL: parsedGlobalSection.datahub_url,
40876
+ EDIT_URL_TEMPLATE: parsedGlobalSection.edit_url_template,
40877
+ PROXY_PATH: parsedGlobalSection.proxy_path,
40878
+ METADATA_LANGUAGE: parsedGlobalSection.metadata_language
40879
+ ? parsedGlobalSection.metadata_language.toLowerCase()
40880
+ : undefined,
40881
+ LOGIN_URL: parsedGlobalSection.login_url,
40882
+ LOGOUT_URL: parsedGlobalSection.logout_url,
40883
+ SETTINGS_URL: parsedGlobalSection.settings_url,
40884
+ WEB_COMPONENT_EMBEDDER_URL: parsedGlobalSection.web_component_embedder_url,
40885
+ LANGUAGES: parsedGlobalSection.languages,
40886
+ CONTACT_EMAIL: parsedGlobalSection.contact_email,
40887
+ REUSE_FORM_URL: parsedGlobalSection.reuse_form_url,
40888
+ };
40889
+ const parsedLayersSections = parseMultiConfigSection(parsed, 'map_layer', ['type'], ['name', 'url', 'data', 'styleUrl', 'accessToken'], warnings, errors);
40890
+ const parsedMapSection = parseConfigSection(parsed, 'map', [], [
40891
+ 'max_zoom',
40892
+ 'do_not_tile_wms',
40893
+ 'max_extent',
40894
+ 'max_feature_count',
40895
+ 'baselayer',
40896
+ 'do_not_use_default_basemap',
40897
+ 'external_viewer_url_template',
40898
+ 'external_viewer_open_new_tab',
40899
+ ], warnings, errors);
40900
+ mapConfig =
40901
+ parsedMapSection === null || parsedLayersSections === null
40902
+ ? null
40903
+ : {
40904
+ MAX_ZOOM: parsedMapSection.max_zoom,
40905
+ DO_NOT_TILE_WMS: parsedMapSection.do_not_tile_wms,
40906
+ MAX_EXTENT: parsedMapSection.max_extent,
40907
+ MAX_FEATURE_COUNT: parsedMapSection.max_feature_count,
40908
+ EXTERNAL_VIEWER_URL_TEMPLATE: parsedMapSection.external_viewer_url_template,
40909
+ EXTERNAL_VIEWER_OPEN_NEW_TAB: parsedMapSection.external_viewer_open_new_tab,
40910
+ DO_NOT_USE_DEFAULT_BASEMAP: !!parsedMapSection.do_not_use_default_basemap,
40911
+ MAP_LAYERS: parsedLayersSections.map((map_layer) => ({
40912
+ TYPE: map_layer.type,
40913
+ URL: map_layer.url,
40914
+ NAME: map_layer.name,
40915
+ DATA: map_layer.data,
40916
+ STYLE_URL: map_layer.styleUrl,
40917
+ ACCESS_TOKEN: map_layer.accessToken,
40918
+ })),
40919
+ };
40920
+ const parsedThemeSection = parseConfigSection(parsed, 'theme', ['primary_color', 'secondary_color', 'main_color', 'background_color'], [
40921
+ 'header_foreground_color',
40922
+ 'main_font',
40923
+ 'title_font',
40924
+ 'fonts_stylesheet_url',
40925
+ 'thumbnail_placeholder',
40926
+ 'header_background',
40927
+ 'favicon',
40928
+ ], warnings, errors);
40929
+ themeConfig =
40930
+ parsedThemeSection === null
40931
+ ? null
40932
+ : {
40933
+ PRIMARY_COLOR: parsedThemeSection.primary_color,
40934
+ SECONDARY_COLOR: parsedThemeSection.secondary_color,
40935
+ MAIN_COLOR: parsedThemeSection.main_color,
40936
+ BACKGROUND_COLOR: parsedThemeSection.background_color,
40937
+ HEADER_FOREGROUND_COLOR: parsedThemeSection.header_foreground_color,
40938
+ THUMBNAIL_PLACEHOLDER: parsedThemeSection.thumbnail_placeholder,
40939
+ HEADER_BACKGROUND: parsedThemeSection.header_background,
40940
+ TITLE_FONT: parsedThemeSection.title_font,
40941
+ MAIN_FONT: parsedThemeSection.main_font,
40942
+ FONTS_STYLESHEET_URL: parsedThemeSection.fonts_stylesheet_url,
40943
+ FAVICON: parsedThemeSection.favicon,
40944
+ };
40945
+ const parsedSearchSection = parseConfigSection(parsed, 'search', [], [
40946
+ 'record_kind_quick_filter',
40947
+ 'filter_geometry_data',
40948
+ 'filter_geometry_url',
40949
+ 'do_not_use_default_search_preset',
40950
+ 'search_preset',
40951
+ 'advanced_filters',
40952
+ 'limit',
40953
+ 'spatial_extent_max_file_size',
40954
+ 'geocoding_provider',
40955
+ 'geocoding_provider_options',
40956
+ 'geocoding_provider_labels',
40957
+ ], warnings, errors);
40958
+ const parsedSearchParams = parseMultiConfigSection(parsed, 'search_preset', ['name'], ['sort', 'filters'], warnings, errors);
40959
+ const parsedCustomFilters = parseMultiConfigSection(parsed, 'custom_filter', ['name', 'base_filter'], ['exclude_values', 'include_values', 'label_key'], warnings, errors);
40960
+ const parsedGeocodingProviderLabels = parsedSearchSection?.geocoding_provider_labels;
40961
+ searchConfig =
40962
+ parsedSearchSection === null
40963
+ ? null
40964
+ : {
40965
+ RECORD_KIND_QUICK_FILTER: parsedSearchSection.record_kind_quick_filter,
40966
+ FILTER_GEOMETRY_DATA: parsedSearchSection.filter_geometry_data,
40967
+ FILTER_GEOMETRY_URL: parsedSearchSection.filter_geometry_url,
40968
+ DO_NOT_USE_DEFAULT_SEARCH_PRESET: !!parsedSearchSection.do_not_use_default_search_preset,
40969
+ SEARCH_PRESET: parsedSearchParams.map((param) => ({
40970
+ sort: param.sort,
40971
+ name: param.name,
40972
+ filters: param.filters,
40973
+ })),
40974
+ ADVANCED_FILTERS: parsedSearchSection.advanced_filters,
40975
+ CUSTOM_FILTERS: (parsedCustomFilters ?? []).map((customFilter) => ({
40976
+ name: customFilter.name,
40977
+ baseFilter: customFilter.base_filter,
40978
+ excludeValues: customFilter.exclude_values,
40979
+ includeValues: customFilter.include_values,
40980
+ labelKey: customFilter.label_key,
40981
+ })),
40982
+ LIMIT: parsedSearchSection.limit,
40983
+ SPATIAL_EXTENT_MAX_FILE_SIZE: parsedSearchSection.spatial_extent_max_file_size,
40984
+ GEOCODING_PROVIDER: parsedSearchSection.geocoding_provider,
40985
+ GEOCODING_PROVIDER_OPTIONS: parsedSearchSection.geocoding_provider_options,
40986
+ GEOCODING_PROVIDER_LABELS: parsedGeocodingProviderLabels
40987
+ ? {
40988
+ MAIN: parsedGeocodingProviderLabels.main,
40989
+ SECONDARY: parsedGeocodingProviderLabels.secondary,
40990
+ TERTIARY: parsedGeocodingProviderLabels.tertiary,
40991
+ }
40992
+ : undefined,
40993
+ };
40994
+ const parsedMetadataQualitySection = parseConfigSection(parsed, 'metadata-quality', [], ['enabled'], warnings, errors);
40995
+ metadataQualityConfig =
40996
+ parsedMetadataQualitySection === null
40997
+ ? null
40998
+ : {
40999
+ ENABLED: parsedMetadataQualitySection.enabled,
41000
+ SORTABLE: parsedMetadataQualitySection.sortable,
41001
+ };
41002
+ let parsedEditingSection = parseConfigSection(parsed, 'editing', [], ['new_record_default_language', 'new_record_standard'], warnings, errors);
41003
+ if (parsedEditingSection !== null &&
41004
+ parsedEditingSection.new_record_default_language !== undefined) {
41005
+ parsedEditingSection = checkNewRecordDefaultLanguage(parsedEditingSection, warnings);
41006
+ }
41007
+ if (parsedEditingSection !== null &&
41008
+ parsedEditingSection.new_record_standard !== undefined) {
41009
+ parsedEditingSection = checkNewRecordStandard(parsedEditingSection, warnings);
41010
+ }
41011
+ editorConfig =
41012
+ parsedEditingSection === null
41013
+ ? null
41014
+ : {
41015
+ NEW_RECORD_DEFAULT_LANGUAGE: parsedEditingSection.new_record_default_language,
41016
+ NEW_RECORD_STANDARD: parsedEditingSection.new_record_standard,
41017
+ };
41018
+ customTranslations = parseTranslationsConfigSection(parsed, 'translations');
41019
+ if (errors.length) {
41020
+ throw new Error(`One or more mandatory settings were missing from the configuration file.
41021
+ ${errors.join('\n')}`);
41022
+ }
41023
+ else if (warnings.length) {
41024
+ console.warn(`One or more unexpected settings were encountered in the configuration file.
41025
+ ${warnings.join('\n')}`);
41026
+ }
41027
+ appConfigLoaded = true;
41028
+ });
41029
+ }
41030
+ function isConfigLoaded() {
41031
+ return appConfigLoaded;
41032
+ }
41033
+ function _reset() {
41034
+ globalConfig = null;
41035
+ themeConfig = null;
41036
+ editorConfig = null;
41037
+ customTranslations = null;
41038
+ }
41039
+ const TRANSLATE_WITH_OVERRIDES_CONFIG = {
41040
+ compiler: {
41041
+ provide: TranslateCompiler,
41042
+ useClass: TranslateMessageFormatCompiler,
41043
+ },
41044
+ loader: [
41045
+ {
41046
+ provide: TRANSLATE_HTTP_LOADER_CONFIG,
41047
+ useValue: {
41048
+ prefix: './assets/i18n/',
41049
+ suffix: '.json',
41050
+ },
41051
+ },
41052
+ {
41053
+ provide: TranslateLoader,
41054
+ useClass: FileWithOverridesTranslateLoader,
41055
+ deps: [HttpClient, TRANSLATE_HTTP_LOADER_CONFIG],
41056
+ },
41057
+ ],
41058
+ };
41059
+
41060
+ const okAppConfigFixture = () => `
41061
+ [global]
41062
+ geonetwork4_api_url = "/geonetwork/srv/api"
41063
+ proxy_path = "/proxy/?url="
41064
+ metadata_language = "fre"
41065
+ login_url = "/cas/login?service="
41066
+ logout_url = "/geonetwork/signout"
41067
+ settings_url = "/geonetwork/settings"
41068
+ web_component_embedder_url = "/datahub/wc-embedder.html"
41069
+
41070
+ [map]
41071
+ max_zoom = 10
41072
+ max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
41073
+ do_not_use_default_basemap = false
41074
+ external_viewer_url_template = 'https://example.com/myviewer?'
41075
+ external_viewer_open_new_tab = true
41076
+ [[map_layer]]
41077
+ type = "wms"
41078
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
41079
+ name = "masque_hdf_ign_carto_latin1"
41080
+ [[map_layer]]
41081
+ type = "wfs"
41082
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
41083
+ name = "masque_hdf_ign_carto_latin1"
41084
+
41085
+ [theme]
41086
+ primary_color = "#093564"
41087
+ secondary_color = "#c2e9dc"
41088
+ main_color = "#212029" # All-purpose text color
41089
+ background_color = "#fdfbff"
41090
+ thumbnail_placeholder = 'assets/img/placeholder.svg'
41091
+ header_background = 'teal'
41092
+ header_foreground_color = "#872e2e"
41093
+ main_font = 'sans-serif'
41094
+ title_font = 'serif'
41095
+ fonts_stylesheet_url = "https://fonts.googleapis.com/css2?family=Open+Sans"
41096
+
41097
+ [search]
41098
+ record_kind_quick_filter = false
41099
+ filter_geometry_url = 'https://my.domain.org/geom.json'
41100
+ do_not_use_default_search_preset = false
41101
+ geocoding_provider = "geoplateforme"
41102
+ geocoding_provider_options.index = "poi"
41103
+ geocoding_provider_options.category = "administratif"
41104
+ geocoding_provider_options.limit = 5
41105
+ geocoding_provider_labels.main = '/properties/name/0'
41106
+ geocoding_provider_labels.secondary = '/properties/citycode/0'
41107
+ geocoding_provider_labels.tertiary = '/properties/category/1'
41108
+ advanced_filters = ['publicationYear', 'documentStandard', 'inspireKeyword', 'topic', 'license', 'myOrg:firstCustomFilter', 'myOrg:secondCustomFilter']
41109
+
41110
+ [[custom_filter]]
41111
+ name = 'myOrg:firstCustomFilter'
41112
+ base_filter = 'keyword'
41113
+ exclude_values = ['my keyword 1', 'my keyword 2']
41114
+ label_key = 'myOrg.firstCustomFilter'
41115
+
41116
+ [[custom_filter]]
41117
+ name = 'myOrg:secondCustomFilter'
41118
+ base_filter = 'keyword'
41119
+ include_values = ['my keyword 3', 'my keyword 4']
41120
+ label_key = 'myOrg.secondCustomFilter'
41121
+
41122
+ [[search_preset]]
41123
+ sort = "-createDate"
41124
+ name = 'filterByOrgs'
41125
+ filters.q = 'Carto'
41126
+ filters.organisation = ['Org1', 'Org2']
41127
+ filters.format = ['ESRI Shapefile']
41128
+ filters.topic = ['boundaries']
41129
+ filters.publicationYear = ['2023', '2022']
41130
+ filters.spatial = ['yes']
41131
+
41132
+ [translations.en]
41133
+ "my.first.key" = 'First label.'
41134
+ "my.second.key" = """
41135
+ Second label,
41136
+ on two lines."""
41137
+
41138
+ [translations.de]
41139
+ my.first.key = 'Erste Etikett.'
41140
+
41141
+ [translations.fr]
41142
+ my.sample.text = "Un bon exemple de texte."
41143
+ "my.quoted.text" = 'du texte entre guillements.'
41144
+ `;
41145
+ const appConfigWithTranslationFixture = () => okAppConfigFixture();
41146
+ const minimalAppConfigFixture = () => `
41147
+ [global]
41148
+ geonetwork4_api_url = "/geonetwork/srv/api"
41149
+ proxy_path = "/proxy/?url="
41150
+
41151
+ [theme]
41152
+ primary_color = "#093564"
41153
+ secondary_color = "#c2e9dc"
41154
+ main_color = "#212029" # All-purpose text color
41155
+ background_color = "#fdfbff"
41156
+ `;
41157
+ const customFilterMissingMandatoryConfigFixture = () => `
41158
+ [global]
41159
+ geonetwork4_api_url = "/geonetwork/srv/api"
41160
+
41161
+ [theme]
41162
+ primary_color = "#093564"
41163
+ secondary_color = "#c2e9dc"
41164
+ main_color = "#212029" # All-purpose text color
41165
+ background_color = "#fdfbff"
41166
+
41167
+ [search]
41168
+ advanced_filters = ['myOrg:firstCustomFilter']
41169
+
41170
+ [[custom_filter]]
41171
+ name = 'myOrg:firstCustomFilter'
41172
+ `;
41173
+ const mapConfigFixture = () => ({
41174
+ MAX_ZOOM: 10,
41175
+ MAX_EXTENT: [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855],
41176
+ DO_NOT_USE_DEFAULT_BASEMAP: false,
41177
+ DO_NOT_TILE_WMS: false,
41178
+ 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}"}]}]',
41179
+ EXTERNAL_VIEWER_OPEN_NEW_TAB: true,
41180
+ MAP_LAYERS: [
41181
+ {
41182
+ TYPE: 'xyz',
41183
+ URL: 'https://some-basemap-server',
41184
+ },
41185
+ {
41186
+ TYPE: 'wms',
41187
+ URL: 'https://some-wms-server',
41188
+ NAME: 'some_layername',
41189
+ },
41190
+ {
41191
+ TYPE: 'wfs',
41192
+ URL: 'https://some-wfs-server',
41193
+ NAME: 'some_layername',
41194
+ },
41195
+ ],
41196
+ });
41197
+ const malformedConfigFixture = () => `
41198
+ {
41199
+ "I thought": "we were still doing json"
41200
+ }
41201
+ `;
41202
+ const missingMandatoryConfigFixture = () => `
41203
+ [theme]
41204
+ primary_color = "#093564"
41205
+ secondary_color = "#c2e9dc"
41206
+ background_color = "#fdfbff"
41207
+ main_font = 'sans-serif'
41208
+ `;
41209
+ const wrongLanguageCodeConfigFixture = () => `
41210
+ [global]
41211
+ geonetwork4_api_url = "/geonetwork/srv/api"
41212
+ proxy_path = "/proxy/?url="
41213
+ metadata_language = "abc"
41214
+
41215
+ [map]
41216
+
41217
+ [theme]
41218
+ primary_color = "#093564"
41219
+ secondary_color = "#c2e9dc"
41220
+ main_color = "#212029" # All-purpose text color
41221
+ background_color = "#fdfbff"
41222
+ `;
41223
+ const unrecognizedKeysConfigFixture = () => `
41224
+ [global]
41225
+ geonetwork4_api_url = "/geonetwork/srv/api"
41226
+ proxy_path = "/proxy/?url="
41227
+ metadata_language = "fre"
41228
+ another_path = '/whatever'
41229
+
41230
+ [map]
41231
+ max_zoom = 10
41232
+ max_extent = [-418263.418776, 5251529.591305, 961272.067714, 6706890.609855]
41233
+ do_not_use_default_basemap = false
41234
+ external_viewer_url_template = 'https://example.com/myviewer?'
41235
+ external_viewer_open_new_tab = true
41236
+ another_zoom = 15
41237
+ [[map_layer]]
41238
+ type = "wms"
41239
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
41240
+ name = "masque_hdf_ign_carto_latin1"
41241
+ [[map_layer]]
41242
+ type = "wfs"
41243
+ url = "https://www.geo2france.fr/geoserver/cr_hdf/ows"
41244
+ name = "masque_hdf_ign_carto_latin1"
41245
+ another_layer = "wrong layer definition"
41246
+
41247
+ [theme]
41248
+ primary_color = "#093564"
41249
+ secondary_color = "#c2e9dc"
41250
+ main_color = "#212029" # All-purpose text color
41251
+ background_color = "#fdfbff"
41252
+ thumbnail_placeholder = 'assets/img/placeholder.svg'
41253
+ header_background = 'teal'
41254
+ header_foreground_color = "#872e2e"
41255
+ main_font = 'sans-serif'
41256
+ title_font = 'serif'
41257
+ another_color = 'red'
41258
+ `;
41259
+
41260
+ function getMapContextLayerFromConfig(config) {
41261
+ switch (config.TYPE) {
41262
+ case 'wms':
41263
+ return {
41264
+ type: 'wms',
41265
+ url: config.URL,
41266
+ name: config.NAME,
41267
+ };
41268
+ case 'wfs':
41269
+ return {
41270
+ type: 'wfs',
41271
+ url: config.URL,
41272
+ featureType: config.NAME,
41273
+ };
41274
+ case 'xyz':
41275
+ return {
41276
+ type: config.TYPE,
41277
+ url: config.URL,
41278
+ };
41279
+ case 'geojson':
41280
+ return {
41281
+ type: config.TYPE,
41282
+ ...(config.DATA ? { data: config.DATA } : { url: config.URL }),
41283
+ };
41284
+ case 'maplibre-style':
41285
+ return {
41286
+ type: config.TYPE,
41287
+ styleUrl: config.STYLE_URL,
41288
+ accessToken: config.ACCESS_TOKEN,
41289
+ };
41290
+ }
41291
+ }
41292
+
40919
41293
  const CHART_TYPE_VALUES = [
40920
41294
  'bar',
40921
41295
  'bar-horizontal',
@@ -40931,5 +41305,5 @@ const CHART_TYPE_VALUES = [
40931
41305
  * Generated bundle index. Do not edit.
40932
41306
  */
40933
41307
 
40934
- 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, GEOCODING_PROVIDER, 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, 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 };
41308
+ 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 };
40935
41309
  //# sourceMappingURL=geonetwork-ui.mjs.map